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.
- checksums.yaml +4 -4
- data/Makefile +4 -2
- data/include/grpc/grpc_security.h +19 -0
- data/src/core/ext/filters/client_channel/lb_policy/outlier_detection/outlier_detection.cc +1 -1
- data/src/core/ext/filters/client_channel/lb_policy/weighted_round_robin/weighted_round_robin.cc +10 -1
- data/src/core/ext/transport/chttp2/transport/hpack_parse_result.cc +176 -0
- data/src/core/ext/transport/chttp2/transport/hpack_parse_result.h +325 -0
- data/src/core/ext/transport/chttp2/transport/hpack_parser.cc +567 -543
- data/src/core/ext/transport/chttp2/transport/hpack_parser.h +150 -9
- data/src/core/ext/transport/chttp2/transport/hpack_parser_table.cc +46 -32
- data/src/core/ext/transport/chttp2/transport/hpack_parser_table.h +18 -5
- data/src/core/ext/transport/chttp2/transport/parsing.cc +12 -12
- data/src/core/lib/backoff/random_early_detection.h +5 -0
- data/src/core/lib/event_engine/posix_engine/posix_engine.h +1 -0
- data/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc +29 -0
- data/src/core/lib/event_engine/posix_engine/posix_engine_listener.h +3 -0
- data/src/core/lib/iomgr/tcp_server_posix.cc +34 -12
- data/src/core/lib/iomgr/tcp_server_utils_posix.h +12 -0
- data/src/core/lib/iomgr/tcp_server_utils_posix_common.cc +21 -0
- data/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc +8 -0
- data/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h +5 -1
- data/src/core/lib/security/security_connector/ssl_utils.cc +2 -1
- data/src/core/lib/security/security_connector/ssl_utils.h +1 -1
- data/src/core/lib/security/security_connector/tls/tls_security_connector.cc +1 -1
- data/src/core/lib/surface/validate_metadata.cc +37 -22
- data/src/core/lib/surface/validate_metadata.h +13 -3
- data/src/core/tsi/ssl_transport_security.cc +5 -2
- data/src/core/tsi/ssl_transport_security.h +13 -1
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +2 -0
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +3 -0
- data/src/ruby/lib/grpc/version.rb +1 -1
- 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/
|
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
|
213
|
+
// Check if we saw an EOF
|
247
214
|
bool eof_error() const {
|
248
|
-
return
|
215
|
+
return min_progress_size_ != 0 || error_.connection_error();
|
249
216
|
}
|
250
217
|
|
251
|
-
//
|
252
|
-
|
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
|
-
|
265
|
-
|
266
|
-
|
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
|
-
|
276
|
-
|
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
|
-
|
283
|
-
|
284
|
-
|
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() {
|
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(
|
298
|
-
|
299
|
-
|
300
|
-
|
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(
|
308
|
-
if (!error_.ok() ||
|
309
|
-
if (
|
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
|
-
|
327
|
-
// If the error was EOF, we flag it here
|
328
|
-
|
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
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
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
|
-
|
362
|
-
|
363
|
-
|
364
|
-
//
|
365
|
-
|
366
|
-
|
367
|
-
|
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
|
-
|
379
|
-
|
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
|
-
|
382
|
-
|
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
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
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
|
-
|
410
|
-
|
411
|
-
|
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
|
-
|
414
|
-
|
431
|
+
++cur;
|
432
|
+
bits = kBase64InverseTable.table[*cur];
|
433
|
+
if (bits > 63) return {};
|
434
|
+
buffer |= bits << 12;
|
415
435
|
|
416
|
-
|
417
|
-
|
418
|
-
|
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.
|
449
|
-
|
450
|
-
|
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
|
-
|
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::
|
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
|
543
|
-
|
478
|
+
return StringResult{HpackParseStatus::kUnbase64Failed,
|
479
|
+
s.string_view().length(), String{}};
|
544
480
|
}
|
545
|
-
return
|
546
|
-
|
481
|
+
return StringResult{HpackParseStatus::kOk, s.string_view().length(),
|
482
|
+
String(std::move(*result))};
|
547
483
|
}
|
548
484
|
|
549
|
-
HPackParser::String::
|
550
|
-
|
551
|
-
|
552
|
-
|
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
|
-
|
559
|
-
|
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
|
494
|
+
return StringResult{sts, wire_len, String(std::move(output))};
|
562
495
|
}
|
563
|
-
return ParseUncompressed(input,
|
496
|
+
return ParseUncompressed(input, length, length);
|
564
497
|
}
|
565
498
|
|
566
|
-
HPackParser::String::
|
567
|
-
Input* input) {
|
568
|
-
|
569
|
-
|
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,
|
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,
|
581
|
-
if (base64.status !=
|
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
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
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
|
613
|
-
|
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
|
619
|
-
|
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
|
633
|
-
|
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
|
-
|
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
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
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
|
-
|
650
|
-
return true;
|
585
|
+
GPR_UNREACHABLE_CODE(return false);
|
651
586
|
}
|
652
587
|
|
653
|
-
|
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
|
603
|
+
return StartParseLiteralKey(false);
|
667
604
|
case 0xf: // varint encoded key index
|
668
|
-
return
|
605
|
+
return StartVarIdxKey(0xf, false);
|
669
606
|
default: // inline encoded key index
|
670
|
-
return
|
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
|
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
|
640
|
+
return StartIdxKey(cur & 0x3f, true);
|
704
641
|
case 7:
|
705
642
|
if (cur == 0x7f) {
|
706
643
|
// varint encoded key index
|
707
|
-
return
|
644
|
+
return StartVarIdxKey(0x3f, true);
|
708
645
|
} else {
|
709
646
|
// inline encoded key index
|
710
|
-
return
|
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
|
-
|
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(
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
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
|
-
|
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
|
-
|
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(
|
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(
|
728
|
+
LogHeader(md);
|
793
729
|
}
|
794
730
|
// Emit whilst we own the metadata.
|
795
|
-
EmitHeader(
|
731
|
+
EmitHeader(md);
|
796
732
|
// Add to the hpack table
|
797
|
-
|
798
|
-
|
799
|
-
|
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
|
-
//
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
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
|
-
|
841
|
-
|
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
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
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
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
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
|
-
|
878
|
-
|
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
|
843
|
+
case HpackParseStatus::kOk:
|
882
844
|
break;
|
883
|
-
case
|
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
|
847
|
+
return false;
|
848
|
+
default:
|
849
|
+
input_->SetErrorAndStopParsing(
|
850
|
+
HpackParseResult::FromStatus(key.status));
|
851
|
+
return false;
|
892
852
|
}
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
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
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
return
|
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
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
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
|
-
|
923
|
-
|
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
|
-
|
930
|
-
|
931
|
-
auto
|
932
|
-
if (
|
933
|
-
|
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
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
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
|
-
|
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
|
-
|
1018
|
+
state_.dynamic_table_updates_allowed = 0;
|
948
1019
|
if (!index.has_value()) return false;
|
949
|
-
const auto* elem =
|
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 (
|
962
|
-
input_->SetErrorAndStopParsing(
|
963
|
-
|
1032
|
+
if (state_.dynamic_table_updates_allowed == 0) {
|
1033
|
+
input_->SetErrorAndStopParsing(
|
1034
|
+
HpackParseResult::TooManyDynamicTableSizeChangesError());
|
964
1035
|
return false;
|
965
1036
|
}
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
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(
|
979
|
-
|
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
|
1018
|
-
|
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
|
-
|
1055
|
-
|
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
|
-
|
1066
|
-
|
1067
|
-
|
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 (
|
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(
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
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
|
-
|
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(
|
1112
|
-
|
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
|
-
|
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
|