grpc 1.55.0 → 1.55.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,7 +24,6 @@
24
24
  #include <stdlib.h>
25
25
 
26
26
  #include <algorithm>
27
- #include <initializer_list>
28
27
  #include <string>
29
28
  #include <utility>
30
29
 
@@ -32,21 +31,22 @@
32
31
  #include "absl/status/status.h"
33
32
  #include "absl/strings/match.h"
34
33
  #include "absl/strings/str_cat.h"
35
- #include "absl/strings/str_format.h"
36
34
  #include "absl/strings/string_view.h"
37
35
  #include "absl/types/optional.h"
38
36
  #include "absl/types/span.h"
39
37
  #include "absl/types/variant.h"
40
38
 
39
+ #include <grpc/slice.h>
41
40
  #include <grpc/support/log.h>
42
41
 
43
42
  #include "src/core/ext/transport/chttp2/transport/decode_huff.h"
44
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"
45
46
  #include "src/core/lib/debug/stats.h"
46
47
  #include "src/core/lib/debug/stats_data.h"
47
48
  #include "src/core/lib/debug/trace.h"
48
- #include "src/core/lib/gprpp/crash.h"
49
- #include "src/core/lib/gprpp/status_helper.h"
49
+ #include "src/core/lib/gprpp/match.h"
50
50
  #include "src/core/lib/slice/slice.h"
51
51
  #include "src/core/lib/slice/slice_refcount.h"
52
52
  #include "src/core/lib/surface/validate_metadata.h"
@@ -82,39 +82,6 @@ struct Base64InverseTable {
82
82
 
83
83
  constexpr Base64InverseTable kBase64InverseTable;
84
84
 
85
- absl::Status EnsureStreamError(absl::Status error) {
86
- if (error.ok()) return error;
87
- return grpc_error_set_int(std::move(error), StatusIntProperty::kStreamId, 0);
88
- }
89
-
90
- bool IsStreamError(const absl::Status& status) {
91
- intptr_t stream_id;
92
- return grpc_error_get_int(status, StatusIntProperty::kStreamId, &stream_id);
93
- }
94
-
95
- class MetadataSizeLimitExceededEncoder {
96
- public:
97
- explicit MetadataSizeLimitExceededEncoder(std::string& summary)
98
- : summary_(summary) {}
99
-
100
- void Encode(const Slice& key, const Slice& value) {
101
- AddToSummary(key.as_string_view(), value.size());
102
- }
103
-
104
- template <typename Key, typename Value>
105
- void Encode(Key, const Value& value) {
106
- AddToSummary(Key::key(), EncodedSizeOfKey(Key(), value));
107
- }
108
-
109
- private:
110
- void AddToSummary(absl::string_view key,
111
- size_t value_length) GPR_ATTRIBUTE_NOINLINE {
112
- absl::StrAppend(&summary_, " ", key, ":",
113
- hpack_constants::SizeForEntry(key.size(), value_length),
114
- "B");
115
- }
116
- std::string& summary_;
117
- };
118
85
  } // namespace
119
86
 
120
87
  // Input tracks the current byte through the input data and provides it
