xref: /aosp_15_r20/external/cronet/net/spdy/alps_decoder.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_SPDY_ALPS_DECODER_H_
6 #define NET_SPDY_ALPS_DECODER_H_
7 
8 #include <cstddef>
9 
10 #include "base/containers/span.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "net/base/net_export.h"
13 #include "net/third_party/quiche/src/quiche/spdy/core/http2_frame_decoder_adapter.h"
14 #include "net/third_party/quiche/src/quiche/spdy/core/spdy_no_op_visitor.h"
15 #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h"
16 
17 namespace net {
18 
19 // Class to parse HTTP/2 frames in the extension_data field
20 // of the ALPS TLS extension.
21 class NET_EXPORT_PRIVATE AlpsDecoder {
22  public:
23   // These values are persisted to logs. Entries should not be renumbered, and
24   // numeric values should never be reused.
25   enum class Error {
26     // No error has occurred.
27     kNoError = 0,
28     // HTTP/2 framing error detected by Http2DecoderAdapter.
29     kFramingError = 1,
30     // Forbidden HTTP/2 frame received.
31     kForbiddenFrame = 2,
32     // Input does not end on HTTP/2 frame boundary.
33     kNotOnFrameBoundary = 3,
34     // SETTINGS frame with ACK received.
35     kSettingsWithAck = 4,
36     // ACCEPT_CH received on invalid stream.
37     kAcceptChInvalidStream = 5,
38     // ACCEPT_CH received with flags.
39     kAcceptChWithFlags = 6,
40     // Malformed ACCEPT_CH payload.
41     kAcceptChMalformed = 7,
42     kMaxValue = kAcceptChMalformed
43   };
44 
45   AlpsDecoder();
46   ~AlpsDecoder();
47 
48   // Decode a stream of HTTP/2 frames received via the ALPS TLS extension.
49   // The HTTP/2 connection preface MUST NOT be present in the input.
50   // Frames other than SETTINGS and ACCEPT_CH are ignored other than for the
51   // purposes of enforcing HTTP/2 framing rules.
52   // May only be called once, with the entire ALPS extension_data.
53   // Returns an error code, or Error::kNoError if no error has occurred.
54   // The requirement that the first frame MUST be SETTINGS is not enforced,
55   // because that only applies to HTTP/2 connections, not ALPS data.
56   [[nodiscard]] Error Decode(base::span<const char> data);
57 
58   // The number of SETTINGS frames received.
59   int settings_frame_count() const;
60 
61   // The HTTP/2 setting parameters parsed from |data|.
GetSettings()62   const spdy::SettingsMap& GetSettings() const {
63     return settings_parser_.GetSettings();
64   }
65   // Origins and corresponding Accept-CH values parsed from |data|.  See
66   // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02
GetAcceptCh()67   const std::vector<spdy::AcceptChOriginValuePair>& GetAcceptCh() const {
68     return accept_ch_parser_.GetAcceptCh();
69   }
70 
71  private:
72   class SettingsParser : public spdy::SpdyNoOpVisitor {
73    public:
74     SettingsParser();
75     ~SettingsParser() override;
76 
forbidden_frame_received()77     bool forbidden_frame_received() const { return forbidden_frame_received_; }
settings_ack_received()78     bool settings_ack_received() const { return settings_ack_received_; }
settings_frame_count()79     int settings_frame_count() const { return settings_frame_count_; }
80     // Number of SETTINGS frames received.
GetSettings()81     const spdy::SettingsMap& GetSettings() const { return settings_; }
82 
83     // SpdyFramerVisitorInterface overrides.
84     void OnCommonHeader(spdy::SpdyStreamId stream_id,
85                         size_t length,
86                         uint8_t type,
87                         uint8_t flags) override;
88     void OnSettings() override;
89     void OnSetting(spdy::SpdySettingsId id, uint32_t value) override;
90     void OnSettingsAck() override;
91 
92    private:
93     // True if a forbidden HTTP/2 frame has been received.
94     bool forbidden_frame_received_ = false;
95     // True if a SETTINGS frame with ACK flag has been received.
96     bool settings_ack_received_ = false;
97     // Number of SETTINGS frames received.
98     int settings_frame_count_ = 0;
99     // Accumulated setting parameters.
100     spdy::SettingsMap settings_;
101   };
102 
103   // Class to parse ACCEPT_CH frames.
104   class AcceptChParser : public spdy::ExtensionVisitorInterface {
105    public:
106     AcceptChParser();
107     ~AcceptChParser() override;
108 
GetAcceptCh()109     const std::vector<spdy::AcceptChOriginValuePair>& GetAcceptCh() const {
110       return accept_ch_;
111     }
112 
113     // Returns an error code, or Error::kNoError if no error has occurred.
error()114     Error error() const { return error_; }
115 
116     // Returns an error code if it was bypassed, or Error::kNoError if no error was bypassed.
error_bypass()117     Error error_bypass() const { return error_bypass_; }
118 
119     // ExtensionVisitorInterface implementation.
120 
121     // Settings are parsed in a SpdyFramerVisitorInterface implementation,
122     // because ExtensionVisitorInterface does not provide information about
123     // receiving an empty SETTINGS frame.
OnSetting(spdy::SpdySettingsId id,uint32_t value)124     void OnSetting(spdy::SpdySettingsId id, uint32_t value) override {}
125 
126     bool OnFrameHeader(spdy::SpdyStreamId stream_id,
127                        size_t length,
128                        uint8_t type,
129                        uint8_t flags) override;
130     void OnFramePayload(const char* data, size_t len) override;
131 
132    private:
133     // Accumulated ACCEPT_CH values.
134     std::vector<spdy::AcceptChOriginValuePair> accept_ch_;
135 
136     Error error_ = Error::kNoError;
137     Error error_bypass_ = Error::kNoError;
138   };
139 
140   SettingsParser settings_parser_;
141   AcceptChParser accept_ch_parser_;
142   http2::Http2DecoderAdapter decoder_adapter_;
143 };
144 
145 }  // namespace net
146 
147 #endif  // NET_SPDY_ALPS_DECODER_H_
148