grpc 1.55.0 → 1.55.3
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/src/core/ext/filters/client_channel/client_channel.cc +4 -6
- data/src/core/ext/filters/client_channel/client_channel.h +2 -0
- 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.cc +30 -17
- 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 +39 -14
- 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/surface/validate_metadata.cc +37 -22
- data/src/core/lib/surface/validate_metadata.h +13 -3
- data/src/ruby/lib/grpc/version.rb +1 -1
- metadata +5 -3
| @@ -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
         |