grpc 1.53.0 → 1.53.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grpc might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Makefile +4 -2
- data/include/grpc/impl/grpc_types.h +11 -2
- data/src/core/ext/filters/client_channel/http_proxy.cc +1 -1
- data/src/core/ext/filters/client_channel/lb_policy/rls/rls.cc +1 -1
- data/src/core/ext/transport/chttp2/transport/bin_encoder.cc +12 -8
- data/src/core/ext/transport/chttp2/transport/bin_encoder.h +5 -1
- data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +33 -2
- data/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +118 -222
- data/src/core/ext/transport/chttp2/transport/hpack_encoder.h +295 -113
- data/src/core/ext/transport/chttp2/transport/hpack_encoder_table.cc +2 -0
- data/src/core/ext/transport/chttp2/transport/hpack_encoder_table.h +2 -0
- data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +466 -273
- data/src/core/ext/transport/chttp2/transport/hpack_parser.h +7 -3
- data/src/core/ext/transport/chttp2/transport/hpack_parser_table.cc +14 -12
- data/src/core/ext/transport/chttp2/transport/hpack_parser_table.h +9 -1
- data/src/core/ext/transport/chttp2/transport/internal.h +2 -0
- data/src/core/ext/transport/chttp2/transport/parsing.cc +6 -0
- data/src/core/lib/backoff/random_early_detection.cc +31 -0
- data/src/core/lib/backoff/random_early_detection.h +59 -0
- data/src/core/lib/iomgr/endpoint_pair.h +2 -2
- data/src/core/lib/iomgr/endpoint_pair_posix.cc +2 -2
- data/src/core/lib/iomgr/endpoint_pair_windows.cc +1 -1
- data/src/core/lib/surface/validate_metadata.cc +43 -42
- data/src/core/lib/surface/validate_metadata.h +9 -0
- data/src/core/lib/transport/metadata_batch.cc +4 -4
- data/src/core/lib/transport/metadata_batch.h +153 -15
- data/src/core/lib/transport/parsed_metadata.h +19 -9
- data/src/ruby/lib/grpc/version.rb +1 -1
- metadata +5 -3
@@ -38,7 +38,6 @@
|
|
38
38
|
#include "absl/types/span.h"
|
39
39
|
#include "absl/types/variant.h"
|
40
40
|
|
41
|
-
#include <grpc/status.h>
|
42
41
|
#include <grpc/support/log.h>
|
43
42
|
|
44
43
|
#include "src/core/ext/transport/chttp2/transport/decode_huff.h"
|
@@ -46,9 +45,11 @@
|
|
46
45
|
#include "src/core/lib/debug/stats.h"
|
47
46
|
#include "src/core/lib/debug/stats_data.h"
|
48
47
|
#include "src/core/lib/debug/trace.h"
|
48
|
+
#include "src/core/lib/gprpp/crash.h"
|
49
49
|
#include "src/core/lib/gprpp/status_helper.h"
|
50
50
|
#include "src/core/lib/slice/slice.h"
|
51
51
|
#include "src/core/lib/slice/slice_refcount.h"
|
52
|
+
#include "src/core/lib/surface/validate_metadata.h"
|
52
53
|
#include "src/core/lib/transport/parsed_metadata.h"
|
53
54
|
|
54
55
|
// IWYU pragma: no_include <type_traits>
|
@@ -80,6 +81,40 @@ struct Base64InverseTable {
|
|
80
81
|
};
|
81
82
|
|
82
83
|
constexpr Base64InverseTable kBase64InverseTable;
|
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
|
+
};
|
83
118
|
} // namespace
|
84
119
|
|
85
120
|
// Input tracks the current byte through the input data and provides it
|
@@ -121,7 +156,8 @@ class HPackParser::Input {
|
|
121
156
|
// of stream
|
122
157
|
absl::optional<uint8_t> Next() {
|
123
158
|
if (end_of_stream()) {
|
124
|
-
|
159
|
+
UnexpectedEOF();
|
160
|
+
return absl::optional<uint8_t>();
|
125
161
|
}
|
126
162
|
return *begin_++;
|
127
163
|
}
|
@@ -187,7 +223,10 @@ class HPackParser::Input {
|
|
187
223
|
// Parse a string prefix
|
188
224
|
absl::optional<StringPrefix> ParseStringPrefix() {
|
189
225
|
auto cur = Next();
|
190
|
-
if (!cur.has_value())
|
226
|
+
if (!cur.has_value()) {
|
227
|
+
GPR_DEBUG_ASSERT(eof_error());
|
228
|
+
return {};
|
229
|
+
}
|
191
230
|
// Huffman if the top bit is 1
|
192
231
|
const bool huff = (*cur & 0x80) != 0;
|
193
232
|
// String length
|
@@ -195,14 +234,19 @@ class HPackParser::Input {
|
|
195
234
|
if (strlen == 0x7f) {
|
196
235
|
// all ones ==> varint string length
|
197
236
|
auto v = ParseVarint(0x7f);
|
198
|
-
if (!v.has_value())
|
237
|
+
if (!v.has_value()) {
|
238
|
+
GPR_DEBUG_ASSERT(eof_error());
|
239
|
+
return {};
|
240
|
+
}
|
199
241
|
strlen = *v;
|
200
242
|
}
|
201
243
|
return StringPrefix{strlen, huff};
|
202
244
|
}
|
203
245
|
|
204
246
|
// Check if we saw an EOF.. must be verified before looking at TakeError
|
205
|
-
bool eof_error() const {
|
247
|
+
bool eof_error() const {
|
248
|
+
return eof_error_ || (!error_.ok() && !IsStreamError(error_));
|
249
|
+
}
|
206
250
|
|
207
251
|
// Extract the parse error, leaving the current error as NONE.
|
208
252
|
grpc_error_handle TakeError() {
|
@@ -211,34 +255,33 @@ class HPackParser::Input {
|
|
211
255
|
return out;
|
212
256
|
}
|
213
257
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
258
|
+
bool has_error() const { return !error_.ok(); }
|
259
|
+
|
260
|
+
// Set the current error - tweaks the error to include a stream id so that
|
261
|
+
// chttp2 does not close the connection.
|
262
|
+
// Intended for errors that are specific to a stream and recoverable.
|
263
|
+
// 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)));
|
222
270
|
}
|
223
271
|
|
224
|
-
//
|
225
|
-
//
|
226
|
-
|
227
|
-
GPR_ATTRIBUTE_NOINLINE
|
228
|
-
|
229
|
-
|
230
|
-
error_ = error_factory();
|
272
|
+
// Set the current error, and skip past remaining bytes.
|
273
|
+
// Intended for unrecoverable errors, with the expectation that they will
|
274
|
+
// close the connection on return to chttp2.
|
275
|
+
GPR_ATTRIBUTE_NOINLINE void SetErrorAndStopParsing(grpc_error_handle error) {
|
276
|
+
GPR_ASSERT(!error.ok());
|
277
|
+
SetError(std::move(error));
|
231
278
|
begin_ = end_;
|
232
|
-
return return_value;
|
233
279
|
}
|
234
280
|
|
235
|
-
// Set the error to an unexpected eof
|
236
|
-
|
237
|
-
|
238
|
-
T UnexpectedEOF(T return_value) {
|
239
|
-
if (!error_.ok()) return return_value;
|
281
|
+
// Set the error to an unexpected eof
|
282
|
+
void UnexpectedEOF() {
|
283
|
+
if (!error_.ok() && !IsStreamError(error_)) return;
|
240
284
|
eof_error_ = true;
|
241
|
-
return return_value;
|
242
285
|
}
|
243
286
|
|
244
287
|
// Update the frontier - signifies we've successfully parsed another element
|
@@ -251,14 +294,24 @@ class HPackParser::Input {
|
|
251
294
|
// Helper to set the error to out of range for ParseVarint
|
252
295
|
absl::optional<uint32_t> ParseVarintOutOfRange(uint32_t value,
|
253
296
|
uint8_t last_byte) {
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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)));
|
301
|
+
return absl::optional<uint32_t>();
|
302
|
+
}
|
303
|
+
|
304
|
+
// If no error is set, set it to the given error (i.e. first error wins)
|
305
|
+
// Do not use this directly, instead use SetErrorAndContinueParsing or
|
306
|
+
// SetErrorAndStopParsing.
|
307
|
+
void SetError(grpc_error_handle error) {
|
308
|
+
if (!error_.ok() || eof_error_) {
|
309
|
+
if (!IsStreamError(error) && IsStreamError(error_)) {
|
310
|
+
error_ = std::move(error); // connection errors dominate
|
311
|
+
}
|
312
|
+
return;
|
313
|
+
}
|
314
|
+
error_ = std::move(error);
|
262
315
|
}
|
263
316
|
|
264
317
|
// Refcount if we are backed by a slice
|
@@ -279,6 +332,21 @@ class HPackParser::Input {
|
|
279
332
|
// management characteristics
|
280
333
|
class HPackParser::String {
|
281
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>()) {}
|
282
350
|
String(const String&) = delete;
|
283
351
|
String& operator=(const String&) = delete;
|
284
352
|
String(String&& other) noexcept : value_(std::move(other.value_)) {
|
@@ -308,72 +376,10 @@ class HPackParser::String {
|
|
308
376
|
}
|
309
377
|
|
310
378
|
// Parse a non-binary string
|
311
|
-
static
|
312
|
-
auto pfx = input->ParseStringPrefix();
|
313
|
-
if (!pfx.has_value()) return {};
|
314
|
-
if (pfx->huff) {
|
315
|
-
// Huffman coded
|
316
|
-
std::vector<uint8_t> output;
|
317
|
-
auto v = ParseHuff(input, pfx->length,
|
318
|
-
[&output](uint8_t c) { output.push_back(c); });
|
319
|
-
if (!v) return {};
|
320
|
-
return String(std::move(output));
|
321
|
-
}
|
322
|
-
return ParseUncompressed(input, pfx->length);
|
323
|
-
}
|
379
|
+
static ParseResult Parse(Input* input);
|
324
380
|
|
325
381
|
// Parse a binary string
|
326
|
-
static
|
327
|
-
auto pfx = input->ParseStringPrefix();
|
328
|
-
if (!pfx.has_value()) return {};
|
329
|
-
if (!pfx->huff) {
|
330
|
-
if (pfx->length > 0 && input->peek() == 0) {
|
331
|
-
// 'true-binary'
|
332
|
-
input->Advance(1);
|
333
|
-
return ParseUncompressed(input, pfx->length - 1);
|
334
|
-
}
|
335
|
-
// Base64 encoded... pull out the string, then unbase64 it
|
336
|
-
auto base64 = ParseUncompressed(input, pfx->length);
|
337
|
-
if (!base64.has_value()) return {};
|
338
|
-
return Unbase64(input, std::move(*base64));
|
339
|
-
} else {
|
340
|
-
// Huffman encoded...
|
341
|
-
std::vector<uint8_t> decompressed;
|
342
|
-
// State here says either we don't know if it's base64 or binary, or we do
|
343
|
-
// and what is it.
|
344
|
-
enum class State { kUnsure, kBinary, kBase64 };
|
345
|
-
State state = State::kUnsure;
|
346
|
-
auto decompressed_ok =
|
347
|
-
ParseHuff(input, pfx->length, [&state, &decompressed](uint8_t c) {
|
348
|
-
if (state == State::kUnsure) {
|
349
|
-
// First byte... if it's zero it's binary
|
350
|
-
if (c == 0) {
|
351
|
-
// Save the type, and skip the zero
|
352
|
-
state = State::kBinary;
|
353
|
-
return;
|
354
|
-
} else {
|
355
|
-
// Flag base64, store this value
|
356
|
-
state = State::kBase64;
|
357
|
-
}
|
358
|
-
}
|
359
|
-
// Non-first byte, or base64 first byte
|
360
|
-
decompressed.push_back(c);
|
361
|
-
});
|
362
|
-
if (!decompressed_ok) return {};
|
363
|
-
switch (state) {
|
364
|
-
case State::kUnsure:
|
365
|
-
// No bytes, empty span
|
366
|
-
return String(absl::Span<const uint8_t>());
|
367
|
-
case State::kBinary:
|
368
|
-
// Binary, we're done
|
369
|
-
return String(std::move(decompressed));
|
370
|
-
case State::kBase64:
|
371
|
-
// Base64 - unpack it
|
372
|
-
return Unbase64(input, String(std::move(decompressed)));
|
373
|
-
}
|
374
|
-
GPR_UNREACHABLE_CODE(abort(););
|
375
|
-
}
|
376
|
-
}
|
382
|
+
static ParseResult ParseBinary(Input* input);
|
377
383
|
|
378
384
|
private:
|
379
385
|
void AppendBytes(const uint8_t* data, size_t length);
|
@@ -385,54 +391,27 @@ class HPackParser::String {
|
|
385
391
|
// Parse some huffman encoded bytes, using output(uint8_t b) to emit each
|
386
392
|
// decoded byte.
|
387
393
|
template <typename Out>
|
388
|
-
static
|
394
|
+
static ParseStatus ParseHuff(Input* input, uint32_t length, Out output) {
|
389
395
|
// If there's insufficient bytes remaining, return now.
|
390
396
|
if (input->remaining() < length) {
|
391
|
-
|
397
|
+
input->UnexpectedEOF();
|
398
|
+
GPR_DEBUG_ASSERT(input->eof_error());
|
399
|
+
return ParseStatus::kEof;
|
392
400
|
}
|
393
401
|
// Grab the byte range, and iterate through it.
|
394
402
|
const uint8_t* p = input->cur_ptr();
|
395
403
|
input->Advance(length);
|
396
|
-
return HuffDecoder<Out>(output, p, p + length).Run()
|
404
|
+
return HuffDecoder<Out>(output, p, p + length).Run()
|
405
|
+
? ParseStatus::kOk
|
406
|
+
: ParseStatus::kParseHuffFailed;
|
397
407
|
}
|
398
408
|
|
399
409
|
// Parse some uncompressed string bytes.
|
400
|
-
static
|
401
|
-
|
402
|
-
// Check there's enough bytes
|
403
|
-
if (input->remaining() < length) {
|
404
|
-
return input->UnexpectedEOF(absl::optional<String>());
|
405
|
-
}
|
406
|
-
auto* refcount = input->slice_refcount();
|
407
|
-
auto* p = input->cur_ptr();
|
408
|
-
input->Advance(length);
|
409
|
-
if (refcount != nullptr) {
|
410
|
-
return String(refcount, p, p + length);
|
411
|
-
} else {
|
412
|
-
return String(absl::Span<const uint8_t>(p, length));
|
413
|
-
}
|
414
|
-
}
|
410
|
+
static ParseResult ParseUncompressed(Input* input, uint32_t length,
|
411
|
+
uint32_t wire_size);
|
415
412
|
|
416
413
|
// Turn base64 encoded bytes into not base64 encoded bytes.
|
417
|
-
|
418
|
-
static absl::optional<String> Unbase64(Input* input, String s) {
|
419
|
-
absl::optional<std::vector<uint8_t>> result;
|
420
|
-
if (auto* p = absl::get_if<Slice>(&s.value_)) {
|
421
|
-
result = Unbase64Loop(p->begin(), p->end());
|
422
|
-
}
|
423
|
-
if (auto* p = absl::get_if<absl::Span<const uint8_t>>(&s.value_)) {
|
424
|
-
result = Unbase64Loop(p->begin(), p->end());
|
425
|
-
}
|
426
|
-
if (auto* p = absl::get_if<std::vector<uint8_t>>(&s.value_)) {
|
427
|
-
result = Unbase64Loop(p->data(), p->data() + p->size());
|
428
|
-
}
|
429
|
-
if (!result.has_value()) {
|
430
|
-
return input->MaybeSetErrorAndReturn(
|
431
|
-
[] { return GRPC_ERROR_CREATE("illegal base64 encoding"); },
|
432
|
-
absl::optional<String>());
|
433
|
-
}
|
434
|
-
return String(std::move(*result));
|
435
|
-
}
|
414
|
+
static ParseResult Unbase64(String s);
|
436
415
|
|
437
416
|
// Main loop for Unbase64
|
438
417
|
static absl::optional<std::vector<uint8_t>> Unbase64Loop(const uint8_t* cur,
|
@@ -519,24 +498,154 @@ class HPackParser::String {
|
|
519
498
|
absl::variant<Slice, absl::Span<const uint8_t>, std::vector<uint8_t>> value_;
|
520
499
|
};
|
521
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
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
HPackParser::String::ParseResult HPackParser::String::Unbase64(String s) {
|
531
|
+
absl::optional<std::vector<uint8_t>> result;
|
532
|
+
if (auto* p = absl::get_if<Slice>(&s.value_)) {
|
533
|
+
result = Unbase64Loop(p->begin(), p->end());
|
534
|
+
}
|
535
|
+
if (auto* p = absl::get_if<absl::Span<const uint8_t>>(&s.value_)) {
|
536
|
+
result = Unbase64Loop(p->begin(), p->end());
|
537
|
+
}
|
538
|
+
if (auto* p = absl::get_if<std::vector<uint8_t>>(&s.value_)) {
|
539
|
+
result = Unbase64Loop(p->data(), p->data() + p->size());
|
540
|
+
}
|
541
|
+
if (!result.has_value()) {
|
542
|
+
return ParseResult{ParseStatus::kUnbase64Failed, s.string_view().length(),
|
543
|
+
String{}};
|
544
|
+
}
|
545
|
+
return ParseResult{ParseStatus::kOk, s.string_view().length(),
|
546
|
+
String(std::move(*result))};
|
547
|
+
}
|
548
|
+
|
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) {
|
556
|
+
// Huffman coded
|
557
|
+
std::vector<uint8_t> output;
|
558
|
+
ParseStatus sts = ParseHuff(input, pfx->length,
|
559
|
+
[&output](uint8_t c) { output.push_back(c); });
|
560
|
+
size_t wire_len = output.size();
|
561
|
+
return ParseResult{sts, wire_len, String(std::move(output))};
|
562
|
+
}
|
563
|
+
return ParseUncompressed(input, pfx->length, pfx->length);
|
564
|
+
}
|
565
|
+
|
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) {
|
575
|
+
// 'true-binary'
|
576
|
+
input->Advance(1);
|
577
|
+
return ParseUncompressed(input, pfx->length - 1, pfx->length);
|
578
|
+
}
|
579
|
+
// 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;
|
582
|
+
return Unbase64(std::move(base64.value));
|
583
|
+
} else {
|
584
|
+
// Huffman encoded...
|
585
|
+
std::vector<uint8_t> decompressed;
|
586
|
+
// State here says either we don't know if it's base64 or binary, or we do
|
587
|
+
// and what is it.
|
588
|
+
enum class State { kUnsure, kBinary, kBase64 };
|
589
|
+
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{}};
|
608
|
+
}
|
609
|
+
switch (state) {
|
610
|
+
case State::kUnsure:
|
611
|
+
// No bytes, empty span
|
612
|
+
return ParseResult{ParseStatus::kOk, 0,
|
613
|
+
String(absl::Span<const uint8_t>())};
|
614
|
+
case State::kBinary:
|
615
|
+
// Binary, we're done
|
616
|
+
{
|
617
|
+
size_t wire_len = decompressed.size();
|
618
|
+
return ParseResult{ParseStatus::kOk, wire_len,
|
619
|
+
String(std::move(decompressed))};
|
620
|
+
}
|
621
|
+
case State::kBase64:
|
622
|
+
// Base64 - unpack it
|
623
|
+
return Unbase64(String(std::move(decompressed)));
|
624
|
+
}
|
625
|
+
GPR_UNREACHABLE_CODE(abort(););
|
626
|
+
}
|
627
|
+
}
|
628
|
+
|
522
629
|
// Parser parses one key/value pair from a byte stream.
|
523
630
|
class HPackParser::Parser {
|
524
631
|
public:
|
525
|
-
Parser(Input* input, grpc_metadata_batch* metadata_buffer,
|
526
|
-
uint32_t metadata_size_limit, HPackTable* table,
|
632
|
+
Parser(Input* input, grpc_metadata_batch* metadata_buffer, HPackTable* table,
|
527
633
|
uint8_t* dynamic_table_updates_allowed, uint32_t* frame_length,
|
528
|
-
LogInfo log_info)
|
634
|
+
RandomEarlyDetection* metadata_early_detection, LogInfo log_info)
|
529
635
|
: input_(input),
|
530
636
|
metadata_buffer_(metadata_buffer),
|
531
637
|
table_(table),
|
532
638
|
dynamic_table_updates_allowed_(dynamic_table_updates_allowed),
|
533
639
|
frame_length_(frame_length),
|
534
|
-
|
640
|
+
metadata_early_detection_(metadata_early_detection),
|
535
641
|
log_info_(log_info) {}
|
536
642
|
|
537
643
|
// Skip any priority bits, or return false on failure
|
538
644
|
bool SkipPriority() {
|
539
|
-
if (input_->remaining() < 5)
|
645
|
+
if (input_->remaining() < 5) {
|
646
|
+
input_->UnexpectedEOF();
|
647
|
+
return false;
|
648
|
+
}
|
540
649
|
input_->Advance(5);
|
541
650
|
return true;
|
542
651
|
}
|
@@ -609,8 +718,9 @@ class HPackParser::Parser {
|
|
609
718
|
case 8:
|
610
719
|
if (cur == 0x80) {
|
611
720
|
// illegal value.
|
612
|
-
|
613
|
-
|
721
|
+
input_->SetErrorAndStopParsing(
|
722
|
+
absl::InternalError("Illegal hpack op code"));
|
723
|
+
return false;
|
614
724
|
}
|
615
725
|
ABSL_FALLTHROUGH_INTENDED;
|
616
726
|
case 9:
|
@@ -647,20 +757,31 @@ class HPackParser::Parser {
|
|
647
757
|
type = "???";
|
648
758
|
break;
|
649
759
|
}
|
650
|
-
gpr_log(GPR_DEBUG, "HTTP:%d:%s:%s: %s", log_info_.stream_id, type,
|
651
|
-
log_info_.is_client ? "CLI" : "SVR",
|
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());
|
652
768
|
}
|
653
769
|
|
654
|
-
|
770
|
+
void EmitHeader(const HPackTable::Memento& md) {
|
655
771
|
// Pass up to the transport
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
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
|
+
}
|
778
|
+
if (!md.parse_status.ok()) {
|
779
|
+
// Reject any requests with invalid metadata.
|
780
|
+
HandleMetadataParseError(md.parse_status);
|
781
|
+
}
|
782
|
+
if (GPR_LIKELY(metadata_buffer_ != nullptr)) {
|
783
|
+
metadata_buffer_->Set(md.md);
|
660
784
|
}
|
661
|
-
|
662
|
-
metadata_buffer_->Set(md);
|
663
|
-
return true;
|
664
785
|
}
|
665
786
|
|
666
787
|
bool FinishHeaderAndAddToTable(absl::optional<HPackTable::Memento> md) {
|
@@ -671,73 +792,149 @@ class HPackParser::Parser {
|
|
671
792
|
LogHeader(*md);
|
672
793
|
}
|
673
794
|
// Emit whilst we own the metadata.
|
674
|
-
|
795
|
+
EmitHeader(*md);
|
675
796
|
// Add to the hpack table
|
676
797
|
grpc_error_handle err = table_->Add(std::move(*md));
|
677
798
|
if (GPR_UNLIKELY(!err.ok())) {
|
678
|
-
input_->
|
799
|
+
input_->SetErrorAndStopParsing(std::move(err));
|
679
800
|
return false;
|
680
801
|
};
|
681
|
-
return
|
802
|
+
return true;
|
682
803
|
}
|
683
804
|
|
684
805
|
bool FinishHeaderOmitFromTable(absl::optional<HPackTable::Memento> md) {
|
685
806
|
// Allow higher code to just pass in failures ... simplifies things a bit.
|
686
807
|
if (!md.has_value()) return false;
|
687
|
-
|
808
|
+
FinishHeaderOmitFromTable(*md);
|
809
|
+
return true;
|
688
810
|
}
|
689
811
|
|
690
|
-
|
812
|
+
void FinishHeaderOmitFromTable(const HPackTable::Memento& md) {
|
691
813
|
// Log if desired
|
692
814
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_hpack_parser)) {
|
693
815
|
LogHeader(md);
|
694
816
|
}
|
695
|
-
|
817
|
+
EmitHeader(md);
|
696
818
|
}
|
697
819
|
|
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
|
+
};
|
838
|
+
}
|
839
|
+
|
840
|
+
HPackTable::Memento Build(ParsedMetadata<grpc_metadata_batch> memento) {
|
841
|
+
return HPackTable::Memento{std::move(memento), std::move(status_)};
|
842
|
+
}
|
843
|
+
|
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
|
+
}
|
870
|
+
|
871
|
+
private:
|
872
|
+
Input* input_;
|
873
|
+
absl::string_view key_string_;
|
874
|
+
absl::Status status_;
|
875
|
+
};
|
876
|
+
|
698
877
|
// Parse a string encoded key and a string encoded value
|
699
878
|
absl::optional<HPackTable::Memento> ParseLiteralKey() {
|
700
879
|
auto key = String::Parse(input_);
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
880
|
+
switch (key.status) {
|
881
|
+
case String::ParseStatus::kOk:
|
882
|
+
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:
|
890
|
+
GPR_DEBUG_ASSERT(input_->eof_error());
|
891
|
+
return absl::nullopt;
|
705
892
|
}
|
706
|
-
auto key_string = key
|
707
|
-
auto
|
708
|
-
|
709
|
-
|
710
|
-
return
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
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()));
|
904
|
+
}
|
905
|
+
|
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();
|
911
|
+
}
|
912
|
+
return ValidateHeaderKeyIsLegal(key);
|
715
913
|
}
|
716
914
|
|
717
915
|
// Parse an index encoded key and a string encoded value
|
718
916
|
absl::optional<HPackTable::Memento> ParseIdxKey(uint32_t index) {
|
719
917
|
const auto* elem = table_->Lookup(index);
|
720
918
|
if (GPR_UNLIKELY(elem == nullptr)) {
|
721
|
-
|
722
|
-
|
723
|
-
}
|
724
|
-
|
725
|
-
|
726
|
-
return
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
}
|
919
|
+
InvalidHPackIndexError(index);
|
920
|
+
return absl::optional<HPackTable::Memento>();
|
921
|
+
}
|
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
|
+
};
|
731
928
|
|
732
929
|
// Parse a varint index encoded key and a string encoded value
|
733
930
|
absl::optional<HPackTable::Memento> ParseVarIdxKey(uint32_t offset) {
|
734
931
|
auto index = input_->ParseVarint(offset);
|
735
|
-
if (GPR_UNLIKELY(!index.has_value())) return
|
932
|
+
if (GPR_UNLIKELY(!index.has_value())) return absl::nullopt;
|
736
933
|
return ParseIdxKey(*index);
|
737
934
|
}
|
738
935
|
|
739
936
|
// Parse a string, figuring out if it's binary or not by the key name.
|
740
|
-
|
937
|
+
String::ParseResult ParseValueString(bool is_binary) {
|
741
938
|
if (is_binary) {
|
742
939
|
return String::ParseBinary(input_);
|
743
940
|
} else {
|
@@ -751,26 +948,25 @@ class HPackParser::Parser {
|
|
751
948
|
if (!index.has_value()) return false;
|
752
949
|
const auto* elem = table_->Lookup(*index);
|
753
950
|
if (GPR_UNLIKELY(elem == nullptr)) {
|
754
|
-
|
951
|
+
InvalidHPackIndexError(*index);
|
952
|
+
return false;
|
755
953
|
}
|
756
|
-
|
954
|
+
FinishHeaderOmitFromTable(*elem);
|
955
|
+
return true;
|
757
956
|
}
|
758
957
|
|
759
958
|
// finish parsing a max table size change
|
760
959
|
bool FinishMaxTableSize(absl::optional<uint32_t> size) {
|
761
960
|
if (!size.has_value()) return false;
|
762
961
|
if (*dynamic_table_updates_allowed_ == 0) {
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
"More than two max table size changes in a single frame");
|
767
|
-
},
|
768
|
-
false);
|
962
|
+
input_->SetErrorAndStopParsing(absl::InternalError(
|
963
|
+
"More than two max table size changes in a single frame"));
|
964
|
+
return false;
|
769
965
|
}
|
770
966
|
(*dynamic_table_updates_allowed_)--;
|
771
967
|
grpc_error_handle err = table_->SetCurrentTableSize(*size);
|
772
968
|
if (!err.ok()) {
|
773
|
-
input_->
|
969
|
+
input_->SetErrorAndStopParsing(std::move(err));
|
774
970
|
return false;
|
775
971
|
}
|
776
972
|
return true;
|
@@ -778,88 +974,52 @@ class HPackParser::Parser {
|
|
778
974
|
|
779
975
|
// Set an invalid hpack index error if no error has been set. Returns result
|
780
976
|
// unmodified.
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
StatusIntProperty::kSize,
|
790
|
-
static_cast<intptr_t>(this->table_->num_entries()));
|
791
|
-
},
|
792
|
-
std::move(result));
|
793
|
-
}
|
794
|
-
|
795
|
-
class MetadataSizeLimitExceededEncoder {
|
796
|
-
public:
|
797
|
-
explicit MetadataSizeLimitExceededEncoder(std::string& summary)
|
798
|
-
: summary_(summary) {}
|
799
|
-
|
800
|
-
void Encode(const Slice& key, const Slice& value) {
|
801
|
-
AddToSummary(key.as_string_view(), value.size());
|
802
|
-
}
|
803
|
-
|
804
|
-
template <typename Key, typename Value>
|
805
|
-
void Encode(Key, const Value& value) {
|
806
|
-
AddToSummary(Key::key(), EncodedSizeOfKey(Key(), value));
|
807
|
-
}
|
977
|
+
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
|
+
}
|
808
985
|
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
"B");
|
986
|
+
GPR_ATTRIBUTE_NOINLINE
|
987
|
+
void HandleMetadataParseError(const absl::Status& status) {
|
988
|
+
if (metadata_buffer_ != nullptr) {
|
989
|
+
metadata_buffer_->Clear();
|
990
|
+
metadata_buffer_ = nullptr;
|
815
991
|
}
|
816
|
-
|
817
|
-
|
992
|
+
// StreamId is used as a signal to skip this stream but keep the connection
|
993
|
+
// alive
|
994
|
+
input_->SetErrorAndContinueParsing(status);
|
995
|
+
}
|
818
996
|
|
819
997
|
GPR_ATTRIBUTE_NOINLINE
|
820
|
-
|
998
|
+
void HandleMetadataHardSizeLimitExceeded(const HPackTable::Memento& md) {
|
821
999
|
// Collect a summary of sizes so far for debugging
|
822
1000
|
// Do not collect contents, for fear of exposing PII.
|
823
1001
|
std::string summary;
|
1002
|
+
std::string error_message;
|
824
1003
|
if (metadata_buffer_ != nullptr) {
|
825
1004
|
MetadataSizeLimitExceededEncoder encoder(summary);
|
826
1005
|
metadata_buffer_->Encode(&encoder);
|
827
1006
|
}
|
828
|
-
summary =
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
[this, summary = std::move(summary)] {
|
836
|
-
return grpc_error_set_int(
|
837
|
-
grpc_error_set_int(
|
838
|
-
GRPC_ERROR_CREATE(absl::StrCat(
|
839
|
-
"received initial metadata size exceeds limit (",
|
840
|
-
*frame_length_, " vs. ", metadata_size_limit_, ")",
|
841
|
-
summary)),
|
842
|
-
StatusIntProperty::kRpcStatus,
|
843
|
-
GRPC_STATUS_RESOURCE_EXHAUSTED),
|
844
|
-
StatusIntProperty::kStreamId, 0);
|
845
|
-
},
|
846
|
-
false);
|
847
|
-
}
|
848
|
-
|
849
|
-
static void ReportMetadataParseError(absl::string_view key,
|
850
|
-
absl::string_view error,
|
851
|
-
absl::string_view value) {
|
852
|
-
gpr_log(
|
853
|
-
GPR_ERROR, "Error parsing metadata: %s",
|
854
|
-
absl::StrCat("error=", error, " key=", key, " value=", value).c_str());
|
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));
|
855
1014
|
}
|
856
1015
|
|
857
1016
|
Input* const input_;
|
858
|
-
grpc_metadata_batch*
|
1017
|
+
grpc_metadata_batch* metadata_buffer_;
|
859
1018
|
HPackTable* const table_;
|
860
1019
|
uint8_t* const dynamic_table_updates_allowed_;
|
861
1020
|
uint32_t* const frame_length_;
|
862
|
-
|
1021
|
+
// Random early detection of metadata size limits.
|
1022
|
+
RandomEarlyDetection* metadata_early_detection_;
|
863
1023
|
const LogInfo log_info_;
|
864
1024
|
};
|
865
1025
|
|
@@ -881,8 +1041,10 @@ HPackParser::HPackParser() = default;
|
|
881
1041
|
HPackParser::~HPackParser() = default;
|
882
1042
|
|
883
1043
|
void HPackParser::BeginFrame(grpc_metadata_batch* metadata_buffer,
|
884
|
-
uint32_t
|
885
|
-
|
1044
|
+
uint32_t metadata_size_soft_limit,
|
1045
|
+
uint32_t metadata_size_hard_limit,
|
1046
|
+
Boundary boundary, Priority priority,
|
1047
|
+
LogInfo log_info) {
|
886
1048
|
metadata_buffer_ = metadata_buffer;
|
887
1049
|
if (metadata_buffer != nullptr) {
|
888
1050
|
metadata_buffer->Set(GrpcStatusFromWire(), true);
|
@@ -891,7 +1053,9 @@ void HPackParser::BeginFrame(grpc_metadata_batch* metadata_buffer,
|
|
891
1053
|
priority_ = priority;
|
892
1054
|
dynamic_table_updates_allowed_ = 2;
|
893
1055
|
frame_length_ = 0;
|
894
|
-
|
1056
|
+
metadata_early_detection_ = RandomEarlyDetection(
|
1057
|
+
/*soft_limit=*/metadata_size_soft_limit,
|
1058
|
+
/*hard_limit=*/metadata_size_hard_limit);
|
895
1059
|
log_info_ = log_info;
|
896
1060
|
}
|
897
1061
|
|
@@ -909,43 +1073,72 @@ grpc_error_handle HPackParser::Parse(const grpc_slice& slice, bool is_last) {
|
|
909
1073
|
}
|
910
1074
|
|
911
1075
|
grpc_error_handle HPackParser::ParseInput(Input input, bool is_last) {
|
912
|
-
|
913
|
-
if (is_last)
|
914
|
-
|
1076
|
+
ParseInputInner(&input);
|
1077
|
+
if (is_last) {
|
1078
|
+
if (metadata_early_detection_.Reject(frame_length_)) {
|
1079
|
+
HandleMetadataSoftSizeLimitExceeded(&input);
|
1080
|
+
}
|
1081
|
+
global_stats().IncrementHttp2MetadataSize(frame_length_);
|
1082
|
+
}
|
915
1083
|
if (input.eof_error()) {
|
916
1084
|
if (GPR_UNLIKELY(is_last && is_boundary())) {
|
917
|
-
|
1085
|
+
auto err = input.TakeError();
|
1086
|
+
if (!err.ok() && !IsStreamError(err)) return err;
|
1087
|
+
return absl::InternalError(
|
918
1088
|
"Incomplete header at the end of a header/continuation sequence");
|
919
1089
|
}
|
920
1090
|
unparsed_bytes_ = std::vector<uint8_t>(input.frontier(), input.end_ptr());
|
921
|
-
return
|
1091
|
+
return input.TakeError();
|
922
1092
|
}
|
923
1093
|
return input.TakeError();
|
924
1094
|
}
|
925
1095
|
|
926
|
-
|
1096
|
+
void HPackParser::ParseInputInner(Input* input) {
|
927
1097
|
switch (priority_) {
|
928
1098
|
case Priority::None:
|
929
1099
|
break;
|
930
1100
|
case Priority::Included: {
|
931
|
-
if (input->remaining() < 5)
|
1101
|
+
if (input->remaining() < 5) {
|
1102
|
+
input->UnexpectedEOF();
|
1103
|
+
return;
|
1104
|
+
}
|
932
1105
|
input->Advance(5);
|
933
1106
|
input->UpdateFrontier();
|
934
1107
|
priority_ = Priority::None;
|
935
1108
|
}
|
936
1109
|
}
|
937
1110
|
while (!input->end_of_stream()) {
|
938
|
-
if (GPR_UNLIKELY(!Parser(input, metadata_buffer_,
|
939
|
-
&
|
940
|
-
&
|
1111
|
+
if (GPR_UNLIKELY(!Parser(input, metadata_buffer_, &table_,
|
1112
|
+
&dynamic_table_updates_allowed_, &frame_length_,
|
1113
|
+
&metadata_early_detection_, log_info_)
|
941
1114
|
.Parse())) {
|
942
|
-
return
|
1115
|
+
return;
|
943
1116
|
}
|
944
1117
|
input->UpdateFrontier();
|
945
1118
|
}
|
946
|
-
return true;
|
947
1119
|
}
|
948
1120
|
|
949
1121
|
void HPackParser::FinishFrame() { metadata_buffer_ = nullptr; }
|
950
1122
|
|
1123
|
+
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
|
+
input->SetErrorAndContinueParsing(
|
1141
|
+
absl::ResourceExhaustedError(error_message));
|
1142
|
+
}
|
1143
|
+
|
951
1144
|
} // namespace grpc_core
|