| // 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. | 
 |  | 
 | #ifndef QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_STATE_H_ | 
 | #define QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_STATE_H_ | 
 |  | 
 | #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 { | 
 |  public: | 
 |   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_; } | 
 |  | 
 |  private: | 
 |   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 | 
 |  | 
 | #endif  // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_STATE_H_ |