blob: e173bc6af1987665da3ceb2281e823e6365e58c1 [file] [log] [blame]
// Copyright 2017 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.
#ifndef QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_H_
#define QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_H_
// Decodes HPACK blocks, calls an HpackDecoderListener with the decoded header
// entries. Also notifies the listener of errors and of the boundaries of the
// HPACK blocks.
// TODO(jamessynge): Add feature allowing an HpackEntryDecoderListener
// sub-class (and possibly others) to be passed in for counting events,
// so that deciding whether to count is not done by having lots of if
// statements, but instead by inserting an indirection only when needed.
// TODO(jamessynge): Consider whether to return false from methods below
// when an error has been previously detected. It protects calling code
// from its failure to pay attention to previous errors, but should we
// spend time to do that?
#include <stddef.h>
#include <cstdint>
#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_block_decoder.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_listener.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_tables.h"
#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_whole_entry_buffer.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_export.h"
#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
namespace http2 {
namespace test {
class HpackDecoderPeer;
} // namespace test
class HTTP2_EXPORT_PRIVATE HpackDecoder {
public:
HpackDecoder(HpackDecoderListener* listener, size_t max_string_size);
virtual ~HpackDecoder();
HpackDecoder(const HpackDecoder&) = delete;
HpackDecoder& operator=(const HpackDecoder&) = delete;
// Set listener to be notified of insertions into the HPACK dynamic table,
// and uses of those entries.
void set_tables_debug_listener(
HpackDecoderTablesDebugListener* debug_listener);
// max_string_size specifies the maximum size of an on-the-wire string (name
// or value, plain or Huffman encoded) that will be accepted. See sections
// 5.1 and 5.2 of RFC 7541. This is a defense against OOM attacks; HTTP/2
// allows a decoder to enforce any limit of the size of the header lists
// that it is willing to decode, including less than the MAX_HEADER_LIST_SIZE
// setting, a setting that is initially unlimited. For example, we might
// choose to send a MAX_HEADER_LIST_SIZE of 64KB, and to use that same value
// as the upper bound for individual strings.
void set_max_string_size_bytes(size_t max_string_size_bytes);
// 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);
// Prepares the decoder for decoding a new HPACK block, and announces this to
// its listener. Returns true if OK to continue with decoding, false if an
// error has been detected, which for StartDecodingBlock means the error was
// detected while decoding a previous HPACK block.
bool StartDecodingBlock();
// Decodes a fragment (some or all of the remainder) of an HPACK block,
// reporting header entries (name & value pairs) that it completely decodes
// in the process to the listener. Returns true successfully decoded, false if
// an error has been detected, either during decoding of the fragment, or
// prior to this call.
bool DecodeFragment(DecodeBuffer* db);
// Completes the process of decoding an HPACK block: if the HPACK block was
// properly terminated, announces the end of the header list to the listener
// and returns true; else returns false.
bool EndDecodingBlock();
// Was an error detected?
bool error_detected();
// Returns the estimate of dynamically allocated memory in bytes.
size_t EstimateMemoryUsage() const;
private:
friend class test::HpackDecoderPeer;
// Reports an error to the listener IF this is the first error detected.
void ReportError(Http2StringPiece error_message);
// The decompressor state, as defined by HPACK (i.e. the static and dynamic
// tables).
HpackDecoderState decoder_state_;
// Assembles the various parts of a header entry into whole entries.
HpackWholeEntryBuffer entry_buffer_;
// The decoder of HPACK blocks into entry parts, passed to entry_buffer_.
HpackBlockDecoder block_decoder_;
// Has an error been detected?
bool error_detected_;
};
} // namespace http2
#endif // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_H_