1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // HpackDecoderState maintains the HPACK decompressor state; i.e. updates the 6 // HPACK dynamic table according to RFC 7541 as the entries in an HPACK block 7 // are decoded, and reads from the static and dynamic tables in order to build 8 // complete header entries. Calls an HpackDecoderListener with the completely 9 // decoded headers (i.e. after resolving table indices into names or values), 10 // thus translating the decoded HPACK entries into HTTP/2 headers. 11 12 #ifndef QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_STATE_H_ 13 #define QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_STATE_H_ 14 15 #include <stddef.h> 16 17 #include <cstdint> 18 19 #include "absl/strings/string_view.h" 20 #include "quiche/http2/hpack/decoder/hpack_decoder_listener.h" 21 #include "quiche/http2/hpack/decoder/hpack_decoder_string_buffer.h" 22 #include "quiche/http2/hpack/decoder/hpack_decoder_tables.h" 23 #include "quiche/http2/hpack/decoder/hpack_decoding_error.h" 24 #include "quiche/http2/hpack/decoder/hpack_whole_entry_listener.h" 25 #include "quiche/http2/hpack/http2_hpack_constants.h" 26 #include "quiche/common/platform/api/quiche_export.h" 27 28 namespace http2 { 29 namespace test { 30 class HpackDecoderStatePeer; 31 } // namespace test 32 33 class QUICHE_EXPORT HpackDecoderState : public HpackWholeEntryListener { 34 public: 35 explicit HpackDecoderState(HpackDecoderListener* listener); 36 ~HpackDecoderState() override; 37 38 HpackDecoderState(const HpackDecoderState&) = delete; 39 HpackDecoderState& operator=(const HpackDecoderState&) = delete; 40 41 // Set the listener to be notified when a whole entry has been decoded, 42 // including resolving name or name and value references. 43 // The listener may be changed at any time. listener()44 HpackDecoderListener* listener() const { return listener_; } 45 46 // ApplyHeaderTableSizeSetting notifies this object that this endpoint has 47 // received a SETTINGS ACK frame acknowledging an earlier SETTINGS frame from 48 // this endpoint specifying a new value for SETTINGS_HEADER_TABLE_SIZE (the 49 // maximum size of the dynamic table that this endpoint will use to decode 50 // HPACK blocks). 51 // Because a SETTINGS frame can contain SETTINGS_HEADER_TABLE_SIZE values, 52 // the caller must keep track of those multiple changes, and make 53 // corresponding calls to this method. In particular, a call must be made 54 // with the lowest value acknowledged by the peer, and a call must be made 55 // with the final value acknowledged, in that order; additional calls may 56 // be made if additional values were sent. These calls must be made between 57 // decoding the SETTINGS ACK, and before the next HPACK block is decoded. 58 void ApplyHeaderTableSizeSetting(uint32_t max_header_table_size); 59 60 // Returns the most recently applied value of SETTINGS_HEADER_TABLE_SIZE. GetCurrentHeaderTableSizeSetting()61 size_t GetCurrentHeaderTableSizeSetting() const { 62 return final_header_table_size_; 63 } 64 65 // OnHeaderBlockStart notifies this object that we're starting to decode the 66 // HPACK payload of a HEADERS or PUSH_PROMISE frame. 67 void OnHeaderBlockStart(); 68 69 // Implement the HpackWholeEntryListener methods, each of which notifies this 70 // object when an entire entry has been decoded. 71 void OnIndexedHeader(size_t index) override; 72 void OnNameIndexAndLiteralValue( 73 HpackEntryType entry_type, size_t name_index, 74 HpackDecoderStringBuffer* value_buffer) override; 75 void OnLiteralNameAndValue(HpackEntryType entry_type, 76 HpackDecoderStringBuffer* name_buffer, 77 HpackDecoderStringBuffer* value_buffer) override; 78 void OnDynamicTableSizeUpdate(size_t size) override; 79 void OnHpackDecodeError(HpackDecodingError error) override; 80 81 // OnHeaderBlockEnd notifies this object that an entire HPACK block has been 82 // decoded, which might have extended into CONTINUATION blocks. 83 void OnHeaderBlockEnd(); 84 85 // Returns error code after an error has been detected and reported. 86 // No further callbacks will be made to the listener. error()87 HpackDecodingError error() const { return error_; } 88 GetDynamicTableSize()89 size_t GetDynamicTableSize() const { 90 return decoder_tables_.current_header_table_size(); 91 } 92 decoder_tables_for_test()93 const HpackDecoderTables& decoder_tables_for_test() const { 94 return decoder_tables_; 95 } 96 97 private: 98 friend class test::HpackDecoderStatePeer; 99 100 // Reports an error to the listener IF this is the first error detected. 101 void ReportError(HpackDecodingError error); 102 103 // The static and dynamic HPACK tables. 104 HpackDecoderTables decoder_tables_; 105 106 // The listener to be notified of headers, the start and end of header 107 // lists, and of errors. 108 HpackDecoderListener* listener_; 109 110 // The most recent HEADER_TABLE_SIZE setting acknowledged by the peer. 111 uint32_t final_header_table_size_; 112 113 // The lowest HEADER_TABLE_SIZE setting acknowledged by the peer; valid until 114 // the next HPACK block is decoded. 115 // TODO(jamessynge): Test raising the HEADER_TABLE_SIZE. 116 uint32_t lowest_header_table_size_; 117 118 // Must the next (first) HPACK entry be a dynamic table size update? 119 bool require_dynamic_table_size_update_; 120 121 // May the next (first or second) HPACK entry be a dynamic table size update? 122 bool allow_dynamic_table_size_update_; 123 124 // Have we already seen a dynamic table size update in this HPACK block? 125 bool saw_dynamic_table_size_update_; 126 127 // Has an error already been detected and reported to the listener? 128 HpackDecodingError error_; 129 }; 130 131 } // namespace http2 132 133 #endif // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_STATE_H_ 134