1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
20
21 #include <grpc/slice.h>
22 #include <grpc/support/port_platform.h>
23 #include <stddef.h>
24 #include <stdlib.h>
25
26 #include <algorithm>
27 #include <memory>
28 #include <string>
29 #include <utility>
30
31 #include "absl/base/attributes.h"
32 #include "absl/log/check.h"
33 #include "absl/log/log.h"
34 #include "absl/status/status.h"
35 #include "absl/strings/match.h"
36 #include "absl/strings/str_cat.h"
37 #include "absl/strings/string_view.h"
38 #include "absl/types/optional.h"
39 #include "absl/types/span.h"
40 #include "absl/types/variant.h"
41 #include "src/core/ext/transport/chttp2/transport/decode_huff.h"
42 #include "src/core/ext/transport/chttp2/transport/hpack_constants.h"
43 #include "src/core/ext/transport/chttp2/transport/hpack_parse_result.h"
44 #include "src/core/ext/transport/chttp2/transport/hpack_parser_table.h"
45 #include "src/core/lib/debug/trace.h"
46 #include "src/core/lib/slice/slice.h"
47 #include "src/core/lib/slice/slice_refcount.h"
48 #include "src/core/lib/surface/validate_metadata.h"
49 #include "src/core/lib/transport/metadata_info.h"
50 #include "src/core/lib/transport/parsed_metadata.h"
51 #include "src/core/telemetry/call_tracer.h"
52 #include "src/core/telemetry/stats.h"
53 #include "src/core/telemetry/stats_data.h"
54 #include "src/core/util/match.h"
55
56 // IWYU pragma: no_include <type_traits>
57
58 namespace grpc_core {
59
60 namespace {
61 // The alphabet used for base64 encoding binary metadata.
62 constexpr char kBase64Alphabet[] =
63 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
64
65 // An inverted table: for each value in kBase64Alphabet, table contains the
66 // index with which it's stored, so we can quickly invert the encoding without
67 // any complicated runtime logic.
68 struct Base64InverseTable {
69 uint8_t table[256]{};
Base64InverseTablegrpc_core::__anond64403910111::Base64InverseTable70 constexpr Base64InverseTable() {
71 for (int i = 0; i < 256; i++) {
72 table[i] = 255;
73 }
74 for (const char* p = kBase64Alphabet; *p; p++) {
75 uint8_t idx = *p;
76 uint8_t ofs = p - kBase64Alphabet;
77 table[idx] = ofs;
78 }
79 }
80 };
81
82 constexpr Base64InverseTable kBase64InverseTable;
83
84 } // namespace
85
86 // Input tracks the current byte through the input data and provides it
87 // via a simple stream interface.
88 class HPackParser::Input {
89 public:
Input(grpc_slice_refcount * current_slice_refcount,const uint8_t * begin,const uint8_t * end,absl::BitGenRef bitsrc,HpackParseResult & frame_error,HpackParseResult & field_error)90 Input(grpc_slice_refcount* current_slice_refcount, const uint8_t* begin,
91 const uint8_t* end, absl::BitGenRef bitsrc,
92 HpackParseResult& frame_error, HpackParseResult& field_error)
93 : current_slice_refcount_(current_slice_refcount),
94 begin_(begin),
95 end_(end),
96 frontier_(begin),
97 frame_error_(frame_error),
98 field_error_(field_error),
99 bitsrc_(bitsrc) {}
100
101 // If input is backed by a slice, retrieve its refcount. If not, return
102 // nullptr.
slice_refcount()103 grpc_slice_refcount* slice_refcount() { return current_slice_refcount_; }
104
105 // Have we reached the end of input?
end_of_stream() const106 bool end_of_stream() const { return begin_ == end_; }
107 // How many bytes until end of input
remaining() const108 size_t remaining() const { return end_ - begin_; }
109 // Current position, as a pointer
cur_ptr() const110 const uint8_t* cur_ptr() const { return begin_; }
111 // End position, as a pointer
end_ptr() const112 const uint8_t* end_ptr() const { return end_; }
113 // Move read position forward by n, unchecked
Advance(size_t n)114 void Advance(size_t n) { begin_ += n; }
115
116 // Retrieve the current character, or nullopt if end of stream
117 // Do not advance
peek() const118 absl::optional<uint8_t> peek() const {
119 if (end_of_stream()) {
120 return {};
121 }
122 return *begin_;
123 }
124
125 // Retrieve and advance past the current character, or return nullopt if end
126 // of stream
Next()127 absl::optional<uint8_t> Next() {
128 if (end_of_stream()) {
129 UnexpectedEOF(/*min_progress_size=*/1);
130 return absl::optional<uint8_t>();
131 }
132 return *begin_++;
133 }
134
135 // Helper to parse a varint delta on top of value, return nullopt on failure
136 // (setting error)
ParseVarint(uint32_t value)137 absl::optional<uint32_t> ParseVarint(uint32_t value) {
138 // TODO(ctiller): break out a variant of this when we know there are at
139 // least 5 bytes in input_
140 auto cur = Next();
141 if (!cur) return {};
142 value += *cur & 0x7f;
143 if ((*cur & 0x80) == 0) return value;
144
145 cur = Next();
146 if (!cur) return {};
147 value += (*cur & 0x7f) << 7;
148 if ((*cur & 0x80) == 0) return value;
149
150 cur = Next();
151 if (!cur) return {};
152 value += (*cur & 0x7f) << 14;
153 if ((*cur & 0x80) == 0) return value;
154
155 cur = Next();
156 if (!cur) return {};
157 value += (*cur & 0x7f) << 21;
158 if ((*cur & 0x80) == 0) return value;
159
160 cur = Next();
161 if (!cur) return {};
162 uint32_t c = (*cur) & 0x7f;
163 // We might overflow here, so we need to be a little careful about the
164 // addition
165 if (c > 0xf) return ParseVarintOutOfRange(value, *cur);
166 const uint32_t add = c << 28;
167 if (add > 0xffffffffu - value) {
168 return ParseVarintOutOfRange(value, *cur);
169 }
170 value += add;
171 if ((*cur & 0x80) == 0) return value;
172
173 // Spec weirdness: we can add an infinite stream of 0x80 at the end of a
174 // varint and still end up with a correctly encoded varint.
175 // We allow up to 16 just for kicks, but any more and we'll assume the
176 // sender is being malicious.
177 int num_redundant_0x80 = 0;
178 do {
179 cur = Next();
180 if (!cur.has_value()) return {};
181 ++num_redundant_0x80;
182 if (num_redundant_0x80 == 16) {
183 return ParseVarintMaliciousEncoding();
184 }
185 } while (*cur == 0x80);
186
187 // BUT... the last byte needs to be 0x00 or we'll overflow dramatically!
188 if (*cur == 0) return value;
189 return ParseVarintOutOfRange(value, *cur);
190 }
191
192 // Parse a string prefix
ParseStringPrefix()193 absl::optional<StringPrefix> ParseStringPrefix() {
194 auto cur = Next();
195 if (!cur.has_value()) {
196 DCHECK(eof_error());
197 return {};
198 }
199 // Huffman if the top bit is 1
200 const bool huff = (*cur & 0x80) != 0;
201 // String length
202 uint32_t strlen = (*cur & 0x7f);
203 if (strlen == 0x7f) {
204 // all ones ==> varint string length
205 auto v = ParseVarint(0x7f);
206 if (!v.has_value()) {
207 DCHECK(eof_error());
208 return {};
209 }
210 strlen = *v;
211 }
212 return StringPrefix{strlen, huff};
213 }
214
215 // Check if we saw an EOF
eof_error() const216 bool eof_error() const {
217 return min_progress_size_ != 0 || frame_error_.connection_error();
218 }
219
220 // Reset the field error to be ok
ClearFieldError()221 void ClearFieldError() {
222 if (field_error_.ok()) return;
223 field_error_ = HpackParseResult();
224 }
225
226 // Minimum number of bytes to unstuck the current parse
min_progress_size() const227 size_t min_progress_size() const { return min_progress_size_; }
228
229 // Set the current error - tweaks the error to include a stream id so that
230 // chttp2 does not close the connection.
231 // Intended for errors that are specific to a stream and recoverable.
232 // Callers should ensure that any hpack table updates happen.
SetErrorAndContinueParsing(HpackParseResult error)233 void SetErrorAndContinueParsing(HpackParseResult error) {
234 DCHECK(error.stream_error());
235 SetError(std::move(error));
236 }
237
238 // Set the current error, and skip past remaining bytes.
239 // Intended for unrecoverable errors, with the expectation that they will
240 // close the connection on return to chttp2.
SetErrorAndStopParsing(HpackParseResult error)241 void SetErrorAndStopParsing(HpackParseResult error) {
242 DCHECK(error.connection_error());
243 SetError(std::move(error));
244 begin_ = end_;
245 }
246
247 // Set the error to an unexpected eof.
248 // min_progress_size: how many bytes beyond the current frontier do we need to
249 // read prior to being able to get further in this parse.
UnexpectedEOF(size_t min_progress_size)250 void UnexpectedEOF(size_t min_progress_size) {
251 CHECK_GT(min_progress_size, 0u);
252 if (eof_error()) return;
253 // Set min progress size, taking into account bytes parsed already but not
254 // consumed.
255 min_progress_size_ = min_progress_size + (begin_ - frontier_);
256 DCHECK(eof_error());
257 }
258
259 // Update the frontier - signifies we've successfully parsed another element
UpdateFrontier()260 void UpdateFrontier() {
261 DCHECK_EQ(skip_bytes_, 0u);
262 frontier_ = begin_;
263 }
264
UpdateFrontierAndSkipBytes(size_t skip_bytes)265 void UpdateFrontierAndSkipBytes(size_t skip_bytes) {
266 UpdateFrontier();
267 size_t remaining = end_ - begin_;
268 if (skip_bytes >= remaining) {
269 // If we have more bytes to skip than we have remaining in this buffer
270 // then we skip over what's there and stash that we need to skip some
271 // more.
272 skip_bytes_ = skip_bytes - remaining;
273 frontier_ = end_;
274 } else {
275 // Otherwise we zoom through some bytes and continue parsing.
276 frontier_ += skip_bytes_;
277 }
278 }
279
280 // Get the frontier - for buffering should we fail due to eof
frontier() const281 const uint8_t* frontier() const { return frontier_; }
282
283 // Access the rng
bitsrc()284 absl::BitGenRef bitsrc() { return bitsrc_; }
285
286 private:
287 // Helper to set the error to out of range for ParseVarint
ParseVarintOutOfRange(uint32_t value,uint8_t last_byte)288 absl::optional<uint32_t> ParseVarintOutOfRange(uint32_t value,
289 uint8_t last_byte) {
290 SetErrorAndStopParsing(
291 HpackParseResult::VarintOutOfRangeError(value, last_byte));
292 return absl::optional<uint32_t>();
293 }
294
295 // Helper to set the error in the case of a malicious encoding
ParseVarintMaliciousEncoding()296 absl::optional<uint32_t> ParseVarintMaliciousEncoding() {
297 SetErrorAndStopParsing(HpackParseResult::MaliciousVarintEncodingError());
298 return absl::optional<uint32_t>();
299 }
300
301 // If no error is set, set it to the given error (i.e. first error wins)
302 // Do not use this directly, instead use SetErrorAndContinueParsing or
303 // SetErrorAndStopParsing.
SetError(HpackParseResult error)304 void SetError(HpackParseResult error) {
305 SetErrorFor(frame_error_, error);
306 SetErrorFor(field_error_, std::move(error));
307 }
308
SetErrorFor(HpackParseResult & error,HpackParseResult new_error)309 void SetErrorFor(HpackParseResult& error, HpackParseResult new_error) {
310 if (!error.ok() || min_progress_size_ > 0) {
311 if (new_error.connection_error() && !error.connection_error()) {
312 error = std::move(new_error); // connection errors dominate
313 }
314 return;
315 }
316 error = std::move(new_error);
317 }
318
319 // Refcount if we are backed by a slice
320 grpc_slice_refcount* current_slice_refcount_;
321 // Current input point
322 const uint8_t* begin_;
323 // End of stream point
324 const uint8_t* const end_;
325 // Frontier denotes the first byte past successfully processed input
326 const uint8_t* frontier_;
327 // Current error
328 HpackParseResult& frame_error_;
329 HpackParseResult& field_error_;
330 // If the error was EOF, we flag it here by noting how many more bytes would
331 // be needed to make progress
332 size_t min_progress_size_ = 0;
333 // Number of bytes that should be skipped before parsing resumes.
334 // (We've failed parsing a request for whatever reason, but we're still
335 // continuing the connection so we need to see future opcodes after this bit).
336 size_t skip_bytes_ = 0;
337 // Random number generator
338 absl::BitGenRef bitsrc_;
339 };
340
string_view() const341 absl::string_view HPackParser::String::string_view() const {
342 if (auto* p = absl::get_if<Slice>(&value_)) {
343 return p->as_string_view();
344 } else if (auto* p = absl::get_if<absl::Span<const uint8_t>>(&value_)) {
345 return absl::string_view(reinterpret_cast<const char*>(p->data()),
346 p->size());
347 } else if (auto* p = absl::get_if<std::vector<uint8_t>>(&value_)) {
348 return absl::string_view(reinterpret_cast<const char*>(p->data()),
349 p->size());
350 }
351 GPR_UNREACHABLE_CODE(return absl::string_view());
352 }
353
354 template <typename Out>
ParseHuff(Input * input,uint32_t length,Out output)355 HpackParseStatus HPackParser::String::ParseHuff(Input* input, uint32_t length,
356 Out output) {
357 // If there's insufficient bytes remaining, return now.
358 if (input->remaining() < length) {
359 input->UnexpectedEOF(/*min_progress_size=*/length);
360 return HpackParseStatus::kEof;
361 }
362 // Grab the byte range, and iterate through it.
363 const uint8_t* p = input->cur_ptr();
364 input->Advance(length);
365 return HuffDecoder<Out>(output, p, p + length).Run()
366 ? HpackParseStatus::kOk
367 : HpackParseStatus::kParseHuffFailed;
368 }
369
370 struct HPackParser::String::StringResult {
371 StringResult() = delete;
StringResultgrpc_core::HPackParser::String::StringResult372 StringResult(HpackParseStatus status, size_t wire_size, String value)
373 : status(status), wire_size(wire_size), value(std::move(value)) {}
374 HpackParseStatus status;
375 size_t wire_size;
376 String value;
377 };
378
ParseUncompressed(Input * input,uint32_t length,uint32_t wire_size)379 HPackParser::String::StringResult HPackParser::String::ParseUncompressed(
380 Input* input, uint32_t length, uint32_t wire_size) {
381 // Check there's enough bytes
382 if (input->remaining() < length) {
383 input->UnexpectedEOF(/*min_progress_size=*/length);
384 DCHECK(input->eof_error());
385 return StringResult{HpackParseStatus::kEof, wire_size, String{}};
386 }
387 auto* refcount = input->slice_refcount();
388 auto* p = input->cur_ptr();
389 input->Advance(length);
390 if (refcount != nullptr) {
391 return StringResult{HpackParseStatus::kOk, wire_size,
392 String(refcount, p, p + length)};
393 } else {
394 return StringResult{HpackParseStatus::kOk, wire_size,
395 String(absl::Span<const uint8_t>(p, length))};
396 }
397 }
398
Unbase64Loop(const uint8_t * cur,const uint8_t * end)399 absl::optional<std::vector<uint8_t>> HPackParser::String::Unbase64Loop(
400 const uint8_t* cur, const uint8_t* end) {
401 while (cur != end && end[-1] == '=') {
402 --end;
403 }
404
405 std::vector<uint8_t> out;
406 out.reserve((3 * (end - cur) / 4) + 3);
407
408 // Decode 4 bytes at a time while we can
409 while (end - cur >= 4) {
410 uint32_t bits = kBase64InverseTable.table[*cur];
411 if (bits > 63) return {};
412 uint32_t buffer = bits << 18;
413 ++cur;
414
415 bits = kBase64InverseTable.table[*cur];
416 if (bits > 63) return {};
417 buffer |= bits << 12;
418 ++cur;
419
420 bits = kBase64InverseTable.table[*cur];
421 if (bits > 63) return {};
422 buffer |= bits << 6;
423 ++cur;
424
425 bits = kBase64InverseTable.table[*cur];
426 if (bits > 63) return {};
427 buffer |= bits;
428 ++cur;
429
430 out.insert(out.end(), {static_cast<uint8_t>(buffer >> 16),
431 static_cast<uint8_t>(buffer >> 8),
432 static_cast<uint8_t>(buffer)});
433 }
434 // Deal with the last 0, 1, 2, or 3 bytes.
435 switch (end - cur) {
436 case 0:
437 return out;
438 case 1:
439 return {};
440 case 2: {
441 uint32_t bits = kBase64InverseTable.table[*cur];
442 if (bits > 63) return {};
443 uint32_t buffer = bits << 18;
444
445 ++cur;
446 bits = kBase64InverseTable.table[*cur];
447 if (bits > 63) return {};
448 buffer |= bits << 12;
449
450 if (buffer & 0xffff) return {};
451 out.push_back(static_cast<uint8_t>(buffer >> 16));
452 return out;
453 }
454 case 3: {
455 uint32_t bits = kBase64InverseTable.table[*cur];
456 if (bits > 63) return {};
457 uint32_t buffer = bits << 18;
458
459 ++cur;
460 bits = kBase64InverseTable.table[*cur];
461 if (bits > 63) return {};
462 buffer |= bits << 12;
463
464 ++cur;
465 bits = kBase64InverseTable.table[*cur];
466 if (bits > 63) return {};
467 buffer |= bits << 6;
468
469 ++cur;
470 if (buffer & 0xff) return {};
471 out.push_back(static_cast<uint8_t>(buffer >> 16));
472 out.push_back(static_cast<uint8_t>(buffer >> 8));
473 return out;
474 }
475 }
476
477 GPR_UNREACHABLE_CODE(return out;);
478 }
479
Unbase64(String s)480 HPackParser::String::StringResult HPackParser::String::Unbase64(String s) {
481 absl::optional<std::vector<uint8_t>> result;
482 if (auto* p = absl::get_if<Slice>(&s.value_)) {
483 result = Unbase64Loop(p->begin(), p->end());
484 }
485 if (auto* p = absl::get_if<absl::Span<const uint8_t>>(&s.value_)) {
486 result = Unbase64Loop(p->begin(), p->end());
487 }
488 if (auto* p = absl::get_if<std::vector<uint8_t>>(&s.value_)) {
489 result = Unbase64Loop(p->data(), p->data() + p->size());
490 }
491 if (!result.has_value()) {
492 return StringResult{HpackParseStatus::kUnbase64Failed,
493 s.string_view().length(), String{}};
494 }
495 return StringResult{HpackParseStatus::kOk, s.string_view().length(),
496 String(std::move(*result))};
497 }
498
Parse(Input * input,bool is_huff,size_t length)499 HPackParser::String::StringResult HPackParser::String::Parse(Input* input,
500 bool is_huff,
501 size_t length) {
502 if (is_huff) {
503 // Huffman coded
504 std::vector<uint8_t> output;
505 HpackParseStatus sts =
506 ParseHuff(input, length, [&output](uint8_t c) { output.push_back(c); });
507 size_t wire_len = output.size();
508 return StringResult{sts, wire_len, String(std::move(output))};
509 }
510 return ParseUncompressed(input, length, length);
511 }
512
ParseBinary(Input * input,bool is_huff,size_t length)513 HPackParser::String::StringResult HPackParser::String::ParseBinary(
514 Input* input, bool is_huff, size_t length) {
515 if (!is_huff) {
516 if (length > 0 && input->peek() == 0) {
517 // 'true-binary'
518 input->Advance(1);
519 return ParseUncompressed(input, length - 1, length);
520 }
521 // Base64 encoded... pull out the string, then unbase64 it
522 auto base64 = ParseUncompressed(input, length, length);
523 if (base64.status != HpackParseStatus::kOk) return base64;
524 return Unbase64(std::move(base64.value));
525 } else {
526 // Huffman encoded...
527 std::vector<uint8_t> decompressed;
528 // State here says either we don't know if it's base64 or binary, or we do
529 // and what is it.
530 enum class State { kUnsure, kBinary, kBase64 };
531 State state = State::kUnsure;
532 auto sts = ParseHuff(input, length, [&state, &decompressed](uint8_t c) {
533 if (state == State::kUnsure) {
534 // First byte... if it's zero it's binary
535 if (c == 0) {
536 // Save the type, and skip the zero
537 state = State::kBinary;
538 return;
539 } else {
540 // Flag base64, store this value
541 state = State::kBase64;
542 }
543 }
544 // Non-first byte, or base64 first byte
545 decompressed.push_back(c);
546 });
547 if (sts != HpackParseStatus::kOk) {
548 return StringResult{sts, 0, String{}};
549 }
550 switch (state) {
551 case State::kUnsure:
552 // No bytes, empty span
553 return StringResult{HpackParseStatus::kOk, 0,
554 String(absl::Span<const uint8_t>())};
555 case State::kBinary:
556 // Binary, we're done
557 {
558 size_t wire_len = decompressed.size();
559 return StringResult{HpackParseStatus::kOk, wire_len,
560 String(std::move(decompressed))};
561 }
562 case State::kBase64:
563 // Base64 - unpack it
564 return Unbase64(String(std::move(decompressed)));
565 }
566 GPR_UNREACHABLE_CODE(abort(););
567 }
568 }
569
570 // Parser parses one key/value pair from a byte stream.
571 class HPackParser::Parser {
572 public:
Parser(Input * input,grpc_metadata_batch * & metadata_buffer,InterSliceState & state,LogInfo log_info)573 Parser(Input* input, grpc_metadata_batch*& metadata_buffer,
574 InterSliceState& state, LogInfo log_info)
575 : input_(input),
576 metadata_buffer_(metadata_buffer),
577 state_(state),
578 log_info_(log_info) {}
579
Parse()580 bool Parse() {
581 switch (state_.parse_state) {
582 case ParseState::kTop:
583 return ParseTop();
584 case ParseState::kParsingKeyLength:
585 return ParseKeyLength();
586 case ParseState::kParsingKeyBody:
587 return ParseKeyBody();
588 case ParseState::kSkippingKeyBody:
589 return SkipKeyBody();
590 case ParseState::kParsingValueLength:
591 return ParseValueLength();
592 case ParseState::kParsingValueBody:
593 return ParseValueBody();
594 case ParseState::kSkippingValueLength:
595 return SkipValueLength();
596 case ParseState::kSkippingValueBody:
597 return SkipValueBody();
598 }
599 GPR_UNREACHABLE_CODE(return false);
600 }
601
602 private:
ParseTop()603 bool ParseTop() {
604 DCHECK(state_.parse_state == ParseState::kTop);
605 auto cur = *input_->Next();
606 input_->ClearFieldError();
607 switch (cur >> 4) {
608 // Literal header not indexed - First byte format: 0000xxxx
609 // Literal header never indexed - First byte format: 0001xxxx
610 // Where xxxx:
611 // 0000 - literal key
612 // 1111 - indexed key, varint encoded index
613 // other - indexed key, inline encoded index
614 case 0:
615 case 1:
616 switch (cur & 0xf) {
617 case 0: // literal key
618 return StartParseLiteralKey(false);
619 case 0xf: // varint encoded key index
620 return StartVarIdxKey(0xf, false);
621 default: // inline encoded key index
622 return StartIdxKey(cur & 0xf, false);
623 }
624 // Update max table size.
625 // First byte format: 001xxxxx
626 // Where xxxxx:
627 // 11111 - max size is varint encoded
628 // other - max size is stored inline
629 case 2:
630 // inline encoded max table size
631 return FinishMaxTableSize(cur & 0x1f);
632 case 3:
633 if (cur == 0x3f) {
634 // varint encoded max table size
635 return FinishMaxTableSize(input_->ParseVarint(0x1f));
636 } else {
637 // inline encoded max table size
638 return FinishMaxTableSize(cur & 0x1f);
639 }
640 // Literal header with incremental indexing.
641 // First byte format: 01xxxxxx
642 // Where xxxxxx:
643 // 000000 - literal key
644 // 111111 - indexed key, varint encoded index
645 // other - indexed key, inline encoded index
646 case 4:
647 if (cur == 0x40) {
648 // literal key
649 return StartParseLiteralKey(true);
650 }
651 ABSL_FALLTHROUGH_INTENDED;
652 case 5:
653 case 6:
654 // inline encoded key index
655 return StartIdxKey(cur & 0x3f, true);
656 case 7:
657 if (cur == 0x7f) {
658 // varint encoded key index
659 return StartVarIdxKey(0x3f, true);
660 } else {
661 // inline encoded key index
662 return StartIdxKey(cur & 0x3f, true);
663 }
664 // Indexed Header Field Representation
665 // First byte format: 1xxxxxxx
666 // Where xxxxxxx:
667 // 0000000 - illegal
668 // 1111111 - varint encoded field index
669 // other - inline encoded field index
670 case 8:
671 if (cur == 0x80) {
672 // illegal value.
673 input_->SetErrorAndStopParsing(
674 HpackParseResult::IllegalHpackOpCode());
675 return false;
676 }
677 ABSL_FALLTHROUGH_INTENDED;
678 case 9:
679 case 10:
680 case 11:
681 case 12:
682 case 13:
683 case 14:
684 // inline encoded field index
685 return FinishIndexed(cur & 0x7f);
686 case 15:
687 if (cur == 0xff) {
688 // varint encoded field index
689 return FinishIndexed(input_->ParseVarint(0x7f));
690 } else {
691 // inline encoded field index
692 return FinishIndexed(cur & 0x7f);
693 }
694 }
695 GPR_UNREACHABLE_CODE(abort());
696 }
697
LogHeader(const HPackTable::Memento & memento)698 void GPR_ATTRIBUTE_NOINLINE LogHeader(const HPackTable::Memento& memento) {
699 const char* type;
700 switch (log_info_.type) {
701 case LogInfo::kHeaders:
702 type = "HDR";
703 break;
704 case LogInfo::kTrailers:
705 type = "TRL";
706 break;
707 case LogInfo::kDontKnow:
708 type = "???";
709 break;
710 }
711 LOG(INFO) << "HTTP:" << log_info_.stream_id << ":" << type << ":"
712 << (log_info_.is_client ? "CLI" : "SVR") << ": "
713 << memento.md.DebugString()
714 << (memento.parse_status.get() == nullptr
715 ? ""
716 : absl::StrCat(
717 " (parse error: ",
718 memento.parse_status->Materialize().ToString(),
719 ")"));
720 }
721
EmitHeader(const HPackTable::Memento & md)722 void EmitHeader(const HPackTable::Memento& md) {
723 // Pass up to the transport
724 state_.frame_length += md.md.transport_size();
725 if (md.parse_status.get() != nullptr) {
726 // Reject any requests with invalid metadata.
727 input_->SetErrorAndContinueParsing(*md.parse_status);
728 }
729 if (GPR_LIKELY(metadata_buffer_ != nullptr)) {
730 metadata_buffer_->Set(md.md);
731 }
732 if (state_.metadata_early_detection.MustReject(state_.frame_length)) {
733 // Reject any requests above hard metadata limit.
734 input_->SetErrorAndContinueParsing(
735 HpackParseResult::HardMetadataLimitExceededError(
736 std::exchange(metadata_buffer_, nullptr), state_.frame_length,
737 state_.metadata_early_detection.hard_limit()));
738 }
739 }
740
FinishHeaderAndAddToTable(HPackTable::Memento md)741 bool FinishHeaderAndAddToTable(HPackTable::Memento md) {
742 // Log if desired
743 if (GRPC_TRACE_FLAG_ENABLED(chttp2_hpack_parser)) {
744 LogHeader(md);
745 }
746 // Emit whilst we own the metadata.
747 EmitHeader(md);
748 // Add to the hpack table
749 if (GPR_UNLIKELY(!state_.hpack_table.Add(std::move(md)))) {
750 input_->SetErrorAndStopParsing(
751 HpackParseResult::AddBeforeTableSizeUpdated(
752 state_.hpack_table.current_table_bytes(),
753 state_.hpack_table.max_bytes()));
754 return false;
755 };
756 return true;
757 }
758
FinishHeaderOmitFromTable(absl::optional<HPackTable::Memento> md)759 bool FinishHeaderOmitFromTable(absl::optional<HPackTable::Memento> md) {
760 // Allow higher code to just pass in failures ... simplifies things a bit.
761 if (!md.has_value()) return false;
762 FinishHeaderOmitFromTable(*md);
763 return true;
764 }
765
FinishHeaderOmitFromTable(const HPackTable::Memento & md)766 void FinishHeaderOmitFromTable(const HPackTable::Memento& md) {
767 // Log if desired
768 if (GRPC_TRACE_FLAG_ENABLED(chttp2_hpack_parser)) {
769 LogHeader(md);
770 }
771 EmitHeader(md);
772 }
773
774 // Parse an index encoded key and a string encoded value
StartIdxKey(uint32_t index,bool add_to_table)775 bool StartIdxKey(uint32_t index, bool add_to_table) {
776 DCHECK(state_.parse_state == ParseState::kTop);
777 input_->UpdateFrontier();
778 const auto* elem = state_.hpack_table.Lookup(index);
779 if (GPR_UNLIKELY(elem == nullptr)) {
780 InvalidHPackIndexError(index);
781 return false;
782 }
783 state_.parse_state = ParseState::kParsingValueLength;
784 state_.is_binary_header = elem->md.is_binary_header();
785 state_.key.emplace<const HPackTable::Memento*>(elem);
786 state_.add_to_table = add_to_table;
787 return ParseValueLength();
788 };
789
790 // Parse a varint index encoded key and a string encoded value
StartVarIdxKey(uint32_t offset,bool add_to_table)791 bool StartVarIdxKey(uint32_t offset, bool add_to_table) {
792 DCHECK(state_.parse_state == ParseState::kTop);
793 auto index = input_->ParseVarint(offset);
794 if (GPR_UNLIKELY(!index.has_value())) return false;
795 return StartIdxKey(*index, add_to_table);
796 }
797
StartParseLiteralKey(bool add_to_table)798 bool StartParseLiteralKey(bool add_to_table) {
799 DCHECK(state_.parse_state == ParseState::kTop);
800 state_.add_to_table = add_to_table;
801 state_.parse_state = ParseState::kParsingKeyLength;
802 input_->UpdateFrontier();
803 return ParseKeyLength();
804 }
805
ShouldSkipParsingString(uint64_t string_length) const806 bool ShouldSkipParsingString(uint64_t string_length) const {
807 // We skip parsing if the string is longer than the current table size, and
808 // if we would have to reject the string due to metadata length limits
809 // regardless of what else was in the metadata batch.
810 //
811 // Why longer than the current table size? - it simplifies the logic at the
812 // end of skipping the string (and possibly a second if this is a key).
813 // If a key/value pair longer than the current table size is added to the
814 // hpack table we're forced to clear the entire table - this is a
815 // predictable operation that's easy to encode and doesn't need any state
816 // other than "skipping" to be carried forward.
817 // If we did not do this, we could end up in a situation where even though
818 // the metadata would overflow the current limit, it might not overflow the
819 // current hpack table size, and so we could not skip in on the off chance
820 // that we'd need to add it to the hpack table *and* reject the batch as a
821 // whole.
822 // That would be a mess, we're not doing it.
823 //
824 // These rules will end up having us parse some things that ultimately get
825 // rejected, and that's ok: the important thing is to have a bounded maximum
826 // so we can't be forced to infinitely buffer - not to have a perfect
827 // computation here.
828 return string_length > state_.hpack_table.current_table_size() &&
829 state_.metadata_early_detection.MustReject(
830 string_length + hpack_constants::kEntryOverhead);
831 }
832
ParseKeyLength()833 bool ParseKeyLength() {
834 DCHECK(state_.parse_state == ParseState::kParsingKeyLength);
835 auto pfx = input_->ParseStringPrefix();
836 if (!pfx.has_value()) return false;
837 state_.is_string_huff_compressed = pfx->huff;
838 state_.string_length = pfx->length;
839 input_->UpdateFrontier();
840 if (ShouldSkipParsingString(state_.string_length)) {
841 input_->SetErrorAndContinueParsing(
842 HpackParseResult::HardMetadataLimitExceededByKeyError(
843 state_.string_length,
844 state_.metadata_early_detection.hard_limit()));
845 metadata_buffer_ = nullptr;
846 state_.parse_state = ParseState::kSkippingKeyBody;
847 return SkipKeyBody();
848 } else {
849 state_.parse_state = ParseState::kParsingKeyBody;
850 return ParseKeyBody();
851 }
852 }
853
ParseKeyBody()854 bool ParseKeyBody() {
855 DCHECK(state_.parse_state == ParseState::kParsingKeyBody);
856 auto key = String::Parse(input_, state_.is_string_huff_compressed,
857 state_.string_length);
858 switch (key.status) {
859 case HpackParseStatus::kOk:
860 break;
861 case HpackParseStatus::kEof:
862 DCHECK(input_->eof_error());
863 return false;
864 default:
865 input_->SetErrorAndStopParsing(
866 HpackParseResult::FromStatus(key.status));
867 return false;
868 }
869 input_->UpdateFrontier();
870 state_.parse_state = ParseState::kParsingValueLength;
871 state_.is_binary_header = absl::EndsWith(key.value.string_view(), "-bin");
872 state_.key.emplace<Slice>(key.value.Take());
873 return ParseValueLength();
874 }
875
SkipStringBody()876 bool SkipStringBody() {
877 auto remaining = input_->remaining();
878 if (remaining >= state_.string_length) {
879 input_->Advance(state_.string_length);
880 return true;
881 } else {
882 input_->Advance(remaining);
883 input_->UpdateFrontier();
884 state_.string_length -= remaining;
885 // The default action of our outer loop is to buffer up to
886 // min_progress_size bytes.
887 // We know we need to do nothing up to the string length, so it would be
888 // legal to pass that here - however that would cause a client selected
889 // large buffer size to be accumulated, which would be an attack vector.
890 // We could also pass 1 here, and we'd be called to parse potentially
891 // every byte, which would give clients a way to consume substantial CPU -
892 // again not great.
893 // So we pick some tradeoff number - big enough to amortize wakeups, but
894 // probably not big enough to cause excessive memory use on the receiver.
895 input_->UnexpectedEOF(
896 /*min_progress_size=*/std::min(state_.string_length, 1024u));
897 return false;
898 }
899 }
900
SkipKeyBody()901 bool SkipKeyBody() {
902 DCHECK(state_.parse_state == ParseState::kSkippingKeyBody);
903 if (!SkipStringBody()) return false;
904 input_->UpdateFrontier();
905 state_.parse_state = ParseState::kSkippingValueLength;
906 return SkipValueLength();
907 }
908
SkipValueLength()909 bool SkipValueLength() {
910 DCHECK(state_.parse_state == ParseState::kSkippingValueLength);
911 auto pfx = input_->ParseStringPrefix();
912 if (!pfx.has_value()) return false;
913 state_.string_length = pfx->length;
914 input_->UpdateFrontier();
915 state_.parse_state = ParseState::kSkippingValueBody;
916 return SkipValueBody();
917 }
918
SkipValueBody()919 bool SkipValueBody() {
920 DCHECK(state_.parse_state == ParseState::kSkippingValueBody);
921 if (!SkipStringBody()) return false;
922 input_->UpdateFrontier();
923 state_.parse_state = ParseState::kTop;
924 if (state_.add_to_table) {
925 state_.hpack_table.AddLargerThanCurrentTableSize();
926 }
927 return true;
928 }
929
ParseValueLength()930 bool ParseValueLength() {
931 DCHECK(state_.parse_state == ParseState::kParsingValueLength);
932 auto pfx = input_->ParseStringPrefix();
933 if (!pfx.has_value()) return false;
934 state_.is_string_huff_compressed = pfx->huff;
935 state_.string_length = pfx->length;
936 input_->UpdateFrontier();
937 if (ShouldSkipParsingString(state_.string_length)) {
938 input_->SetErrorAndContinueParsing(
939 HpackParseResult::HardMetadataLimitExceededByValueError(
940 Match(
941 state_.key, [](const Slice& s) { return s.as_string_view(); },
942 [](const HPackTable::Memento* m) { return m->md.key(); }),
943 state_.string_length,
944 state_.metadata_early_detection.hard_limit()));
945 metadata_buffer_ = nullptr;
946 state_.parse_state = ParseState::kSkippingValueBody;
947 return SkipValueBody();
948 } else {
949 state_.parse_state = ParseState::kParsingValueBody;
950 return ParseValueBody();
951 }
952 }
953
ParseValueBody()954 bool ParseValueBody() {
955 DCHECK(state_.parse_state == ParseState::kParsingValueBody);
956 auto value =
957 state_.is_binary_header
958 ? String::ParseBinary(input_, state_.is_string_huff_compressed,
959 state_.string_length)
960 : String::Parse(input_, state_.is_string_huff_compressed,
961 state_.string_length);
962 absl::string_view key_string;
963 if (auto* s = absl::get_if<Slice>(&state_.key)) {
964 key_string = s->as_string_view();
965 if (state_.field_error.ok()) {
966 auto r = ValidateKey(key_string);
967 if (r != ValidateMetadataResult::kOk) {
968 input_->SetErrorAndContinueParsing(
969 HpackParseResult::InvalidMetadataError(r, key_string));
970 }
971 }
972 } else {
973 const auto* memento = absl::get<const HPackTable::Memento*>(state_.key);
974 key_string = memento->md.key();
975 if (state_.field_error.ok() && memento->parse_status.get() != nullptr) {
976 input_->SetErrorAndContinueParsing(*memento->parse_status);
977 }
978 }
979 switch (value.status) {
980 case HpackParseStatus::kOk:
981 break;
982 case HpackParseStatus::kEof:
983 DCHECK(input_->eof_error());
984 return false;
985 default: {
986 auto result =
987 HpackParseResult::FromStatusWithKey(value.status, key_string);
988 if (result.stream_error()) {
989 input_->SetErrorAndContinueParsing(std::move(result));
990 break;
991 } else {
992 input_->SetErrorAndStopParsing(std::move(result));
993 return false;
994 }
995 }
996 }
997 auto value_slice = value.value.Take();
998 const auto transport_size =
999 key_string.size() + value.wire_size + hpack_constants::kEntryOverhead;
1000 auto md = grpc_metadata_batch::Parse(
1001 key_string, std::move(value_slice), state_.add_to_table, transport_size,
1002 [key_string, this](absl::string_view message, const Slice&) {
1003 if (!state_.field_error.ok()) return;
1004 input_->SetErrorAndContinueParsing(
1005 HpackParseResult::MetadataParseError(key_string));
1006 LOG(ERROR) << "Error parsing '" << key_string
1007 << "' metadata: " << message;
1008 });
1009 HPackTable::Memento memento{
1010 std::move(md), state_.field_error.PersistentStreamErrorOrNullptr()};
1011 input_->UpdateFrontier();
1012 state_.parse_state = ParseState::kTop;
1013 if (state_.add_to_table) {
1014 return FinishHeaderAndAddToTable(std::move(memento));
1015 } else {
1016 FinishHeaderOmitFromTable(memento);
1017 return true;
1018 }
1019 }
1020
ValidateKey(absl::string_view key)1021 ValidateMetadataResult ValidateKey(absl::string_view key) {
1022 if (key == HttpSchemeMetadata::key() || key == HttpMethodMetadata::key() ||
1023 key == HttpAuthorityMetadata::key() || key == HttpPathMetadata::key() ||
1024 key == HttpStatusMetadata::key()) {
1025 return ValidateMetadataResult::kOk;
1026 }
1027 return ValidateHeaderKeyIsLegal(key);
1028 }
1029
1030 // Emit an indexed field
FinishIndexed(absl::optional<uint32_t> index)1031 bool FinishIndexed(absl::optional<uint32_t> index) {
1032 state_.dynamic_table_updates_allowed = 0;
1033 if (!index.has_value()) return false;
1034 const auto* elem = state_.hpack_table.Lookup(*index);
1035 if (GPR_UNLIKELY(elem == nullptr)) {
1036 InvalidHPackIndexError(*index);
1037 return false;
1038 }
1039 FinishHeaderOmitFromTable(*elem);
1040 return true;
1041 }
1042
1043 // finish parsing a max table size change
FinishMaxTableSize(absl::optional<uint32_t> size)1044 bool FinishMaxTableSize(absl::optional<uint32_t> size) {
1045 if (!size.has_value()) return false;
1046 if (state_.dynamic_table_updates_allowed == 0) {
1047 input_->SetErrorAndStopParsing(
1048 HpackParseResult::TooManyDynamicTableSizeChangesError());
1049 return false;
1050 }
1051 state_.dynamic_table_updates_allowed--;
1052 if (!state_.hpack_table.SetCurrentTableSize(*size)) {
1053 input_->SetErrorAndStopParsing(
1054 HpackParseResult::IllegalTableSizeChangeError(
1055 *size, state_.hpack_table.max_bytes()));
1056 return false;
1057 }
1058 return true;
1059 }
1060
1061 // Set an invalid hpack index error if no error has been set. Returns result
1062 // unmodified.
InvalidHPackIndexError(uint32_t index)1063 void InvalidHPackIndexError(uint32_t index) {
1064 input_->SetErrorAndStopParsing(
1065 HpackParseResult::InvalidHpackIndexError(index));
1066 }
1067
1068 Input* const input_;
1069 grpc_metadata_batch*& metadata_buffer_;
1070 InterSliceState& state_;
1071 const LogInfo log_info_;
1072 };
1073
Take()1074 Slice HPackParser::String::Take() {
1075 if (auto* p = absl::get_if<Slice>(&value_)) {
1076 return p->Copy();
1077 } else if (auto* p = absl::get_if<absl::Span<const uint8_t>>(&value_)) {
1078 return Slice::FromCopiedBuffer(*p);
1079 } else if (auto* p = absl::get_if<std::vector<uint8_t>>(&value_)) {
1080 return Slice::FromCopiedBuffer(*p);
1081 }
1082 GPR_UNREACHABLE_CODE(return Slice());
1083 }
1084
1085 // PUBLIC INTERFACE
1086
1087 HPackParser::HPackParser() = default;
1088
1089 HPackParser::~HPackParser() = default;
1090
BeginFrame(grpc_metadata_batch * metadata_buffer,uint32_t metadata_size_soft_limit,uint32_t metadata_size_hard_limit,Boundary boundary,Priority priority,LogInfo log_info)1091 void HPackParser::BeginFrame(grpc_metadata_batch* metadata_buffer,
1092 uint32_t metadata_size_soft_limit,
1093 uint32_t metadata_size_hard_limit,
1094 Boundary boundary, Priority priority,
1095 LogInfo log_info) {
1096 metadata_buffer_ = metadata_buffer;
1097 if (metadata_buffer != nullptr) {
1098 metadata_buffer->Set(GrpcStatusFromWire(), true);
1099 }
1100 boundary_ = boundary;
1101 priority_ = priority;
1102 state_.dynamic_table_updates_allowed = 2;
1103 state_.metadata_early_detection.SetLimits(
1104 /*soft_limit=*/metadata_size_soft_limit,
1105 /*hard_limit=*/metadata_size_hard_limit);
1106 log_info_ = log_info;
1107 }
1108
Parse(const grpc_slice & slice,bool is_last,absl::BitGenRef bitsrc,CallTracerAnnotationInterface * call_tracer)1109 grpc_error_handle HPackParser::Parse(
1110 const grpc_slice& slice, bool is_last, absl::BitGenRef bitsrc,
1111 CallTracerAnnotationInterface* call_tracer) {
1112 if (GPR_UNLIKELY(!unparsed_bytes_.empty())) {
1113 unparsed_bytes_.insert(unparsed_bytes_.end(), GRPC_SLICE_START_PTR(slice),
1114 GRPC_SLICE_END_PTR(slice));
1115 if (!(is_last && is_boundary()) &&
1116 unparsed_bytes_.size() < min_progress_size_) {
1117 // We wouldn't make progress anyway, skip out.
1118 return absl::OkStatus();
1119 }
1120 std::vector<uint8_t> buffer = std::move(unparsed_bytes_);
1121 return ParseInput(
1122 Input(nullptr, buffer.data(), buffer.data() + buffer.size(), bitsrc,
1123 state_.frame_error, state_.field_error),
1124 is_last, call_tracer);
1125 }
1126 return ParseInput(Input(slice.refcount, GRPC_SLICE_START_PTR(slice),
1127 GRPC_SLICE_END_PTR(slice), bitsrc, state_.frame_error,
1128 state_.field_error),
1129 is_last, call_tracer);
1130 }
1131
ParseInput(Input input,bool is_last,CallTracerAnnotationInterface * call_tracer)1132 grpc_error_handle HPackParser::ParseInput(
1133 Input input, bool is_last, CallTracerAnnotationInterface* call_tracer) {
1134 ParseInputInner(&input);
1135 if (is_last && is_boundary()) {
1136 if (state_.metadata_early_detection.Reject(state_.frame_length,
1137 input.bitsrc())) {
1138 HandleMetadataSoftSizeLimitExceeded(&input);
1139 }
1140 global_stats().IncrementHttp2MetadataSize(state_.frame_length);
1141 if (call_tracer != nullptr && metadata_buffer_ != nullptr) {
1142 MetadataSizesAnnotation metadata_sizes_annotation(
1143 metadata_buffer_, state_.metadata_early_detection.soft_limit(),
1144 state_.metadata_early_detection.hard_limit());
1145 call_tracer->RecordAnnotation(metadata_sizes_annotation);
1146 }
1147 if (!state_.frame_error.connection_error() &&
1148 (input.eof_error() || state_.parse_state != ParseState::kTop)) {
1149 state_.frame_error = HpackParseResult::IncompleteHeaderAtBoundaryError();
1150 }
1151 state_.frame_length = 0;
1152 return std::exchange(state_.frame_error, HpackParseResult()).Materialize();
1153 } else {
1154 if (input.eof_error() && !state_.frame_error.connection_error()) {
1155 unparsed_bytes_ = std::vector<uint8_t>(input.frontier(), input.end_ptr());
1156 min_progress_size_ = input.min_progress_size();
1157 }
1158 return state_.frame_error.Materialize();
1159 }
1160 }
1161
ParseInputInner(Input * input)1162 void HPackParser::ParseInputInner(Input* input) {
1163 switch (priority_) {
1164 case Priority::None:
1165 break;
1166 case Priority::Included: {
1167 if (input->remaining() < 5) {
1168 input->UnexpectedEOF(/*min_progress_size=*/5);
1169 return;
1170 }
1171 input->Advance(5);
1172 input->UpdateFrontier();
1173 priority_ = Priority::None;
1174 }
1175 }
1176 while (!input->end_of_stream()) {
1177 if (GPR_UNLIKELY(
1178 !Parser(input, metadata_buffer_, state_, log_info_).Parse())) {
1179 return;
1180 }
1181 input->UpdateFrontier();
1182 }
1183 }
1184
FinishFrame()1185 void HPackParser::FinishFrame() { metadata_buffer_ = nullptr; }
1186
HandleMetadataSoftSizeLimitExceeded(Input * input)1187 void HPackParser::HandleMetadataSoftSizeLimitExceeded(Input* input) {
1188 input->SetErrorAndContinueParsing(
1189 HpackParseResult::SoftMetadataLimitExceededError(
1190 std::exchange(metadata_buffer_, nullptr), state_.frame_length,
1191 state_.metadata_early_detection.soft_limit()));
1192 }
1193
1194 } // namespace grpc_core
1195