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