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