blob: 921d48ca392679eb84929205f6e022ed4e3f6291 [file] [log] [blame]
QUICHE teamfd50a402018-12-07 22:54:05 -05001// 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#include "net/third_party/quiche/src/http2/hpack/decoder/hpack_decoder_state.h"
6
QUICHE teamfd50a402018-12-07 22:54:05 -05007#include "net/third_party/quiche/src/http2/hpack/hpack_string.h"
8#include "net/third_party/quiche/src/http2/http2_constants.h"
QUICHE team61940b42019-03-07 23:32:27 -05009#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
QUICHE teamfd50a402018-12-07 22:54:05 -050010#include "net/third_party/quiche/src/http2/platform/api/http2_macros.h"
11
12namespace http2 {
13namespace {
14
15HpackString ExtractHpackString(HpackDecoderStringBuffer* string_buffer) {
16 if (string_buffer->IsBuffered()) {
17 return HpackString(string_buffer->ReleaseString());
18 } else {
19 auto result = HpackString(string_buffer->str());
20 string_buffer->Reset();
21 return result;
22 }
23}
24
25} // namespace
26
27HpackDecoderState::HpackDecoderState(HpackDecoderListener* listener)
28 : listener_(HTTP2_DIE_IF_NULL(listener)),
29 final_header_table_size_(Http2SettingsInfo::DefaultHeaderTableSize()),
30 lowest_header_table_size_(final_header_table_size_),
31 require_dynamic_table_size_update_(false),
32 allow_dynamic_table_size_update_(true),
33 saw_dynamic_table_size_update_(false),
34 error_detected_(false) {}
35HpackDecoderState::~HpackDecoderState() = default;
36
37void HpackDecoderState::set_tables_debug_listener(
38 HpackDecoderTablesDebugListener* debug_listener) {
39 decoder_tables_.set_debug_listener(debug_listener);
40}
41
42void HpackDecoderState::ApplyHeaderTableSizeSetting(
43 uint32_t header_table_size) {
QUICHE team61940b42019-03-07 23:32:27 -050044 HTTP2_DVLOG(2) << "HpackDecoderState::ApplyHeaderTableSizeSetting("
45 << header_table_size << ")";
QUICHE teamfd50a402018-12-07 22:54:05 -050046 DCHECK_LE(lowest_header_table_size_, final_header_table_size_);
47 if (header_table_size < lowest_header_table_size_) {
48 lowest_header_table_size_ = header_table_size;
49 }
50 final_header_table_size_ = header_table_size;
QUICHE team61940b42019-03-07 23:32:27 -050051 HTTP2_DVLOG(2) << "low water mark: " << lowest_header_table_size_;
52 HTTP2_DVLOG(2) << "final limit: " << final_header_table_size_;
QUICHE teamfd50a402018-12-07 22:54:05 -050053}
54
55// Called to notify this object that we're starting to decode an HPACK block
56// (e.g. a HEADERS or PUSH_PROMISE frame's header has been decoded).
57void HpackDecoderState::OnHeaderBlockStart() {
QUICHE team61940b42019-03-07 23:32:27 -050058 HTTP2_DVLOG(2) << "HpackDecoderState::OnHeaderBlockStart";
QUICHE teamfd50a402018-12-07 22:54:05 -050059 // This instance can't be reused after an error has been detected, as we must
60 // assume that the encoder and decoder compression states are no longer
61 // synchronized.
62 DCHECK(!error_detected_);
63 DCHECK_LE(lowest_header_table_size_, final_header_table_size_);
64 allow_dynamic_table_size_update_ = true;
65 saw_dynamic_table_size_update_ = false;
66 // If the peer has acknowledged a HEADER_TABLE_SIZE smaller than that which
67 // its HPACK encoder has been using, then the next HPACK block it sends MUST
68 // start with a Dynamic Table Size Update entry that is at least as low as
69 // lowest_header_table_size_. That may be followed by another as great as
70 // final_header_table_size_, if those are different.
71 require_dynamic_table_size_update_ =
72 (lowest_header_table_size_ <
73 decoder_tables_.current_header_table_size() ||
74 final_header_table_size_ < decoder_tables_.header_table_size_limit());
QUICHE team61940b42019-03-07 23:32:27 -050075 HTTP2_DVLOG(2) << "HpackDecoderState::OnHeaderListStart "
76 << "require_dynamic_table_size_update_="
77 << require_dynamic_table_size_update_;
QUICHE teamfd50a402018-12-07 22:54:05 -050078 listener_->OnHeaderListStart();
79}
80
81void HpackDecoderState::OnIndexedHeader(size_t index) {
QUICHE team61940b42019-03-07 23:32:27 -050082 HTTP2_DVLOG(2) << "HpackDecoderState::OnIndexedHeader: " << index;
QUICHE teamfd50a402018-12-07 22:54:05 -050083 if (error_detected_) {
84 return;
85 }
86 if (require_dynamic_table_size_update_) {
87 ReportError("Missing dynamic table size update.");
88 return;
89 }
90 allow_dynamic_table_size_update_ = false;
91 const HpackStringPair* entry = decoder_tables_.Lookup(index);
92 if (entry != nullptr) {
93 listener_->OnHeader(HpackEntryType::kIndexedHeader, entry->name,
94 entry->value);
95 } else {
96 ReportError("Invalid index.");
97 }
98}
99
100void HpackDecoderState::OnNameIndexAndLiteralValue(
101 HpackEntryType entry_type,
102 size_t name_index,
103 HpackDecoderStringBuffer* value_buffer) {
QUICHE team61940b42019-03-07 23:32:27 -0500104 HTTP2_DVLOG(2) << "HpackDecoderState::OnNameIndexAndLiteralValue "
105 << entry_type << ", " << name_index << ", "
106 << value_buffer->str();
QUICHE teamfd50a402018-12-07 22:54:05 -0500107 if (error_detected_) {
108 return;
109 }
110 if (require_dynamic_table_size_update_) {
111 ReportError("Missing dynamic table size update.");
112 return;
113 }
114 allow_dynamic_table_size_update_ = false;
115 const HpackStringPair* entry = decoder_tables_.Lookup(name_index);
116 if (entry != nullptr) {
117 HpackString value(ExtractHpackString(value_buffer));
118 listener_->OnHeader(entry_type, entry->name, value);
119 if (entry_type == HpackEntryType::kIndexedLiteralHeader) {
120 decoder_tables_.Insert(entry->name, value);
121 }
122 } else {
123 ReportError("Invalid name index.");
124 }
125}
126
127void HpackDecoderState::OnLiteralNameAndValue(
128 HpackEntryType entry_type,
129 HpackDecoderStringBuffer* name_buffer,
130 HpackDecoderStringBuffer* value_buffer) {
QUICHE team61940b42019-03-07 23:32:27 -0500131 HTTP2_DVLOG(2) << "HpackDecoderState::OnLiteralNameAndValue " << entry_type
132 << ", " << name_buffer->str() << ", " << value_buffer->str();
QUICHE teamfd50a402018-12-07 22:54:05 -0500133 if (error_detected_) {
134 return;
135 }
136 if (require_dynamic_table_size_update_) {
137 ReportError("Missing dynamic table size update.");
138 return;
139 }
140 allow_dynamic_table_size_update_ = false;
141 HpackString name(ExtractHpackString(name_buffer));
142 HpackString value(ExtractHpackString(value_buffer));
143 listener_->OnHeader(entry_type, name, value);
144 if (entry_type == HpackEntryType::kIndexedLiteralHeader) {
145 decoder_tables_.Insert(name, value);
146 }
147}
148
149void HpackDecoderState::OnDynamicTableSizeUpdate(size_t size_limit) {
QUICHE team61940b42019-03-07 23:32:27 -0500150 HTTP2_DVLOG(2) << "HpackDecoderState::OnDynamicTableSizeUpdate " << size_limit
151 << ", required="
152 << (require_dynamic_table_size_update_ ? "true" : "false")
153 << ", allowed="
154 << (allow_dynamic_table_size_update_ ? "true" : "false");
QUICHE teamfd50a402018-12-07 22:54:05 -0500155 if (error_detected_) {
156 return;
157 }
158 DCHECK_LE(lowest_header_table_size_, final_header_table_size_);
159 if (!allow_dynamic_table_size_update_) {
160 // At most two dynamic table size updates allowed at the start, and not
161 // after a header.
162 ReportError("Dynamic table size update not allowed.");
163 return;
164 }
165 if (require_dynamic_table_size_update_) {
166 // The new size must not be greater than the low water mark.
167 if (size_limit > lowest_header_table_size_) {
168 ReportError("Initial dynamic table size update is above low water mark.");
169 return;
170 }
171 require_dynamic_table_size_update_ = false;
172 } else if (size_limit > final_header_table_size_) {
173 // The new size must not be greater than the final max header table size
174 // that the peer acknowledged.
175 ReportError("Dynamic table size update is above acknowledged setting.");
176 return;
177 }
178 decoder_tables_.DynamicTableSizeUpdate(size_limit);
179 if (saw_dynamic_table_size_update_) {
180 allow_dynamic_table_size_update_ = false;
181 } else {
182 saw_dynamic_table_size_update_ = true;
183 }
184 // We no longer need to keep an eye out for a lower header table size.
185 lowest_header_table_size_ = final_header_table_size_;
186}
187
188void HpackDecoderState::OnHpackDecodeError(Http2StringPiece error_message) {
QUICHE team61940b42019-03-07 23:32:27 -0500189 HTTP2_DVLOG(2) << "HpackDecoderState::OnHpackDecodeError " << error_message;
QUICHE teamfd50a402018-12-07 22:54:05 -0500190 if (!error_detected_) {
191 ReportError(error_message);
192 }
193}
194
195void HpackDecoderState::OnHeaderBlockEnd() {
QUICHE team61940b42019-03-07 23:32:27 -0500196 HTTP2_DVLOG(2) << "HpackDecoderState::OnHeaderBlockEnd";
QUICHE teamfd50a402018-12-07 22:54:05 -0500197 if (error_detected_) {
198 return;
199 }
200 if (require_dynamic_table_size_update_) {
201 // Apparently the HPACK block was empty, but we needed it to contain at
202 // least 1 dynamic table size update.
203 ReportError("Missing dynamic table size update.");
204 } else {
205 listener_->OnHeaderListEnd();
206 }
207}
208
209void HpackDecoderState::ReportError(Http2StringPiece error_message) {
QUICHE team61940b42019-03-07 23:32:27 -0500210 HTTP2_DVLOG(2) << "HpackDecoderState::ReportError is new="
211 << (!error_detected_ ? "true" : "false")
212 << ", error_message: " << error_message;
QUICHE teamfd50a402018-12-07 22:54:05 -0500213 if (!error_detected_) {
214 listener_->OnHeaderErrorDetected(error_message);
215 error_detected_ = true;
216 }
217}
218
219} // namespace http2