• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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