| // 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 "http2/decoder/decode_buffer.h" | 
 | #include "http2/hpack/decoder/hpack_block_decoder.h" | 
 | #include "http2/hpack/decoder/hpack_decoder_listener.h" | 
 | #include "http2/hpack/decoder/hpack_decoder_state.h" | 
 | #include "http2/hpack/decoder/hpack_decoder_tables.h" | 
 | #include "http2/hpack/decoder/hpack_decoding_error.h" | 
 | #include "http2/hpack/decoder/hpack_whole_entry_buffer.h" | 
 | #include "common/platform/api/quiche_export.h" | 
 |  | 
 | namespace http2 { | 
 | namespace test { | 
 | class HpackDecoderPeer; | 
 | }  // namespace test | 
 |  | 
 | class QUICHE_EXPORT_PRIVATE HpackDecoder { | 
 |  public: | 
 |   HpackDecoder(HpackDecoderListener* listener, size_t max_string_size); | 
 |   virtual ~HpackDecoder(); | 
 |  | 
 |   HpackDecoder(const HpackDecoder&) = delete; | 
 |   HpackDecoder& operator=(const HpackDecoder&) = delete; | 
 |  | 
 |   // 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); | 
 |  | 
 |   // Returns the most recently applied value of SETTINGS_HEADER_TABLE_SIZE. | 
 |   size_t GetCurrentHeaderTableSizeSetting() const { | 
 |     return decoder_state_.GetCurrentHeaderTableSizeSetting(); | 
 |   } | 
 |  | 
 |   // 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(); | 
 |  | 
 |   // If no error has been detected so far, query |decoder_state_| for errors and | 
 |   // set |error_| if necessary.  Returns true if an error has ever been | 
 |   // detected. | 
 |   bool DetectError(); | 
 |  | 
 |   size_t GetDynamicTableSize() const { | 
 |     return decoder_state_.GetDynamicTableSize(); | 
 |   } | 
 |  | 
 |   // Error code if an error has occurred, HpackDecodingError::kOk otherwise. | 
 |   HpackDecodingError error() const { return error_; } | 
 |  | 
 |   std::string detailed_error() const { return detailed_error_; } | 
 |  | 
 |  private: | 
 |   friend class test::HpackDecoderPeer; | 
 |  | 
 |   // Reports an error to the listener IF this is the first error detected. | 
 |   void ReportError(HpackDecodingError error, std::string detailed_error); | 
 |  | 
 |   // 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_; | 
 |  | 
 |   // Error code if an error has occurred, HpackDecodingError::kOk otherwise. | 
 |   HpackDecodingError error_; | 
 |   std::string detailed_error_; | 
 | }; | 
 |  | 
 | }  // namespace http2 | 
 |  | 
 | #endif  // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_H_ |