@@ -122,11 +89,12 @@ class MetadataSizeLimitExceededEncoder {
122
89
  class HPackParser::Input {
123
90
  public:
124
91
  Input(grpc_slice_refcount* current_slice_refcount, const uint8_t* begin,
125
- const uint8_t* end)
92
+ const uint8_t* end, HpackParseResult& error)
126
93
  : current_slice_refcount_(current_slice_refcount),
127
94
  begin_(begin),
128
95
  end_(end),
129
- frontier_(begin) {}
96
+ frontier_(begin),
97
+ error_(error) {}
130
98
 
131
99
  // If input is backed by a slice, retrieve its refcount. If not, return
132
100
  // nullptr.
@@ -156,7 +124,7 @@ class HPackParser::Input {
156
124
  // of stream
157
125
  absl::optional<uint8_t> Next() {
158
126
  if (end_of_stream()) {
159
- UnexpectedEOF();
127
+ UnexpectedEOF(/*min_progress_size=*/1);
160
128
  return absl::optional<uint8_t>();
161
129
  }
162
130
  return *begin_++;
@@ -202,9 +170,16 @@ class HPackParser::Input {
202
170
 
203
171
  // Spec weirdness: we can add an infinite stream of 0x80 at the end of a
204
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;
205
176
  do {
206
177
  cur = Next();
207
178
  if (!cur.has_value()) return {};
179
+ ++num_redundant_0x80;
180
+ if (num_redundant_0x80 == 16) {
181
+ return ParseVarintMaliciousEncoding();
182
+ }
208
183
  } while (*cur == 0x80);
209
184
 
210
185
  // BUT... the last byte needs to be 0x00 or we'll overflow dramatically!
@@ -212,14 +187,6 @@ class HPackParser::Input {
212
187
  return ParseVarintOutOfRange(value, *cur);
213
188
  }
214
189
 
215
- // Prefix for a string
216
- struct StringPrefix {
217
- // Number of bytes in input for string
218
- uint32_t length;
219
- // Is it huffman compressed
220
- bool huff;
221
- };
222
-
223
190
  // Parse a string prefix
224
191
  absl::optional<StringPrefix> ParseStringPrefix() {
225
192
  auto cur = Next();
@@ -243,17 +210,13 @@ class HPackParser::Input {
243
210
  return StringPrefix{strlen, huff};
244
211
  }
245
212
 
246
- // Check if we saw an EOF.. must be verified before looking at TakeError
213
+ // Check if we saw an EOF
247
214
  bool eof_error() const {
248
- return eof_error_ || (!error_.ok() && !IsStreamError(error_));
215
+ return min_progress_size_ != 0 || error_.connection_error();
249
216
  }
250
217
 
251
- // Extract the parse error, leaving the current error as NONE.
252
- grpc_error_handle TakeError() {
253
- grpc_error_handle out = error_;
254
- error_ = absl::OkStatus();
255
- return out;
256
- }
218
+ // Minimum number of bytes to unstuck the current parse
219
+ size_t min_progress_size() const { return min_progress_size_; }
257
220
 
258
221
  bool has_error() const { return !error_.ok(); }
259
222
 
@@ -261,31 +224,55 @@ class HPackParser::Input {
261
224
  // chttp2 does not close the connection.
262
225
  // Intended for errors that are specific to a stream and recoverable.
263
226
  // Callers should ensure that any hpack table updates happen.
264
- GPR_ATTRIBUTE_NOINLINE void SetErrorAndContinueParsing(
265
- grpc_error_handle error) {
266
- GPR_ASSERT(!error.ok());
267
- // StreamId is used as a signal to skip this stream but keep the connection
268
- // alive
269
- SetError(EnsureStreamError(std::move(error)));
227
+ void SetErrorAndContinueParsing(HpackParseResult error) {
228
+ GPR_DEBUG_ASSERT(error.stream_error());
229
+ SetError(std::move(error));
270
230
  }
271
231
 
272
232
  // Set the current error, and skip past remaining bytes.
273
233
  // Intended for unrecoverable errors, with the expectation that they will
274
234
  // close the connection on return to chttp2.
275
- GPR_ATTRIBUTE_NOINLINE void SetErrorAndStopParsing(grpc_error_handle error) {
276
- GPR_ASSERT(!error.ok());
235
+ void SetErrorAndStopParsing(HpackParseResult error) {
236
+ GPR_DEBUG_ASSERT(error.connection_error());
277
237
  SetError(std::move(error));
278
238
  begin_ = end_;
279
239
  }
280
240
 
281
- // Set the error to an unexpected eof
282
- void UnexpectedEOF() {
283
- if (!error_.ok() && !IsStreamError(error_)) return;
284
- eof_error_ = true;
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.
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());
285
254
  }
286
255
 
287
256
  // Update the frontier - signifies we've successfully parsed another element
288
- void UpdateFrontier() { frontier_ = begin_; }
257
+ void UpdateFrontier() {
258
+ GPR_DEBUG_ASSERT(skip_bytes_ == 0);
259
+ frontier_ = begin_;
260
+ }
261
+
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
+ }
289
276
 
290
277
  // Get the frontier - for buffering should we fail due to eof
291
278
  const uint8_t* frontier() const { return frontier_; }
@@ -294,19 +281,23 @@ class HPackParser::Input {
294
281
  // Helper to set the error to out of range for ParseVarint
295
282
  absl::optional<uint32_t> ParseVarintOutOfRange(uint32_t value,
296
283
  uint8_t last_byte) {
297
- SetErrorAndStopParsing(absl::InternalError(absl::StrFormat(
298
- "integer overflow in hpack integer decoding: have 0x%08x, "
299
- "got byte 0x%02x on byte 5",
300
- value, 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
290
+ absl::optional<uint32_t> ParseVarintMaliciousEncoding() {
291
+ SetErrorAndStopParsing(HpackParseResult::MaliciousVarintEncodingError());
301
292
  return absl::optional<uint32_t>();
302
293
  }
303
294
 
304
295
  // If no error is set, set it to the given error (i.e. first error wins)
305
296
  // Do not use this directly, instead use SetErrorAndContinueParsing or
306
297
  // SetErrorAndStopParsing.
307
- void SetError(grpc_error_handle error) {
308
- if (!error_.ok() || eof_error_) {
309
- if (!IsStreamError(error) && IsStreamError(error_)) {
298
+ void SetError(HpackParseResult error) {
299
+ if (!error_.ok() || min_progress_size_ > 0) {
300
+ if (error.connection_error() && !error_.connection_error()) {
310
301
  error_ = std::move(error); // connection errors dominate
311
302
  }
312
303
  return;
@@ -323,211 +314,156 @@ class HPackParser::Input {
323
314
  // Frontier denotes the first byte past successfully processed input
324
315
  const uint8_t* frontier_;
325
316
  // Current error
326
- grpc_error_handle error_;
327
- // If the error was EOF, we flag it here..
328
- bool eof_error_ = false;
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;
329
325
  };
330
326
 
331
- // Helper to parse a string and turn it into a slice with appropriate memory
332
- // management characteristics
333
- class HPackParser::String {
334
- public:
335
- // ParseResult carries both a ParseStatus and the parsed string
336
- struct ParseResult;
337
- // Result of parsing a string
338
- enum class ParseStatus {
339
- // Parsed OK
340
- kOk,
341
- // Parse reached end of the current frame
342
- kEof,
343
- // Parse failed due to a huffman decode error
344
- kParseHuffFailed,
345
- // Parse failed due to a base64 decode error
346
- kUnbase64Failed,
347
- };
348
-
349
- String() : value_(absl::Span<const uint8_t>()) {}
350
- String(const String&) = delete;
351
- String& operator=(const String&) = delete;
352
- String(String&& other) noexcept : value_(std::move(other.value_)) {
353
- other.value_ = absl::Span<const uint8_t>();
354
- }
355
- String& operator=(String&& other) noexcept {
356
- value_ = std::move(other.value_);
357
- other.value_ = absl::Span<const uint8_t>();
358
- return *this;
327
+ 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());
359
336
  }
337
+ GPR_UNREACHABLE_CODE(return absl::string_view());
338
+ }
360
339
 
361
- // Take the value and leave this empty
362
- Slice Take();
363
-
364
- // Return a reference to the value as a string view
365
- absl::string_view string_view() const {
366
- if (auto* p = absl::get_if<Slice>(&value_)) {
367
- return p->as_string_view();
368
- } else if (auto* p = absl::get_if<absl::Span<const uint8_t>>(&value_)) {
369
- return absl::string_view(reinterpret_cast<const char*>(p->data()),
370
- p->size());
371
- } else if (auto* p = absl::get_if<std::vector<uint8_t>>(&value_)) {
372
- return absl::string_view(reinterpret_cast<const char*>(p->data()),
373
- p->size());
374
- }
375
- GPR_UNREACHABLE_CODE(return absl::string_view());
340
+ template <typename Out>
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;
376
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
+ }
377
355
 
378
- // Parse a non-binary string
379
- static ParseResult Parse(Input* input);
356
+ struct HPackParser::String::StringResult {
357
+ StringResult() = delete;
358
+ 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
+ };
380
364
 
381
- // Parse a binary string
382
- static ParseResult ParseBinary(Input* input);
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
+ }
383
384
 
384
- private:
385
- void AppendBytes(const uint8_t* data, size_t length);
386
- explicit String(std::vector<uint8_t> v) : value_(std::move(v)) {}
387
- explicit String(absl::Span<const uint8_t> v) : value_(v) {}
388
- String(grpc_slice_refcount* r, const uint8_t* begin, const uint8_t* end)
389
- : value_(Slice::FromRefcountAndBytes(r, begin, end)) {}
390
-
391
- // Parse some huffman encoded bytes, using output(uint8_t b) to emit each
392
- // decoded byte.
393
- template <typename Out>
394
- static ParseStatus ParseHuff(Input* input, uint32_t length, Out output) {
395
- // If there's insufficient bytes remaining, return now.
396
- if (input->remaining() < length) {
397
- input->UnexpectedEOF();
398
- GPR_DEBUG_ASSERT(input->eof_error());
399
- return ParseStatus::kEof;
400
- }
401
- // Grab the byte range, and iterate through it.
402
- const uint8_t* p = input->cur_ptr();
403
- input->Advance(length);
404
- return HuffDecoder<Out>(output, p, p + length).Run()
405
- ? ParseStatus::kOk
406
- : ParseStatus::kParseHuffFailed;
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;
407
389
  }
408
390
 
409
- // Parse some uncompressed string bytes.
410
- static ParseResult ParseUncompressed(Input* input, uint32_t length,
411
- uint32_t wire_size);
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;
412
430
 
413
- // Turn base64 encoded bytes into not base64 encoded bytes.
414
- static ParseResult Unbase64(String s);
431
+ ++cur;
432
+ bits = kBase64InverseTable.table[*cur];
433
+ if (bits > 63) return {};
434
+ buffer |= bits << 12;
415
435
 
416
- // Main loop for Unbase64
417
- static absl::optional<std::vector<uint8_t>> Unbase64Loop(const uint8_t* cur,
418
- const uint8_t* end) {
419
- while (cur != end && end[-1] == '=') {
420
- --end;
436
+ if (buffer & 0xffff) return {};
437
+ out.push_back(static_cast<uint8_t>(buffer >> 16));
438
+ return out;
421
439
  }
422
-
423
- std::vector<uint8_t> out;
424
- out.reserve(3 * (end - cur) / 4 + 3);
425
-
426
- // Decode 4 bytes at a time while we can
427
- while (end - cur >= 4) {
440
+ case 3: {
428
441
  uint32_t bits = kBase64InverseTable.table[*cur];
429
442
  if (bits > 63) return {};
430
443
  uint32_t buffer = bits << 18;
431
- ++cur;
432
444
 
445
+ ++cur;
433
446
  bits = kBase64InverseTable.table[*cur];
434
447
  if (bits > 63) return {};
435
448
  buffer |= bits << 12;
436
- ++cur;
437
449
 
450
+ ++cur;
438
451
  bits = kBase64InverseTable.table[*cur];
439
452
  if (bits > 63) return {};
440
453
  buffer |= bits << 6;
441
- ++cur;
442
454
 
443
- bits = kBase64InverseTable.table[*cur];
444
- if (bits > 63) return {};
445
- buffer |= bits;
446
455
  ++cur;
447
-
448
- out.insert(out.end(), {static_cast<uint8_t>(buffer >> 16),
449
- static_cast<uint8_t>(buffer >> 8),
450
- static_cast<uint8_t>(buffer)});
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;
451
460
  }
452
- // Deal with the last 0, 1, 2, or 3 bytes.
453
- switch (end - cur) {
454
- case 0:
455
- return out;
456
- case 1:
457
- return {};
458
- case 2: {
459
- uint32_t bits = kBase64InverseTable.table[*cur];
460
- if (bits > 63) return {};
461
- uint32_t buffer = bits << 18;
462
-
463
- ++cur;
464
- bits = kBase64InverseTable.table[*cur];
465
- if (bits > 63) return {};
466
- buffer |= bits << 12;
467
-
468
- if (buffer & 0xffff) return {};
469
- out.push_back(static_cast<uint8_t>(buffer >> 16));
470
- return out;
471
- }
472
- case 3: {
473
- uint32_t bits = kBase64InverseTable.table[*cur];
474
- if (bits > 63) return {};
475
- uint32_t buffer = bits << 18;
476
-
477
- ++cur;
478
- bits = kBase64InverseTable.table[*cur];
479
- if (bits > 63) return {};
480
- buffer |= bits << 12;
481
-
482
- ++cur;
483
- bits = kBase64InverseTable.table[*cur];
484
- if (bits > 63) return {};
485
- buffer |= bits << 6;
486
-
487
- ++cur;
488
- if (buffer & 0xff) return {};
489
- out.push_back(static_cast<uint8_t>(buffer >> 16));
490
- out.push_back(static_cast<uint8_t>(buffer >> 8));
491
- return out;
492
- }
493
- }
494
-
495
- GPR_UNREACHABLE_CODE(return out;);
496
461
  }
497
462
 
498
- absl::variant<Slice, absl::Span<const uint8_t>, std::vector<uint8_t>> value_;
499
- };
500
-
501
- struct HPackParser::String::ParseResult {
502
- ParseResult() = delete;
503
- ParseResult(ParseStatus status, size_t wire_size, String value)
504
- : status(status), wire_size(wire_size), value(std::move(value)) {}
505
- ParseStatus status;
506
- size_t wire_size;
507
- String value;
508
- };
509
-
510
- HPackParser::String::ParseResult HPackParser::String::ParseUncompressed(
511
- Input* input, uint32_t length, uint32_t wire_size) {
512
- // Check there's enough bytes
513
- if (input->remaining() < length) {
514
- input->UnexpectedEOF();
515
- GPR_DEBUG_ASSERT(input->eof_error());
516
- return ParseResult{ParseStatus::kEof, wire_size, String{}};
517
- }
518
- auto* refcount = input->slice_refcount();
519
- auto* p = input->cur_ptr();
520
- input->Advance(length);
521
- if (refcount != nullptr) {
522
- return ParseResult{ParseStatus::kOk, wire_size,
523
- String(refcount, p, p + length)};
524
- } else {
525
- return ParseResult{ParseStatus::kOk, wire_size,
526
- String(absl::Span<const uint8_t>(p, length))};
527
- }
463
+ GPR_UNREACHABLE_CODE(return out;);
528
464
  }
529
465
 
530
- HPackParser::String::ParseResult HPackParser::String::Unbase64(String s) {
466
+ HPackParser::String::StringResult HPackParser::String::Unbase64(String s) {
531
467
  absl::optional<std::vector<uint8_t>> result;
532
468
  if (auto* p = absl::get_if<Slice>(&s.value_)) {
533
469
  result = Unbase64Loop(p->begin(), p->end());
@@ -539,46 +475,38 @@ HPackParser::String::ParseResult HPackParser::String::Unbase64(String s) {
539
475
  result = Unbase64Loop(p->data(), p->data() + p->size());
540
476
  }
541
477
  if (!result.has_value()) {
542
- return ParseResult{ParseStatus::kUnbase64Failed, s.string_view().length(),
543
- String{}};
478
+ return StringResult{HpackParseStatus::kUnbase64Failed,
479
+ s.string_view().length(), String{}};
544
480
  }
545
- return ParseResult{ParseStatus::kOk, s.string_view().length(),
546
- String(std::move(*result))};
481
+ return StringResult{HpackParseStatus::kOk, s.string_view().length(),
482
+ String(std::move(*result))};
547
483
  }
548
484
 
549
- HPackParser::String::ParseResult HPackParser::String::Parse(Input* input) {
550
- auto pfx = input->ParseStringPrefix();
551
- if (!pfx.has_value()) {
552
- GPR_DEBUG_ASSERT(input->eof_error());
553
- return ParseResult{ParseStatus::kEof, 0, String{}};
554
- }
555
- if (pfx->huff) {
485
+ HPackParser::String::StringResult HPackParser::String::Parse(Input* input,
486
+ bool is_huff,
487
+ size_t length) {
488
+ if (is_huff) {
556
489
  // Huffman coded
557
490
  std::vector<uint8_t> output;
558
- ParseStatus sts = ParseHuff(input, pfx->length,
559
- [&output](uint8_t c) { output.push_back(c); });
491
+ HpackParseStatus sts =
492
+ ParseHuff(input, length, [&output](uint8_t c) { output.push_back(c); });
560
493
  size_t wire_len = output.size();
561
- return ParseResult{sts, wire_len, String(std::move(output))};
494
+ return StringResult{sts, wire_len, String(std::move(output))};
562
495
  }
563
- return ParseUncompressed(input, pfx->length, pfx->length);
496
+ return ParseUncompressed(input, length, length);
564
497
  }
565
498
 
566
- HPackParser::String::ParseResult HPackParser::String::ParseBinary(
567
- Input* input) {
568
- auto pfx = input->ParseStringPrefix();
569
- if (!pfx.has_value()) {
570
- GPR_DEBUG_ASSERT(input->eof_error());
571
- return ParseResult{ParseStatus::kEof, 0, String{}};
572
- }
573
- if (!pfx->huff) {
574
- if (pfx->length > 0 && input->peek() == 0) {
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) {
575
503
  // 'true-binary'
576
504
  input->Advance(1);
577
- return ParseUncompressed(input, pfx->length - 1, pfx->length);
505
+ return ParseUncompressed(input, length - 1, length);
578
506
  }
579
507
  // Base64 encoded... pull out the string, then unbase64 it
580
- auto base64 = ParseUncompressed(input, pfx->length, pfx->length);
581
- if (base64.status != ParseStatus::kOk) return base64;
508
+ auto base64 = ParseUncompressed(input, length, length);
509
+ if (base64.status != HpackParseStatus::kOk) return base64;
582
510
  return Unbase64(std::move(base64.value));
583
511
  } else {
584
512
  // Huffman encoded...
@@ -587,36 +515,35 @@ HPackParser::String::ParseResult HPackParser::String::ParseBinary(
587
515
  // and what is it.
588
516
  enum class State { kUnsure, kBinary, kBase64 };
589
517
  State state = State::kUnsure;
590
- auto sts =
591
- ParseHuff(input, pfx->length, [&state, &decompressed](uint8_t c) {
592
- if (state == State::kUnsure) {
593
- // First byte... if it's zero it's binary
594
- if (c == 0) {
595
- // Save the type, and skip the zero
596
- state = State::kBinary;
597
- return;
598
- } else {
599
- // Flag base64, store this value
600
- state = State::kBase64;
601
- }
602
- }
603
- // Non-first byte, or base64 first byte
604
- decompressed.push_back(c);
605
- });
606
- if (sts != ParseStatus::kOk) {
607
- return ParseResult{sts, 0, String{}};
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{}};
608
535
  }
609
536
  switch (state) {
610
537
  case State::kUnsure:
611
538
  // No bytes, empty span
612
- return ParseResult{ParseStatus::kOk, 0,
613
- String(absl::Span<const uint8_t>())};
539
+ return StringResult{HpackParseStatus::kOk, 0,
540
+ String(absl::Span<const uint8_t>())};
614
541
  case State::kBinary:
615
542
  // Binary, we're done
616
543
  {
617
544
  size_t wire_len = decompressed.size();
618
- return ParseResult{ParseStatus::kOk, wire_len,
619
- String(std::move(decompressed))};
545
+ return StringResult{HpackParseStatus::kOk, wire_len,
546
+ String(std::move(decompressed))};
620
547
  }
621
548
  case State::kBase64:
622
549
  // Base64 - unpack it
@@ -629,28 +556,38 @@ HPackParser::String::ParseResult HPackParser::String::ParseBinary(
629
556
  // Parser parses one key/value pair from a byte stream.
630
557
  class HPackParser::Parser {
631
558
  public:
632
- Parser(Input* input, grpc_metadata_batch* metadata_buffer, HPackTable* table,
633
- uint8_t* dynamic_table_updates_allowed, uint32_t* frame_length,
634
- RandomEarlyDetection* metadata_early_detection, LogInfo log_info)
559
+ Parser(Input* input, grpc_metadata_batch*& metadata_buffer,
560
+ InterSliceState& state, LogInfo log_info)
635
561
  : input_(input),
636
562
  metadata_buffer_(metadata_buffer),
637
- table_(table),
638
- dynamic_table_updates_allowed_(dynamic_table_updates_allowed),
639
- frame_length_(frame_length),
640
- metadata_early_detection_(metadata_early_detection),
563
+ state_(state),
641
564
  log_info_(log_info) {}
642
565
 
643
- // Skip any priority bits, or return false on failure
644
- bool SkipPriority() {
645
- if (input_->remaining() < 5) {
646
- input_->UnexpectedEOF();
647
- return false;
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();
648
584
  }
649
- input_->Advance(5);
650
- return true;
585
+ GPR_UNREACHABLE_CODE(return false);
651
586
  }
652
587
 
653
- bool Parse() {
588
+ private:
589
+ bool ParseTop() {
590
+ GPR_DEBUG_ASSERT(state_.parse_state == ParseState::kTop);
654
591
  auto cur = *input_->Next();
655
592
  switch (cur >> 4) {
656
593
  // Literal header not indexed - First byte format: 0000xxxx
@@ -663,11 +600,11 @@ class HPackParser::Parser {
663
600
  case 1:
664
601
  switch (cur & 0xf) {
665
602
  case 0: // literal key
666
- return FinishHeaderOmitFromTable(ParseLiteralKey());
603
+ return StartParseLiteralKey(false);
667
604
  case 0xf: // varint encoded key index
668
- return FinishHeaderOmitFromTable(ParseVarIdxKey(0xf));
605
+ return StartVarIdxKey(0xf, false);
669
606
  default: // inline encoded key index
670
- return FinishHeaderOmitFromTable(ParseIdxKey(cur & 0xf));
607
+ return StartIdxKey(cur & 0xf, false);
671
608
  }
672
609
  // Update max table size.
673
610
  // First byte format: 001xxxxx
@@ -694,20 +631,20 @@ class HPackParser::Parser {
694
631
  case 4:
695
632
  if (cur == 0x40) {
696
633
  // literal key
697
- return FinishHeaderAndAddToTable(ParseLiteralKey());
634
+ return StartParseLiteralKey(true);
698
635
  }
699
636
  ABSL_FALLTHROUGH_INTENDED;
700
637
  case 5:
701
638
  case 6:
702
639
  // inline encoded key index
703
- return FinishHeaderAndAddToTable(ParseIdxKey(cur & 0x3f));
640
+ return StartIdxKey(cur & 0x3f, true);
704
641
  case 7:
705
642
  if (cur == 0x7f) {
706
643
  // varint encoded key index
707
- return FinishHeaderAndAddToTable(ParseVarIdxKey(0x3f));
644
+ return StartVarIdxKey(0x3f, true);
708
645
  } else {
709
646
  // inline encoded key index
710
- return FinishHeaderAndAddToTable(ParseIdxKey(cur & 0x3f));
647
+ return StartIdxKey(cur & 0x3f, true);
711
648
  }
712
649
  // Indexed Header Field Representation
713
650
  // First byte format: 1xxxxxxx
@@ -719,7 +656,7 @@ class HPackParser::Parser {
719
656
  if (cur == 0x80) {
720
657
  // illegal value.
721
658
  input_->SetErrorAndStopParsing(
722
- absl::InternalError("Illegal hpack op code"));
659
+ HpackParseResult::IllegalHpackOpCode());
723
660
  return false;
724
661
  }
725
662
  ABSL_FALLTHROUGH_INTENDED;
@@ -743,7 +680,6 @@ class HPackParser::Parser {
743
680
  GPR_UNREACHABLE_CODE(abort());
744
681
  }
745
682
 
746
- private:
747
683
  void GPR_ATTRIBUTE_NOINLINE LogHeader(const HPackTable::Memento& memento) {
748
684
  const char* type;
749
685
  switch (log_info_.type) {
@@ -757,46 +693,48 @@ class HPackParser::Parser {
757
693
  type = "???";
758
694
  break;
759
695
  }
760
- gpr_log(GPR_DEBUG, "HTTP:%d:%s:%s: %s%s", log_info_.stream_id, type,
761
- log_info_.is_client ? "CLI" : "SVR",
762
- memento.md.DebugString().c_str(),
763
- memento.parse_status.ok()
764
- ? ""
765
- : absl::StrCat(
766
- " (parse error: ", memento.parse_status.ToString(), ")")
767
- .c_str());
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());
768
704
  }
769
705
 
770
706
  void EmitHeader(const HPackTable::Memento& md) {
771
707
  // Pass up to the transport
772
- *frame_length_ += md.md.transport_size();
773
- if (!input_->has_error() &&
774
- metadata_early_detection_->MustReject(*frame_length_)) {
775
- // Reject any requests above hard metadata limit.
776
- HandleMetadataHardSizeLimitExceeded(md);
777
- }
708
+ state_.frame_length += md.md.transport_size();
778
709
  if (!md.parse_status.ok()) {
779
710
  // Reject any requests with invalid metadata.
780
- HandleMetadataParseError(md.parse_status);
711
+ input_->SetErrorAndContinueParsing(md.parse_status);
781
712
  }
782
713
  if (GPR_LIKELY(metadata_buffer_ != nullptr)) {
783
714
  metadata_buffer_->Set(md.md);
784
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
+ }
785
723
  }
786
724
 
787
- bool FinishHeaderAndAddToTable(absl::optional<HPackTable::Memento> md) {
788
- // Allow higher code to just pass in failures ... simplifies things a bit.
789
- if (!md.has_value()) return false;
725
+ bool FinishHeaderAndAddToTable(HPackTable::Memento md) {
790
726
  // Log if desired
791
727
  if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_hpack_parser)) {
792
- LogHeader(*md);
728
+ LogHeader(md);
793
729
  }
794
730
  // Emit whilst we own the metadata.
795
- EmitHeader(*md);
731
+ EmitHeader(md);
796
732
  // Add to the hpack table
797
- grpc_error_handle err = table_->Add(std::move(*md));
798
- if (GPR_UNLIKELY(!err.ok())) {
799
- input_->SetErrorAndStopParsing(std::move(err));
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()));
800
738
  return false;
801
739
  };
802
740
  return true;
@@ -817,136 +755,269 @@ class HPackParser::Parser {
817
755
  EmitHeader(md);
818
756
  }
819
757
 
820
- // Helper type to build a memento from a key & value, and to consolidate some
821
- // tricky error path code.
822
- class MementoBuilder {
823
- public:
824
- explicit MementoBuilder(Input* input, absl::string_view key_string,
825
- absl::Status status = absl::OkStatus())
826
- : input_(input), key_string_(key_string), status_(std::move(status)) {}
827
-
828
- auto ErrorHandler() {
829
- return [this](absl::string_view error, const Slice&) {
830
- auto message =
831
- absl::StrCat("Error parsing '", key_string_,
832
- "' metadata: error=", error, " key=", key_string_);
833
- gpr_log(GPR_ERROR, "%s", message.c_str());
834
- if (status_.ok()) {
835
- status_ = absl::InternalError(message);
836
- }
837
- };
758
+ // Parse an index encoded key and a string encoded value
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;
838
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
+ };
839
773
 
840
- HPackTable::Memento Build(ParsedMetadata<grpc_metadata_batch> memento) {
841
- return HPackTable::Memento{std::move(memento), std::move(status_)};
842
- }
774
+ // Parse a varint index encoded key and a string encoded value
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
+ }
843
781
 
844
- // Handle the result of parsing a value.
845
- // Returns true if parsing should continue, false if it should stop.
846
- // Stores an error on the input if necessary.
847
- bool HandleParseResult(String::ParseStatus status) {
848
- auto continuable = [this](absl::string_view error) {
849
- auto this_error = absl::InternalError(absl::StrCat(
850
- "Error parsing '", key_string_, "' metadata: error=", error));
851
- if (status_.ok()) status_ = this_error;
852
- input_->SetErrorAndContinueParsing(std::move(this_error));
853
- };
854
- switch (status) {
855
- case String::ParseStatus::kOk:
856
- return true;
857
- case String::ParseStatus::kParseHuffFailed:
858
- input_->SetErrorAndStopParsing(
859
- absl::InternalError("Huffman decoding failed"));
860
- return false;
861
- case String::ParseStatus::kUnbase64Failed:
862
- continuable("illegal base64 encoding");
863
- return true;
864
- case String::ParseStatus::kEof:
865
- GPR_DEBUG_ASSERT(input_->eof_error());
866
- return false;
867
- }
868
- GPR_UNREACHABLE_CODE(return false);
869
- }
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
+ }
870
789
 
871
- private:
872
- Input* input_;
873
- absl::string_view key_string_;
874
- absl::Status status_;
875
- };
790
+ 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
+
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
+ }
876
837
 
877
- // Parse a string encoded key and a string encoded value
878
- absl::optional<HPackTable::Memento> ParseLiteralKey() {
879
- auto key = String::Parse(input_);
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);
880
842
  switch (key.status) {
881
- case String::ParseStatus::kOk:
843
+ case HpackParseStatus::kOk:
882
844
  break;
883
- case String::ParseStatus::kParseHuffFailed:
884
- input_->SetErrorAndStopParsing(
885
- absl::InternalError("Huffman decoding failed"));
886
- return absl::nullopt;
887
- case String::ParseStatus::kUnbase64Failed:
888
- Crash("unreachable");
889
- case String::ParseStatus::kEof:
845
+ case HpackParseStatus::kEof:
890
846
  GPR_DEBUG_ASSERT(input_->eof_error());
891
- return absl::nullopt;
847
+ return false;
848
+ default:
849
+ input_->SetErrorAndStopParsing(
850
+ HpackParseResult::FromStatus(key.status));
851
+ return false;
892
852
  }
893
- auto key_string = key.value.string_view();
894
- auto value = ParseValueString(absl::EndsWith(key_string, "-bin"));
895
- MementoBuilder builder(input_, key_string,
896
- EnsureStreamError(ValidateKey(key_string)));
897
- if (!builder.HandleParseResult(value.status)) return absl::nullopt;
898
- auto value_slice = value.value.Take();
899
- const auto transport_size =
900
- key_string.size() + value.wire_size + hpack_constants::kEntryOverhead;
901
- return builder.Build(
902
- grpc_metadata_batch::Parse(key_string, std::move(value_slice),
903
- transport_size, builder.ErrorHandler()));
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();
904
858
  }
905
859
 
906
- absl::Status ValidateKey(absl::string_view key) {
907
- if (key == HttpSchemeMetadata::key() || key == HttpMethodMetadata::key() ||
908
- key == HttpAuthorityMetadata::key() || key == HttpPathMetadata::key() ||
909
- key == HttpStatusMetadata::key()) {
910
- return absl::OkStatus();
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;
911
882
  }
912
- return ValidateHeaderKeyIsLegal(key);
913
883
  }
914
884
 
915
- // Parse an index encoded key and a string encoded value
916
- absl::optional<HPackTable::Memento> ParseIdxKey(uint32_t index) {
917
- const auto* elem = table_->Lookup(index);
918
- if (GPR_UNLIKELY(elem == nullptr)) {
919
- InvalidHPackIndexError(index);
920
- return absl::optional<HPackTable::Memento>();
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
+
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
+
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();
921
910
  }
922
- MementoBuilder builder(input_, elem->md.key(), elem->parse_status);
923
- auto value = ParseValueString(elem->md.is_binary_header());
924
- if (!builder.HandleParseResult(value.status)) return absl::nullopt;
925
- return builder.Build(elem->md.WithNewValue(
926
- value.value.Take(), value.wire_size, builder.ErrorHandler()));
927
- };
911
+ return true;
912
+ }
928
913
 
929
- // Parse a varint index encoded key and a string encoded value
930
- absl::optional<HPackTable::Memento> ParseVarIdxKey(uint32_t offset) {
931
- auto index = input_->ParseVarint(offset);
932
- if (GPR_UNLIKELY(!index.has_value())) return absl::nullopt;
933
- return ParseIdxKey(*index);
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
+ }
934
936
  }
935
937
 
936
- // Parse a string, figuring out if it's binary or not by the key name.
937
- String::ParseResult ParseValueString(bool is_binary) {
938
- if (is_binary) {
939
- return String::ParseBinary(input_);
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
+ }
940
957
  } else {
941
- return String::Parse(input_);
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;
942
1004
  }
943
1005
  }
944
1006
 
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
+
945
1016
  // Emit an indexed field
946
1017
  bool FinishIndexed(absl::optional<uint32_t> index) {
947
- *dynamic_table_updates_allowed_ = 0;
1018
+ state_.dynamic_table_updates_allowed = 0;
948
1019
  if (!index.has_value()) return false;
949
- const auto* elem = table_->Lookup(*index);
1020
+ const auto* elem = state_.hpack_table.Lookup(*index);
950
1021
  if (GPR_UNLIKELY(elem == nullptr)) {
951
1022
  InvalidHPackIndexError(*index);
952
1023
  return false;
@@ -958,15 +1029,16 @@ class HPackParser::Parser {
958
1029
  // finish parsing a max table size change
959
1030
  bool FinishMaxTableSize(absl::optional<uint32_t> size) {
960
1031
  if (!size.has_value()) return false;
961
- if (*dynamic_table_updates_allowed_ == 0) {
962
- input_->SetErrorAndStopParsing(absl::InternalError(
963
- "More than two max table size changes in a single frame"));
1032
+ if (state_.dynamic_table_updates_allowed == 0) {
1033
+ input_->SetErrorAndStopParsing(
1034
+ HpackParseResult::TooManyDynamicTableSizeChangesError());
964
1035
  return false;
965
1036
  }
966
- (*dynamic_table_updates_allowed_)--;
967
- grpc_error_handle err = table_->SetCurrentTableSize(*size);
968
- if (!err.ok()) {
969
- input_->SetErrorAndStopParsing(std::move(err));
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()));
970
1042
  return false;
971
1043
  }
972
1044
  return true;
@@ -975,51 +1047,13 @@ class HPackParser::Parser {
975
1047
  // Set an invalid hpack index error if no error has been set. Returns result
976
1048
  // unmodified.
977
1049
  void InvalidHPackIndexError(uint32_t index) {
978
- input_->SetErrorAndStopParsing(grpc_error_set_int(
979
- grpc_error_set_int(absl::InternalError("Invalid HPACK index received"),
980
- StatusIntProperty::kIndex,
981
- static_cast<intptr_t>(index)),
982
- StatusIntProperty::kSize,
983
- static_cast<intptr_t>(this->table_->num_entries())));
984
- }
985
-
986
- GPR_ATTRIBUTE_NOINLINE
987
- void HandleMetadataParseError(const absl::Status& status) {
988
- if (metadata_buffer_ != nullptr) {
989
- metadata_buffer_->Clear();
990
- metadata_buffer_ = nullptr;
991
- }
992
- // StreamId is used as a signal to skip this stream but keep the connection
993
- // alive
994
- input_->SetErrorAndContinueParsing(status);
995
- }
996
-
997
- GPR_ATTRIBUTE_NOINLINE
998
- void HandleMetadataHardSizeLimitExceeded(const HPackTable::Memento& md) {
999
- // Collect a summary of sizes so far for debugging
1000
- // Do not collect contents, for fear of exposing PII.
1001
- std::string summary;
1002
- std::string error_message;
1003
- if (metadata_buffer_ != nullptr) {
1004
- MetadataSizeLimitExceededEncoder encoder(summary);
1005
- metadata_buffer_->Encode(&encoder);
1006
- }
1007
- summary = absl::StrCat("; adding ", md.md.key(), " (length ",
1008
- md.md.transport_size(), "B)",
1009
- summary.empty() ? "" : " to ", summary);
1010
- error_message = absl::StrCat(
1011
- "received metadata size exceeds hard limit (", *frame_length_, " vs. ",
1012
- metadata_early_detection_->hard_limit(), ")", summary);
1013
- HandleMetadataParseError(absl::ResourceExhaustedError(error_message));
1050
+ input_->SetErrorAndStopParsing(
1051
+ HpackParseResult::InvalidHpackIndexError(index));
1014
1052
  }
1015
1053
 
1016
1054
  Input* const input_;
1017
- grpc_metadata_batch* metadata_buffer_;
1018
- HPackTable* const table_;
1019
- uint8_t* const dynamic_table_updates_allowed_;
1020
- uint32_t* const frame_length_;
1021
- // Random early detection of metadata size limits.
1022
- RandomEarlyDetection* metadata_early_detection_;
1055
+ grpc_metadata_batch*& metadata_buffer_;
1056
+ InterSliceState& state_;
1023
1057
  const LogInfo log_info_;
1024
1058
  };
1025
1059
 
@@ -1051,9 +1085,8 @@ void HPackParser::BeginFrame(grpc_metadata_batch* metadata_buffer,
1051
1085
  }
1052
1086
  boundary_ = boundary;
1053
1087
  priority_ = priority;
1054
- dynamic_table_updates_allowed_ = 2;
1055
- frame_length_ = 0;
1056
- metadata_early_detection_ = RandomEarlyDetection(
1088
+ state_.dynamic_table_updates_allowed = 2;
1089
+ state_.metadata_early_detection.SetLimits(
1057
1090
  /*soft_limit=*/metadata_size_soft_limit,
1058
1091
  /*hard_limit=*/metadata_size_hard_limit);
1059
1092
  log_info_ = log_info;
@@ -1061,36 +1094,43 @@ void HPackParser::BeginFrame(grpc_metadata_batch* metadata_buffer,
1061
1094
 
1062
1095
  grpc_error_handle HPackParser::Parse(const grpc_slice& slice, bool is_last) {
1063
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
+ }
1064
1104
  std::vector<uint8_t> buffer = std::move(unparsed_bytes_);
1065
- buffer.insert(buffer.end(), GRPC_SLICE_START_PTR(slice),
1066
- GRPC_SLICE_END_PTR(slice));
1067
- return ParseInput(
1068
- Input(nullptr, buffer.data(), buffer.data() + buffer.size()), is_last);
1105
+ return ParseInput(Input(nullptr, buffer.data(),
1106
+ buffer.data() + buffer.size(), state_.frame_error),
1107
+ is_last);
1069
1108
  }
1070
1109
  return ParseInput(Input(slice.refcount, GRPC_SLICE_START_PTR(slice),
1071
- GRPC_SLICE_END_PTR(slice)),
1110
+ GRPC_SLICE_END_PTR(slice), state_.frame_error),
1072
1111
  is_last);
1073
1112
  }
1074
1113
 
1075
1114
  grpc_error_handle HPackParser::ParseInput(Input input, bool is_last) {
1076
1115
  ParseInputInner(&input);
1077
- if (is_last) {
1078
- if (metadata_early_detection_.Reject(frame_length_)) {
1116
+ if (is_last && is_boundary()) {
1117
+ if (state_.metadata_early_detection.Reject(state_.frame_length)) {
1079
1118
  HandleMetadataSoftSizeLimitExceeded(&input);
1080
1119
  }
1081
- global_stats().IncrementHttp2MetadataSize(frame_length_);
1082
- }
1083
- if (input.eof_error()) {
1084
- if (GPR_UNLIKELY(is_last && is_boundary())) {
1085
- auto err = input.TakeError();
1086
- if (!err.ok() && !IsStreamError(err)) return err;
1087
- return absl::InternalError(
1088
- "Incomplete header at the end of a header/continuation sequence");
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();
1089
1131
  }
1090
- unparsed_bytes_ = std::vector<uint8_t>(input.frontier(), input.end_ptr());
1091
- return input.TakeError();
1132
+ return state_.frame_error.Materialize();
1092
1133
  }
1093
- return input.TakeError();
1094
1134
  }
1095
1135
 
1096
1136
  void HPackParser::ParseInputInner(Input* input) {
@@ -1099,7 +1139,7 @@ void HPackParser::ParseInputInner(Input* input) {
1099
1139
  break;
1100
1140
  case Priority::Included: {
1101
1141
  if (input->remaining() < 5) {
1102
- input->UnexpectedEOF();
1142
+ input->UnexpectedEOF(/*min_progress_size=*/5);
1103
1143
  return;
1104
1144
  }
1105
1145
  input->Advance(5);
@@ -1108,10 +1148,8 @@ void HPackParser::ParseInputInner(Input* input) {
1108
1148
  }
1109
1149
  }
1110
1150
  while (!input->end_of_stream()) {
1111
- if (GPR_UNLIKELY(!Parser(input, metadata_buffer_, &table_,
1112
- &dynamic_table_updates_allowed_, &frame_length_,
1113
- &metadata_early_detection_, log_info_)
1114
- .Parse())) {
1151
+ if (GPR_UNLIKELY(
1152
+ !Parser(input, metadata_buffer_, state_, log_info_).Parse())) {
1115
1153
  return;
1116
1154
  }
1117
1155
  input->UpdateFrontier();
@@ -1121,24 +1159,10 @@ void HPackParser::ParseInputInner(Input* input) {
1121
1159
  void HPackParser::FinishFrame() { metadata_buffer_ = nullptr; }
1122
1160
 
1123
1161
  void HPackParser::HandleMetadataSoftSizeLimitExceeded(Input* input) {
1124
- // Collect a summary of sizes so far for debugging
1125
- // Do not collect contents, for fear of exposing PII.
1126
- std::string summary;
1127
- std::string error_message;
1128
- if (metadata_buffer_ != nullptr) {
1129
- MetadataSizeLimitExceededEncoder encoder(summary);
1130
- metadata_buffer_->Encode(&encoder);
1131
- }
1132
- error_message = absl::StrCat(
1133
- "received metadata size exceeds soft limit (", frame_length_, " vs. ",
1134
- metadata_early_detection_.soft_limit(),
1135
- "), rejecting requests with some random probability", summary);
1136
- if (metadata_buffer_ != nullptr) {
1137
- metadata_buffer_->Clear();
1138
- metadata_buffer_ = nullptr;
1139
- }
1140
1162
  input->SetErrorAndContinueParsing(
1141
- absl::ResourceExhaustedError(error_message));
1163
+ HpackParseResult::SoftMetadataLimitExceededError(
1164
+ std::exchange(metadata_buffer_, nullptr), state_.frame_length,
1165
+ state_.metadata_early_detection.soft_limit()));
1142
1166
  }
1143
1167
 
1144
1168
  } // namespace grpc_core