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