// Copyright 2021 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef NET_SPDY_ALPS_DECODER_H_ #define NET_SPDY_ALPS_DECODER_H_ #include #include "base/containers/span.h" #include "base/strings/string_number_conversions.h" #include "net/base/net_export.h" #include "net/third_party/quiche/src/quiche/spdy/core/http2_frame_decoder_adapter.h" #include "net/third_party/quiche/src/quiche/spdy/core/spdy_no_op_visitor.h" #include "net/third_party/quiche/src/quiche/spdy/core/spdy_protocol.h" namespace net { // Class to parse HTTP/2 frames in the extension_data field // of the ALPS TLS extension. class NET_EXPORT_PRIVATE AlpsDecoder { public: // These values are persisted to logs. Entries should not be renumbered, and // numeric values should never be reused. enum class Error { // No error has occurred. kNoError = 0, // HTTP/2 framing error detected by Http2DecoderAdapter. kFramingError = 1, // Forbidden HTTP/2 frame received. kForbiddenFrame = 2, // Input does not end on HTTP/2 frame boundary. kNotOnFrameBoundary = 3, // SETTINGS frame with ACK received. kSettingsWithAck = 4, // ACCEPT_CH received on invalid stream. kAcceptChInvalidStream = 5, // ACCEPT_CH received with flags. kAcceptChWithFlags = 6, // Malformed ACCEPT_CH payload. kAcceptChMalformed = 7, kMaxValue = kAcceptChMalformed }; AlpsDecoder(); ~AlpsDecoder(); // Decode a stream of HTTP/2 frames received via the ALPS TLS extension. // The HTTP/2 connection preface MUST NOT be present in the input. // Frames other than SETTINGS and ACCEPT_CH are ignored other than for the // purposes of enforcing HTTP/2 framing rules. // May only be called once, with the entire ALPS extension_data. // Returns an error code, or Error::kNoError if no error has occurred. // The requirement that the first frame MUST be SETTINGS is not enforced, // because that only applies to HTTP/2 connections, not ALPS data. [[nodiscard]] Error Decode(base::span data); // The number of SETTINGS frames received. int settings_frame_count() const; // The HTTP/2 setting parameters parsed from |data|. const spdy::SettingsMap& GetSettings() const { return settings_parser_.GetSettings(); } // Origins and corresponding Accept-CH values parsed from |data|. See // https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02 const std::vector& GetAcceptCh() const { return accept_ch_parser_.GetAcceptCh(); } private: class SettingsParser : public spdy::SpdyNoOpVisitor { public: SettingsParser(); ~SettingsParser() override; bool forbidden_frame_received() const { return forbidden_frame_received_; } bool settings_ack_received() const { return settings_ack_received_; } int settings_frame_count() const { return settings_frame_count_; } // Number of SETTINGS frames received. const spdy::SettingsMap& GetSettings() const { return settings_; } // SpdyFramerVisitorInterface overrides. void OnCommonHeader(spdy::SpdyStreamId stream_id, size_t length, uint8_t type, uint8_t flags) override; void OnSettings() override; void OnSetting(spdy::SpdySettingsId id, uint32_t value) override; void OnSettingsAck() override; private: // True if a forbidden HTTP/2 frame has been received. bool forbidden_frame_received_ = false; // True if a SETTINGS frame with ACK flag has been received. bool settings_ack_received_ = false; // Number of SETTINGS frames received. int settings_frame_count_ = 0; // Accumulated setting parameters. spdy::SettingsMap settings_; }; // Class to parse ACCEPT_CH frames. class AcceptChParser : public spdy::ExtensionVisitorInterface { public: AcceptChParser(); ~AcceptChParser() override; const std::vector& GetAcceptCh() const { return accept_ch_; } // Returns an error code, or Error::kNoError if no error has occurred. Error error() const { return error_; } // Returns an error code if it was bypassed, or Error::kNoError if no error was bypassed. Error error_bypass() const { return error_bypass_; } // ExtensionVisitorInterface implementation. // Settings are parsed in a SpdyFramerVisitorInterface implementation, // because ExtensionVisitorInterface does not provide information about // receiving an empty SETTINGS frame. void OnSetting(spdy::SpdySettingsId id, uint32_t value) override {} bool OnFrameHeader(spdy::SpdyStreamId stream_id, size_t length, uint8_t type, uint8_t flags) override; void OnFramePayload(const char* data, size_t len) override; private: // Accumulated ACCEPT_CH values. std::vector accept_ch_; Error error_ = Error::kNoError; Error error_bypass_ = Error::kNoError; }; SettingsParser settings_parser_; AcceptChParser accept_ch_parser_; http2::Http2DecoderAdapter decoder_adapter_; }; } // namespace net #endif // NET_SPDY_ALPS_DECODER_H_