blob: f890b3ee9cb99d524c3092aaa7b5e78ac30444b6 [file] [log] [blame]
// 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 <cstddef>
#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<const char> 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<spdy::AcceptChOriginValuePair>& 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<spdy::AcceptChOriginValuePair>& 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<spdy::AcceptChOriginValuePair> 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_