grpc 1.56.0.pre3 → 1.56.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +4 -2
  3. data/include/grpc/grpc_security.h +19 -0
  4. data/src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.cc +1 -1
  5. data/src/core/ext/filters/client_channel/lb_policy/weighted_round_robin/weighted_round_robin.cc +10 -1
  6. data/src/core/ext/transport/chttp2/transport/hpack_parse_result.cc +176 -0
  7. data/src/core/ext/transport/chttp2/transport/hpack_parse_result.h +325 -0
  8. data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +567 -543
  9. data/src/core/ext/transport/chttp2/transport/hpack_parser.h +150 -9
  10. data/src/core/ext/transport/chttp2/transport/hpack_parser_table.cc +46 -32
  11. data/src/core/ext/transport/chttp2/transport/hpack_parser_table.h +18 -5
  12. data/src/core/ext/transport/chttp2/transport/parsing.cc +12 -12
  13. data/src/core/lib/backoff/random_early_detection.h +5 -0
  14. data/src/core/lib/event_engine/posix_engine/posix_engine.h +1 -0
  15. data/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc +29 -0
  16. data/src/core/lib/event_engine/posix_engine/posix_engine_listener.h +3 -0
  17. data/src/core/lib/iomgr/tcp_server_posix.cc +34 -12
  18. data/src/core/lib/iomgr/tcp_server_utils_posix.h +12 -0
  19. data/src/core/lib/iomgr/tcp_server_utils_posix_common.cc +21 -0
  20. data/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc +8 -0
  21. data/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h +5 -1
  22. data/src/core/lib/security/security_connector/ssl_utils.cc +2 -1
  23. data/src/core/lib/security/security_connector/ssl_utils.h +1 -1
  24. data/src/core/lib/security/security_connector/tls/tls_security_connector.cc +1 -1
  25. data/src/core/lib/surface/validate_metadata.cc +37 -22
  26. data/src/core/lib/surface/validate_metadata.h +13 -3
  27. data/src/core/tsi/ssl_transport_security.cc +5 -2
  28. data/src/core/tsi/ssl_transport_security.h +13 -1
  29. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +2 -0
  30. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +3 -0
  31. data/src/ruby/lib/grpc/version.rb +1 -1
  32. metadata +7 -5
@@ -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