xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/http2/hpack/decoder/hpack_decoder.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2017 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 #ifndef QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_H_
6 #define QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_H_
7 
8 // Decodes HPACK blocks, calls an HpackDecoderListener with the decoded header
9 // entries. Also notifies the listener of errors and of the boundaries of the
10 // HPACK blocks.
11 
12 // TODO(jamessynge): Add feature allowing an HpackEntryDecoderListener
13 // sub-class (and possibly others) to be passed in for counting events,
14 // so that deciding whether to count is not done by having lots of if
15 // statements, but instead by inserting an indirection only when needed.
16 
17 // TODO(jamessynge): Consider whether to return false from methods below
18 // when an error has been previously detected. It protects calling code
19 // from its failure to pay attention to previous errors, but should we
20 // spend time to do that?
21 
22 #include <stddef.h>
23 
24 #include <cstdint>
25 
26 #include "quiche/http2/decoder/decode_buffer.h"
27 #include "quiche/http2/hpack/decoder/hpack_block_decoder.h"
28 #include "quiche/http2/hpack/decoder/hpack_decoder_listener.h"
29 #include "quiche/http2/hpack/decoder/hpack_decoder_state.h"
30 #include "quiche/http2/hpack/decoder/hpack_decoder_tables.h"
31 #include "quiche/http2/hpack/decoder/hpack_decoding_error.h"
32 #include "quiche/http2/hpack/decoder/hpack_whole_entry_buffer.h"
33 #include "quiche/common/platform/api/quiche_export.h"
34 
35 namespace http2 {
36 namespace test {
37 class HpackDecoderPeer;
38 }  // namespace test
39 
40 class QUICHE_EXPORT HpackDecoder {
41  public:
42   HpackDecoder(HpackDecoderListener* listener, size_t max_string_size);
43   virtual ~HpackDecoder();
44 
45   HpackDecoder(const HpackDecoder&) = delete;
46   HpackDecoder& operator=(const HpackDecoder&) = delete;
47 
48   // max_string_size specifies the maximum size of an on-the-wire string (name
49   // or value, plain or Huffman encoded) that will be accepted. See sections
50   // 5.1 and 5.2 of RFC 7541. This is a defense against OOM attacks; HTTP/2
51   // allows a decoder to enforce any limit of the size of the header lists
52   // that it is willing to decode, including less than the MAX_HEADER_LIST_SIZE
53   // setting, a setting that is initially unlimited. For example, we might
54   // choose to send a MAX_HEADER_LIST_SIZE of 64KB, and to use that same value
55   // as the upper bound for individual strings.
56   void set_max_string_size_bytes(size_t max_string_size_bytes);
57 
58   // ApplyHeaderTableSizeSetting notifies this object that this endpoint has
59   // received a SETTINGS ACK frame acknowledging an earlier SETTINGS frame from
60   // this endpoint specifying a new value for SETTINGS_HEADER_TABLE_SIZE (the
61   // maximum size of the dynamic table that this endpoint will use to decode
62   // HPACK blocks).
63   // Because a SETTINGS frame can contain SETTINGS_HEADER_TABLE_SIZE values,
64   // the caller must keep track of those multiple changes, and make
65   // corresponding calls to this method. In particular, a call must be made
66   // with the lowest value acknowledged by the peer, and a call must be made
67   // with the final value acknowledged, in that order; additional calls may
68   // be made if additional values were sent. These calls must be made between
69   // decoding the SETTINGS ACK, and before the next HPACK block is decoded.
70   void ApplyHeaderTableSizeSetting(uint32_t max_header_table_size);
71 
72   // Returns the most recently applied value of SETTINGS_HEADER_TABLE_SIZE.
GetCurrentHeaderTableSizeSetting()73   size_t GetCurrentHeaderTableSizeSetting() const {
74     return decoder_state_.GetCurrentHeaderTableSizeSetting();
75   }
76 
77   // Prepares the decoder for decoding a new HPACK block, and announces this to
78   // its listener. Returns true if OK to continue with decoding, false if an
79   // error has been detected, which for StartDecodingBlock means the error was
80   // detected while decoding a previous HPACK block.
81   bool StartDecodingBlock();
82 
83   // Decodes a fragment (some or all of the remainder) of an HPACK block,
84   // reporting header entries (name & value pairs) that it completely decodes
85   // in the process to the listener. Returns true successfully decoded, false if
86   // an error has been detected, either during decoding of the fragment, or
87   // prior to this call.
88   bool DecodeFragment(DecodeBuffer* db);
89 
90   // Completes the process of decoding an HPACK block: if the HPACK block was
91   // properly terminated, announces the end of the header list to the listener
92   // and returns true; else returns false.
93   bool EndDecodingBlock();
94 
95   // If no error has been detected so far, query |decoder_state_| for errors and
96   // set |error_| if necessary.  Returns true if an error has ever been
97   // detected.
98   bool DetectError();
99 
GetDynamicTableSize()100   size_t GetDynamicTableSize() const {
101     return decoder_state_.GetDynamicTableSize();
102   }
103 
104   // Error code if an error has occurred, HpackDecodingError::kOk otherwise.
error()105   HpackDecodingError error() const { return error_; }
106 
107  private:
108   friend class test::HpackDecoderPeer;
109 
110   // Reports an error to the listener IF this is the first error detected.
111   void ReportError(HpackDecodingError error);
112 
113   // The decompressor state, as defined by HPACK (i.e. the static and dynamic
114   // tables).
115   HpackDecoderState decoder_state_;
116 
117   // Assembles the various parts of a header entry into whole entries.
118   HpackWholeEntryBuffer entry_buffer_;
119 
120   // The decoder of HPACK blocks into entry parts, passed to entry_buffer_.
121   HpackBlockDecoder block_decoder_;
122 
123   // Error code if an error has occurred, HpackDecodingError::kOk otherwise.
124   HpackDecodingError error_;
125 };
126 
127 }  // namespace http2
128 
129 #endif  // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_H_
130