blob: 3040c181471ef78651fb7466ef382a3a1e4bf224 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// HpackDecoderState maintains the HPACK decompressor state; i.e. updates the
// HPACK dynamic table according to RFC 7541 as the entries in an HPACK block
// are decoded, and reads from the static and dynamic tables in order to build
// complete header entries. Calls an HpackDecoderListener with the completely
// decoded headers (i.e. after resolving table indices into names or values),
// thus translating the decoded HPACK entries into HTTP/2 headers.
#include <stddef.h>
#include <cstdint>
#include "absl/strings/string_view.h"
#include "http2/hpack/decoder/hpack_decoder_listener.h"
#include "http2/hpack/decoder/hpack_decoder_string_buffer.h"
#include "http2/hpack/decoder/hpack_decoder_tables.h"
#include "http2/hpack/decoder/hpack_decoding_error.h"
#include "http2/hpack/decoder/hpack_whole_entry_listener.h"
#include "http2/hpack/http2_hpack_constants.h"
#include "common/platform/api/quiche_export.h"
namespace http2 {
namespace test {
class HpackDecoderStatePeer;
} // namespace test
class QUICHE_EXPORT_PRIVATE HpackDecoderState : public HpackWholeEntryListener {
explicit HpackDecoderState(HpackDecoderListener* listener);
~HpackDecoderState() override;
HpackDecoderState(const HpackDecoderState&) = delete;
HpackDecoderState& operator=(const HpackDecoderState&) = delete;
// Set the listener to be notified when a whole entry has been decoded,
// including resolving name or name and value references.
// The listener may be changed at any time.
HpackDecoderListener* listener() const { return listener_; }
// ApplyHeaderTableSizeSetting notifies this object that this endpoint has
// received a SETTINGS ACK frame acknowledging an earlier SETTINGS frame from
// this endpoint specifying a new value for SETTINGS_HEADER_TABLE_SIZE (the
// maximum size of the dynamic table that this endpoint will use to decode
// HPACK blocks).
// Because a SETTINGS frame can contain SETTINGS_HEADER_TABLE_SIZE values,
// the caller must keep track of those multiple changes, and make
// corresponding calls to this method. In particular, a call must be made
// with the lowest value acknowledged by the peer, and a call must be made
// with the final value acknowledged, in that order; additional calls may
// be made if additional values were sent. These calls must be made between
// decoding the SETTINGS ACK, and before the next HPACK block is decoded.
void ApplyHeaderTableSizeSetting(uint32_t max_header_table_size);
// Returns the most recently applied value of SETTINGS_HEADER_TABLE_SIZE.
size_t GetCurrentHeaderTableSizeSetting() const {
return final_header_table_size_;
// OnHeaderBlockStart notifies this object that we're starting to decode the
// HPACK payload of a HEADERS or PUSH_PROMISE frame.
void OnHeaderBlockStart();
// Implement the HpackWholeEntryListener methods, each of which notifies this
// object when an entire entry has been decoded.
void OnIndexedHeader(size_t index) override;
void OnNameIndexAndLiteralValue(
HpackEntryType entry_type,
size_t name_index,
HpackDecoderStringBuffer* value_buffer) override;
void OnLiteralNameAndValue(HpackEntryType entry_type,
HpackDecoderStringBuffer* name_buffer,
HpackDecoderStringBuffer* value_buffer) override;
void OnDynamicTableSizeUpdate(size_t size) override;
void OnHpackDecodeError(HpackDecodingError error,
std::string detailed_error) override;
// OnHeaderBlockEnd notifies this object that an entire HPACK block has been
// decoded, which might have extended into CONTINUATION blocks.
void OnHeaderBlockEnd();
// Returns error code after an error has been detected and reported.
// No further callbacks will be made to the listener.
HpackDecodingError error() const { return error_; }
size_t GetDynamicTableSize() const {
return decoder_tables_.current_header_table_size();
const HpackDecoderTables& decoder_tables_for_test() const {
return decoder_tables_;
std::string detailed_error() const { return detailed_error_; }
friend class test::HpackDecoderStatePeer;
// Reports an error to the listener IF this is the first error detected.
void ReportError(HpackDecodingError error, std::string detailed_error);
// The static and dynamic HPACK tables.
HpackDecoderTables decoder_tables_;
// The listener to be notified of headers, the start and end of header
// lists, and of errors.
HpackDecoderListener* listener_;
// The most recent HEADER_TABLE_SIZE setting acknowledged by the peer.
uint32_t final_header_table_size_;
// The lowest HEADER_TABLE_SIZE setting acknowledged by the peer; valid until
// the next HPACK block is decoded.
// TODO(jamessynge): Test raising the HEADER_TABLE_SIZE.
uint32_t lowest_header_table_size_;
// Must the next (first) HPACK entry be a dynamic table size update?
bool require_dynamic_table_size_update_;
// May the next (first or second) HPACK entry be a dynamic table size update?
bool allow_dynamic_table_size_update_;
// Have we already seen a dynamic table size update in this HPACK block?
bool saw_dynamic_table_size_update_;
// Has an error already been detected and reported to the listener?
HpackDecodingError error_;
std::string detailed_error_;
} // namespace http2