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
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 0ae21f1a2c098f42e02627a2f42d31f3ff20ab095fd29e842122418a6ef9a205
         | 
| 4 | 
            +
              data.tar.gz: 16f30ea02d89e66f113bf4ecb28d34f4507418726acf9ff0f4f371636db2427d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: bc74a95bfe12838c5c28cd47a95e0d8a9abec0634522292831709ddd3e394dfc0ea1a255348f14e32dbf757013043be1d1248dd6c4d51a26f5549a8b9bee1ed6
         | 
| 7 | 
            +
              data.tar.gz: 68f68a12ef092eebd3333c16eda5b5337378b4615448f25a6da8551b253acba54093ce373e66bbf5eb5304b5be6f243328c0cdf941e57510010e8919c9b93de9
         | 
    
        data/Makefile
    CHANGED
    
    | @@ -411,8 +411,8 @@ Q = @ | |
| 411 411 | 
             
            endif
         | 
| 412 412 |  | 
| 413 413 | 
             
            CORE_VERSION = 32.0.0
         | 
| 414 | 
            -
            CPP_VERSION = 1.55. | 
| 415 | 
            -
            CSHARP_VERSION = 2.55. | 
| 414 | 
            +
            CPP_VERSION = 1.55.3
         | 
| 415 | 
            +
            CSHARP_VERSION = 2.55.3
         | 
| 416 416 |  | 
| 417 417 | 
             
            CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
         | 
| 418 418 | 
             
            CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
         | 
| @@ -1057,6 +1057,7 @@ LIBGRPC_SRC = \ | |
| 1057 1057 | 
             
                src/core/ext/transport/chttp2/transport/frame_window_update.cc \
         | 
| 1058 1058 | 
             
                src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
         | 
| 1059 1059 | 
             
                src/core/ext/transport/chttp2/transport/hpack_encoder_table.cc \
         | 
| 1060 | 
            +
                src/core/ext/transport/chttp2/transport/hpack_parse_result.cc \
         | 
| 1060 1061 | 
             
                src/core/ext/transport/chttp2/transport/hpack_parser.cc \
         | 
| 1061 1062 | 
             
                src/core/ext/transport/chttp2/transport/hpack_parser_table.cc \
         | 
| 1062 1063 | 
             
                src/core/ext/transport/chttp2/transport/http2_settings.cc \
         | 
| @@ -1919,6 +1920,7 @@ LIBGRPC_UNSECURE_SRC = \ | |
| 1919 1920 | 
             
                src/core/ext/transport/chttp2/transport/frame_window_update.cc \
         | 
| 1920 1921 | 
             
                src/core/ext/transport/chttp2/transport/hpack_encoder.cc \
         | 
| 1921 1922 | 
             
                src/core/ext/transport/chttp2/transport/hpack_encoder_table.cc \
         | 
| 1923 | 
            +
                src/core/ext/transport/chttp2/transport/hpack_parse_result.cc \
         | 
| 1922 1924 | 
             
                src/core/ext/transport/chttp2/transport/hpack_parser.cc \
         | 
| 1923 1925 | 
             
                src/core/ext/transport/chttp2/transport/hpack_parser_table.cc \
         | 
| 1924 1926 | 
             
                src/core/ext/transport/chttp2/transport/http2_settings.cc \
         | 
| @@ -3033,6 +3033,8 @@ void ClientChannel::FilterBasedLoadBalancedCall::RecvInitialMetadataReady( | |
| 3033 3033 | 
             
                // recv_initial_metadata_flags is not populated for clients
         | 
| 3034 3034 | 
             
                self->call_attempt_tracer()->RecordReceivedInitialMetadata(
         | 
| 3035 3035 | 
             
                    self->recv_initial_metadata_);
         | 
| 3036 | 
            +
                auto* peer_string = self->recv_initial_metadata_->get_pointer(PeerString());
         | 
| 3037 | 
            +
                if (peer_string != nullptr) self->peer_string_ = peer_string->Ref();
         | 
| 3036 3038 | 
             
              }
         | 
| 3037 3039 | 
             
              Closure::Run(DEBUG_LOCATION, self->original_recv_initial_metadata_ready_,
         | 
| 3038 3040 | 
             
                           error);
         | 
| @@ -3076,12 +3078,8 @@ void ClientChannel::FilterBasedLoadBalancedCall::RecvTrailingMetadataReady( | |
| 3076 3078 | 
             
                  }
         | 
| 3077 3079 | 
             
                }
         | 
| 3078 3080 | 
             
                absl::string_view peer_string;
         | 
| 3079 | 
            -
                if (self-> | 
| 3080 | 
            -
                   | 
| 3081 | 
            -
                      self->recv_initial_metadata_->get_pointer(PeerString());
         | 
| 3082 | 
            -
                  if (peer_string_slice != nullptr) {
         | 
| 3083 | 
            -
                    peer_string = peer_string_slice->as_string_view();
         | 
| 3084 | 
            -
                  }
         | 
| 3081 | 
            +
                if (self->peer_string_.has_value()) {
         | 
| 3082 | 
            +
                  peer_string = self->peer_string_->as_string_view();
         | 
| 3085 3083 | 
             
                }
         | 
| 3086 3084 | 
             
                self->RecordCallCompletion(status, self->recv_trailing_metadata_,
         | 
| 3087 3085 | 
             
                                           self->transport_stream_stats_, peer_string);
         | 
| @@ -65,6 +65,7 @@ | |
| 65 65 | 
             
            #include "src/core/lib/resolver/resolver.h"
         | 
| 66 66 | 
             
            #include "src/core/lib/resource_quota/arena.h"
         | 
| 67 67 | 
             
            #include "src/core/lib/service_config/service_config.h"
         | 
| 68 | 
            +
            #include "src/core/lib/slice/slice.h"
         | 
| 68 69 | 
             
            #include "src/core/lib/surface/channel.h"
         | 
| 69 70 | 
             
            #include "src/core/lib/transport/connectivity_state.h"
         | 
| 70 71 | 
             
            #include "src/core/lib/transport/metadata_batch.h"
         | 
| @@ -552,6 +553,7 @@ class ClientChannel::FilterBasedLoadBalancedCall | |
| 552 553 | 
             
              CallCombiner* call_combiner_;
         | 
| 553 554 | 
             
              grpc_polling_entity* pollent_;
         | 
| 554 555 | 
             
              grpc_closure* on_call_destruction_complete_;
         | 
| 556 | 
            +
              absl::optional<Slice> peer_string_;
         | 
| 555 557 |  | 
| 556 558 | 
             
              // Set when we get a cancel_stream op.
         | 
| 557 559 | 
             
              grpc_error_handle cancel_error_;
         | 
| @@ -0,0 +1,176 @@ | |
| 1 | 
            +
            // Copyright 2023 gRPC authors.
         | 
| 2 | 
            +
            //
         | 
| 3 | 
            +
            // Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 4 | 
            +
            // you may not use this file except in compliance with the License.
         | 
| 5 | 
            +
            // You may obtain a copy of the License at
         | 
| 6 | 
            +
            //
         | 
| 7 | 
            +
            //     http://www.apache.org/licenses/LICENSE-2.0
         | 
| 8 | 
            +
            //
         | 
| 9 | 
            +
            // Unless required by applicable law or agreed to in writing, software
         | 
| 10 | 
            +
            // distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 11 | 
            +
            // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 12 | 
            +
            // See the License for the specific language governing permissions and
         | 
| 13 | 
            +
            // limitations under the License.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            #include <grpc/support/port_platform.h>
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            #include "src/core/ext/transport/chttp2/transport/hpack_parse_result.h"
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            #include <stddef.h>
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            #include <initializer_list>
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            #include "absl/strings/str_format.h"
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            #include "src/core/ext/transport/chttp2/transport/hpack_constants.h"
         | 
| 26 | 
            +
            #include "src/core/lib/gprpp/status_helper.h"
         | 
| 27 | 
            +
            #include "src/core/lib/iomgr/error.h"
         | 
| 28 | 
            +
            #include "src/core/lib/slice/slice.h"
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            namespace grpc_core {
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            namespace {
         | 
| 33 | 
            +
            class MetadataSizeLimitExceededEncoder {
         | 
| 34 | 
            +
             public:
         | 
| 35 | 
            +
              explicit MetadataSizeLimitExceededEncoder(std::string& summary)
         | 
| 36 | 
            +
                  : summary_(summary) {}
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              void Encode(const Slice& key, const Slice& value) {
         | 
| 39 | 
            +
                AddToSummary(key.as_string_view(), value.size());
         | 
| 40 | 
            +
              }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              template <typename Key, typename Value>
         | 
| 43 | 
            +
              void Encode(Key, const Value& value) {
         | 
| 44 | 
            +
                AddToSummary(Key::key(), EncodedSizeOfKey(Key(), value));
         | 
| 45 | 
            +
              }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
             private:
         | 
| 48 | 
            +
              void AddToSummary(absl::string_view key,
         | 
| 49 | 
            +
                                size_t value_length) GPR_ATTRIBUTE_NOINLINE {
         | 
| 50 | 
            +
                absl::StrAppend(&summary_, " ", key, ":",
         | 
| 51 | 
            +
                                hpack_constants::SizeForEntry(key.size(), value_length),
         | 
| 52 | 
            +
                                "B");
         | 
| 53 | 
            +
              }
         | 
| 54 | 
            +
              std::string& summary_;
         | 
| 55 | 
            +
            };
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            absl::Status MakeStreamError(absl::Status error) {
         | 
| 58 | 
            +
              GPR_DEBUG_ASSERT(!error.ok());
         | 
| 59 | 
            +
              return grpc_error_set_int(std::move(error), StatusIntProperty::kStreamId, 0);
         | 
| 60 | 
            +
            }
         | 
| 61 | 
            +
            }  // namespace
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            absl::Status HpackParseResult::Materialize() const {
         | 
| 64 | 
            +
              if (materialized_status_.has_value()) return *materialized_status_;
         | 
| 65 | 
            +
              materialized_status_ = BuildMaterialized();
         | 
| 66 | 
            +
              return *materialized_status_;
         | 
| 67 | 
            +
            }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            absl::Status HpackParseResult::BuildMaterialized() const {
         | 
| 70 | 
            +
              switch (status_.get()) {
         | 
| 71 | 
            +
                case HpackParseStatus::kOk:
         | 
| 72 | 
            +
                  return absl::OkStatus();
         | 
| 73 | 
            +
                case HpackParseStatus::kEof:
         | 
| 74 | 
            +
                  Crash("Materialize() called on EOF");
         | 
| 75 | 
            +
                  break;
         | 
| 76 | 
            +
                case HpackParseStatus::kMovedFrom:
         | 
| 77 | 
            +
                  Crash("Materialize() called on moved-from object");
         | 
| 78 | 
            +
                  break;
         | 
| 79 | 
            +
                case HpackParseStatus::kInvalidMetadata:
         | 
| 80 | 
            +
                  if (key_.empty()) {
         | 
| 81 | 
            +
                    return MakeStreamError(absl::InternalError(
         | 
| 82 | 
            +
                        ValidateMetadataResultToString(validate_metadata_result_)));
         | 
| 83 | 
            +
                  } else {
         | 
| 84 | 
            +
                    return MakeStreamError(absl::InternalError(absl::StrCat(
         | 
| 85 | 
            +
                        ValidateMetadataResultToString(validate_metadata_result_), ": ",
         | 
| 86 | 
            +
                        key_)));
         | 
| 87 | 
            +
                  }
         | 
| 88 | 
            +
                case HpackParseStatus::kSoftMetadataLimitExceeded:
         | 
| 89 | 
            +
                case HpackParseStatus::kHardMetadataLimitExceeded: {
         | 
| 90 | 
            +
                  const auto& e = metadata_limit_exceeded_;
         | 
| 91 | 
            +
                  // Collect a summary of sizes so far for debugging
         | 
| 92 | 
            +
                  // Do not collect contents, for fear of exposing PII.
         | 
| 93 | 
            +
                  std::string summary;
         | 
| 94 | 
            +
                  if (e.prior != nullptr) {
         | 
| 95 | 
            +
                    MetadataSizeLimitExceededEncoder encoder(summary);
         | 
| 96 | 
            +
                    e.prior->Encode(&encoder);
         | 
| 97 | 
            +
                  }
         | 
| 98 | 
            +
                  return MakeStreamError(absl::ResourceExhaustedError(absl::StrCat(
         | 
| 99 | 
            +
                      "received metadata size exceeds ",
         | 
| 100 | 
            +
                      status_.get() == HpackParseStatus::kSoftMetadataLimitExceeded
         | 
| 101 | 
            +
                          ? "soft"
         | 
| 102 | 
            +
                          : "hard",
         | 
| 103 | 
            +
                      " limit (", e.frame_length, " vs. ", e.limit, ")",
         | 
| 104 | 
            +
                      summary.empty() ? "" : "; ", summary)));
         | 
| 105 | 
            +
                }
         | 
| 106 | 
            +
                case HpackParseStatus::kHardMetadataLimitExceededByKey: {
         | 
| 107 | 
            +
                  const auto& e = metadata_limit_exceeded_by_atom_;
         | 
| 108 | 
            +
                  return MakeStreamError(absl::ResourceExhaustedError(
         | 
| 109 | 
            +
                      absl::StrCat("received metadata size exceeds hard limit (key length ",
         | 
| 110 | 
            +
                                   e.atom_length, " vs. ", e.limit, ")")));
         | 
| 111 | 
            +
                }
         | 
| 112 | 
            +
                case HpackParseStatus::kHardMetadataLimitExceededByValue: {
         | 
| 113 | 
            +
                  const auto& e = metadata_limit_exceeded_by_atom_;
         | 
| 114 | 
            +
                  return MakeStreamError(absl::ResourceExhaustedError(absl::StrCat(
         | 
| 115 | 
            +
                      "received metadata size exceeds hard limit (value length ",
         | 
| 116 | 
            +
                      e.atom_length, " vs. ", e.limit, ")")));
         | 
| 117 | 
            +
                }
         | 
| 118 | 
            +
                case HpackParseStatus::kMetadataParseError:
         | 
| 119 | 
            +
                  if (!key_.empty()) {
         | 
| 120 | 
            +
                    return MakeStreamError(absl::InternalError(
         | 
| 121 | 
            +
                        absl::StrCat("Error parsing '", key_, "' metadata")));
         | 
| 122 | 
            +
                  } else {
         | 
| 123 | 
            +
                    return MakeStreamError(absl::InternalError("Error parsing metadata"));
         | 
| 124 | 
            +
                  }
         | 
| 125 | 
            +
                case HpackParseStatus::kUnbase64Failed:
         | 
| 126 | 
            +
                  if (!key_.empty()) {
         | 
| 127 | 
            +
                    return MakeStreamError(absl::InternalError(absl::StrCat(
         | 
| 128 | 
            +
                        "Error parsing '", key_, "' metadata: illegal base64 encoding")));
         | 
| 129 | 
            +
                  } else {
         | 
| 130 | 
            +
                    return MakeStreamError(absl::InternalError(
         | 
| 131 | 
            +
                        absl::StrCat("Failed base64 decoding metadata")));
         | 
| 132 | 
            +
                  }
         | 
| 133 | 
            +
                case HpackParseStatus::kIncompleteHeaderAtBoundary:
         | 
| 134 | 
            +
                  return absl::InternalError(
         | 
| 135 | 
            +
                      "Incomplete header at the end of a header/continuation sequence");
         | 
| 136 | 
            +
                case HpackParseStatus::kVarintOutOfRange:
         | 
| 137 | 
            +
                  return absl::InternalError(absl::StrFormat(
         | 
| 138 | 
            +
                      "integer overflow in hpack integer decoding: have 0x%08x, "
         | 
| 139 | 
            +
                      "got byte 0x%02x",
         | 
| 140 | 
            +
                      varint_out_of_range_.value, varint_out_of_range_.last_byte));
         | 
| 141 | 
            +
                case HpackParseStatus::kIllegalTableSizeChange:
         | 
| 142 | 
            +
                  return absl::InternalError(absl::StrCat(
         | 
| 143 | 
            +
                      "Attempt to make hpack table ", illegal_table_size_change_.new_size,
         | 
| 144 | 
            +
                      " bytes when max is ", illegal_table_size_change_.max_size,
         | 
| 145 | 
            +
                      " bytes"));
         | 
| 146 | 
            +
                case HpackParseStatus::kAddBeforeTableSizeUpdated:
         | 
| 147 | 
            +
                  return absl::InternalError(
         | 
| 148 | 
            +
                      absl::StrCat("HPACK max table size reduced to ",
         | 
| 149 | 
            +
                                   illegal_table_size_change_.new_size,
         | 
| 150 | 
            +
                                   " but not reflected by hpack stream (still at ",
         | 
| 151 | 
            +
                                   illegal_table_size_change_.max_size, ")"));
         | 
| 152 | 
            +
                case HpackParseStatus::kParseHuffFailed:
         | 
| 153 | 
            +
                  if (!key_.empty()) {
         | 
| 154 | 
            +
                    return absl::InternalError(
         | 
| 155 | 
            +
                        absl::StrCat("Failed huffman decoding '", key_, "' metadata"));
         | 
| 156 | 
            +
                  } else {
         | 
| 157 | 
            +
                    return absl::InternalError(
         | 
| 158 | 
            +
                        absl::StrCat("Failed huffman decoding metadata"));
         | 
| 159 | 
            +
                  }
         | 
| 160 | 
            +
                  break;
         | 
| 161 | 
            +
                case HpackParseStatus::kTooManyDynamicTableSizeChanges:
         | 
| 162 | 
            +
                  return absl::InternalError(
         | 
| 163 | 
            +
                      "More than two max table size changes in a single frame");
         | 
| 164 | 
            +
                case HpackParseStatus::kMaliciousVarintEncoding:
         | 
| 165 | 
            +
                  return absl::InternalError(
         | 
| 166 | 
            +
                      "Malicious varint encoding detected in HPACK stream");
         | 
| 167 | 
            +
                case HpackParseStatus::kInvalidHpackIndex:
         | 
| 168 | 
            +
                  return absl::InternalError(absl::StrFormat(
         | 
| 169 | 
            +
                      "Invalid HPACK index received (%d)", invalid_hpack_index_));
         | 
| 170 | 
            +
                case HpackParseStatus::kIllegalHpackOpCode:
         | 
| 171 | 
            +
                  return absl::InternalError("Illegal hpack op code");
         | 
| 172 | 
            +
              }
         | 
| 173 | 
            +
              GPR_UNREACHABLE_CODE(return absl::UnknownError("Should never reach here"));
         | 
| 174 | 
            +
            }
         | 
| 175 | 
            +
             | 
| 176 | 
            +
            }  // namespace grpc_core
         | 
| @@ -0,0 +1,325 @@ | |
| 1 | 
            +
            // Copyright 2023 gRPC authors.
         | 
| 2 | 
            +
            //
         | 
| 3 | 
            +
            // Licensed under the Apache License, Version 2.0 (the "License");
         | 
| 4 | 
            +
            // you may not use this file except in compliance with the License.
         | 
| 5 | 
            +
            // You may obtain a copy of the License at
         | 
| 6 | 
            +
            //
         | 
| 7 | 
            +
            //     http://www.apache.org/licenses/LICENSE-2.0
         | 
| 8 | 
            +
            //
         | 
| 9 | 
            +
            // Unless required by applicable law or agreed to in writing, software
         | 
| 10 | 
            +
            // distributed under the License is distributed on an "AS IS" BASIS,
         | 
| 11 | 
            +
            // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         | 
| 12 | 
            +
            // See the License for the specific language governing permissions and
         | 
| 13 | 
            +
            // limitations under the License.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            #ifndef GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSE_RESULT_H
         | 
| 16 | 
            +
            #define GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSE_RESULT_H
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            #include <grpc/support/port_platform.h>
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            #include <stdint.h>
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            #include <string>
         | 
| 23 | 
            +
            #include <utility>
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            #include "absl/status/status.h"
         | 
| 26 | 
            +
            #include "absl/strings/str_cat.h"
         | 
| 27 | 
            +
            #include "absl/strings/string_view.h"
         | 
| 28 | 
            +
            #include "absl/types/optional.h"
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            #include <grpc/support/log.h>
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            #include "src/core/lib/gprpp/crash.h"
         | 
| 33 | 
            +
            #include "src/core/lib/surface/validate_metadata.h"
         | 
| 34 | 
            +
            #include "src/core/lib/transport/metadata_batch.h"
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            namespace grpc_core {
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            // Result of parsing
         | 
| 39 | 
            +
            // Makes it trivial to identify stream vs connection errors (via a range check)
         | 
| 40 | 
            +
            enum class HpackParseStatus : uint8_t {
         | 
| 41 | 
            +
              ///////////////////////////////////////////////////////
         | 
| 42 | 
            +
              // Non-Errors
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              // Parsed OK
         | 
| 45 | 
            +
              kOk,
         | 
| 46 | 
            +
              // Parse reached end of the current frame
         | 
| 47 | 
            +
              kEof,
         | 
| 48 | 
            +
              // Moved from - used to denote a HpackParseResult that has been moved into a
         | 
| 49 | 
            +
              // different object, and so the original should be deemed invalid.
         | 
| 50 | 
            +
              kMovedFrom,
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              ///////////////////////////////////////////////////////////////////
         | 
| 53 | 
            +
              // Stream Errors - result in a stream cancellation
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              // Sentinel value used to denote the first error that is a stream error.
         | 
| 56 | 
            +
              // All stream errors are hence >= kFirstStreamError and <
         | 
| 57 | 
            +
              // kFirstConnectionError.
         | 
| 58 | 
            +
              // Should not be used in switch statements, instead the first error message
         | 
| 59 | 
            +
              // after this one should be assigned the same value.
         | 
| 60 | 
            +
              kFirstStreamError,
         | 
| 61 | 
            +
              kInvalidMetadata = kFirstStreamError,
         | 
| 62 | 
            +
              // Hard metadata limit exceeded by the total set of metadata
         | 
| 63 | 
            +
              kHardMetadataLimitExceeded,
         | 
| 64 | 
            +
              kSoftMetadataLimitExceeded,
         | 
| 65 | 
            +
              // Hard metadata limit exceeded by a single key string
         | 
| 66 | 
            +
              kHardMetadataLimitExceededByKey,
         | 
| 67 | 
            +
              // Hard metadata limit exceeded by a single value string
         | 
| 68 | 
            +
              kHardMetadataLimitExceededByValue,
         | 
| 69 | 
            +
              kMetadataParseError,
         | 
| 70 | 
            +
              // Parse failed due to a base64 decode error
         | 
| 71 | 
            +
              kUnbase64Failed,
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              ///////////////////////////////////////////////////////////////////
         | 
| 74 | 
            +
              // Connection Errors - result in the tcp connection closing
         | 
| 75 | 
            +
             | 
| 76 | 
            +
              // Sentinel value used to denote the first error that is a connection error.
         | 
| 77 | 
            +
              // All connection errors are hence >= kFirstConnectionError.
         | 
| 78 | 
            +
              // Should not be used in switch statements, instead the first error message
         | 
| 79 | 
            +
              // after this one should be assigned the same value.
         | 
| 80 | 
            +
              kFirstConnectionError,
         | 
| 81 | 
            +
              // Incomplete header at end of header boundary
         | 
| 82 | 
            +
              kIncompleteHeaderAtBoundary = kFirstConnectionError,
         | 
| 83 | 
            +
              // Varint out of range
         | 
| 84 | 
            +
              kVarintOutOfRange,
         | 
| 85 | 
            +
              // Invalid HPACK index
         | 
| 86 | 
            +
              kInvalidHpackIndex,
         | 
| 87 | 
            +
              // Illegal HPACK table size change
         | 
| 88 | 
            +
              kIllegalTableSizeChange,
         | 
| 89 | 
            +
              // Trying to add to the hpack table prior to reducing after a settings change
         | 
| 90 | 
            +
              kAddBeforeTableSizeUpdated,
         | 
| 91 | 
            +
              // Parse failed due to a huffman decode error
         | 
| 92 | 
            +
              kParseHuffFailed,
         | 
| 93 | 
            +
              // Too many dynamic table size changes in one frame
         | 
| 94 | 
            +
              kTooManyDynamicTableSizeChanges,
         | 
| 95 | 
            +
              // Maliciously long varint encoding
         | 
| 96 | 
            +
              // We don't read past 16 repeated 0x80 prefixes on a varint (all zeros)
         | 
| 97 | 
            +
              // because no reasonable varint encoder would emit that (16 is already quite
         | 
| 98 | 
            +
              // generous!)
         | 
| 99 | 
            +
              // Because we stop reading we don't parse the rest of the bytes and so we
         | 
| 100 | 
            +
              // can't recover parsing and would end up with a hpack table desync if we
         | 
| 101 | 
            +
              // tried, so this is a connection error.
         | 
| 102 | 
            +
              kMaliciousVarintEncoding,
         | 
| 103 | 
            +
              // Illegal hpack op code
         | 
| 104 | 
            +
              kIllegalHpackOpCode,
         | 
| 105 | 
            +
            };
         | 
| 106 | 
            +
             | 
| 107 | 
            +
            inline bool IsStreamError(HpackParseStatus status) {
         | 
| 108 | 
            +
              return status >= HpackParseStatus::kFirstStreamError &&
         | 
| 109 | 
            +
                     status < HpackParseStatus::kFirstConnectionError;
         | 
| 110 | 
            +
            }
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            inline bool IsConnectionError(HpackParseStatus status) {
         | 
| 113 | 
            +
              return status >= HpackParseStatus::kFirstConnectionError;
         | 
| 114 | 
            +
            }
         | 
| 115 | 
            +
             | 
| 116 | 
            +
            inline bool IsEphemeralError(HpackParseStatus status) {
         | 
| 117 | 
            +
              switch (status) {
         | 
| 118 | 
            +
                case HpackParseStatus::kSoftMetadataLimitExceeded:
         | 
| 119 | 
            +
                case HpackParseStatus::kHardMetadataLimitExceeded:
         | 
| 120 | 
            +
                  return true;
         | 
| 121 | 
            +
                default:
         | 
| 122 | 
            +
                  return false;
         | 
| 123 | 
            +
              }
         | 
| 124 | 
            +
            }
         | 
| 125 | 
            +
             | 
| 126 | 
            +
            class HpackParseResult {
         | 
| 127 | 
            +
             public:
         | 
| 128 | 
            +
              HpackParseResult() : HpackParseResult{HpackParseStatus::kOk} {}
         | 
| 129 | 
            +
             | 
| 130 | 
            +
              bool ok() const { return status_.get() == HpackParseStatus::kOk; }
         | 
| 131 | 
            +
              bool stream_error() const { return IsStreamError(status_.get()); }
         | 
| 132 | 
            +
              bool connection_error() const { return IsConnectionError(status_.get()); }
         | 
| 133 | 
            +
              bool ephemeral() const { return IsEphemeralError(status_.get()); }
         | 
| 134 | 
            +
             | 
| 135 | 
            +
              HpackParseResult PersistentStreamErrorOrOk() const {
         | 
| 136 | 
            +
                if (connection_error() || ephemeral()) return HpackParseResult();
         | 
| 137 | 
            +
                return *this;
         | 
| 138 | 
            +
              }
         | 
| 139 | 
            +
             | 
| 140 | 
            +
              static HpackParseResult FromStatus(HpackParseStatus status) {
         | 
| 141 | 
            +
                // Most statuses need some payloads, and we only need this functionality
         | 
| 142 | 
            +
                // rarely - so allow list the statuses that we can include here.
         | 
| 143 | 
            +
                switch (status) {
         | 
| 144 | 
            +
                  case HpackParseStatus::kUnbase64Failed:
         | 
| 145 | 
            +
                  case HpackParseStatus::kParseHuffFailed:
         | 
| 146 | 
            +
                    return HpackParseResult{status};
         | 
| 147 | 
            +
                  default:
         | 
| 148 | 
            +
                    Crash(
         | 
| 149 | 
            +
                        absl::StrCat("Invalid HpackParseStatus for FromStatus: ", status));
         | 
| 150 | 
            +
                }
         | 
| 151 | 
            +
              }
         | 
| 152 | 
            +
             | 
| 153 | 
            +
              static HpackParseResult FromStatusWithKey(HpackParseStatus status,
         | 
| 154 | 
            +
                                                        absl::string_view key) {
         | 
| 155 | 
            +
                auto r = FromStatus(status);
         | 
| 156 | 
            +
                r.key_ = std::string(key);
         | 
| 157 | 
            +
                return r;
         | 
| 158 | 
            +
              }
         | 
| 159 | 
            +
             | 
| 160 | 
            +
              static HpackParseResult MetadataParseError(absl::string_view key) {
         | 
| 161 | 
            +
                HpackParseResult r{HpackParseStatus::kMetadataParseError};
         | 
| 162 | 
            +
                r.key_ = std::string(key);
         | 
| 163 | 
            +
                return r;
         | 
| 164 | 
            +
              }
         | 
| 165 | 
            +
             | 
| 166 | 
            +
              static HpackParseResult AddBeforeTableSizeUpdated(uint32_t current_size,
         | 
| 167 | 
            +
                                                                uint32_t max_size) {
         | 
| 168 | 
            +
                HpackParseResult p{HpackParseStatus::kAddBeforeTableSizeUpdated};
         | 
| 169 | 
            +
                p.illegal_table_size_change_ =
         | 
| 170 | 
            +
                    IllegalTableSizeChange{current_size, max_size};
         | 
| 171 | 
            +
                return p;
         | 
| 172 | 
            +
              }
         | 
| 173 | 
            +
             | 
| 174 | 
            +
              static HpackParseResult MaliciousVarintEncodingError() {
         | 
| 175 | 
            +
                return HpackParseResult{HpackParseStatus::kMaliciousVarintEncoding};
         | 
| 176 | 
            +
              }
         | 
| 177 | 
            +
             | 
| 178 | 
            +
              static HpackParseResult IllegalHpackOpCode() {
         | 
| 179 | 
            +
                return HpackParseResult{HpackParseStatus::kIllegalHpackOpCode};
         | 
| 180 | 
            +
              }
         | 
| 181 | 
            +
             | 
| 182 | 
            +
              static HpackParseResult InvalidMetadataError(ValidateMetadataResult result,
         | 
| 183 | 
            +
                                                           absl::string_view key) {
         | 
| 184 | 
            +
                GPR_DEBUG_ASSERT(result != ValidateMetadataResult::kOk);
         | 
| 185 | 
            +
                HpackParseResult p{HpackParseStatus::kInvalidMetadata};
         | 
| 186 | 
            +
                p.key_ = std::string(key);
         | 
| 187 | 
            +
                p.validate_metadata_result_ = result;
         | 
| 188 | 
            +
                return p;
         | 
| 189 | 
            +
              }
         | 
| 190 | 
            +
             | 
| 191 | 
            +
              static HpackParseResult IncompleteHeaderAtBoundaryError() {
         | 
| 192 | 
            +
                return HpackParseResult{HpackParseStatus::kIncompleteHeaderAtBoundary};
         | 
| 193 | 
            +
              }
         | 
| 194 | 
            +
             | 
| 195 | 
            +
              static HpackParseResult VarintOutOfRangeError(uint32_t value,
         | 
| 196 | 
            +
                                                            uint8_t last_byte) {
         | 
| 197 | 
            +
                HpackParseResult p{HpackParseStatus::kVarintOutOfRange};
         | 
| 198 | 
            +
                p.varint_out_of_range_ = VarintOutOfRange{last_byte, value};
         | 
| 199 | 
            +
                return p;
         | 
| 200 | 
            +
              }
         | 
| 201 | 
            +
             | 
| 202 | 
            +
              static HpackParseResult InvalidHpackIndexError(uint32_t index) {
         | 
| 203 | 
            +
                HpackParseResult p{HpackParseStatus::kInvalidHpackIndex};
         | 
| 204 | 
            +
                p.invalid_hpack_index_ = index;
         | 
| 205 | 
            +
                return p;
         | 
| 206 | 
            +
              }
         | 
| 207 | 
            +
             | 
| 208 | 
            +
              static HpackParseResult IllegalTableSizeChangeError(uint32_t new_size,
         | 
| 209 | 
            +
                                                                  uint32_t max_size) {
         | 
| 210 | 
            +
                HpackParseResult p{HpackParseStatus::kIllegalTableSizeChange};
         | 
| 211 | 
            +
                p.illegal_table_size_change_ = IllegalTableSizeChange{new_size, max_size};
         | 
| 212 | 
            +
                return p;
         | 
| 213 | 
            +
              }
         | 
| 214 | 
            +
             | 
| 215 | 
            +
              static HpackParseResult TooManyDynamicTableSizeChangesError() {
         | 
| 216 | 
            +
                return HpackParseResult{HpackParseStatus::kTooManyDynamicTableSizeChanges};
         | 
| 217 | 
            +
              }
         | 
| 218 | 
            +
             | 
| 219 | 
            +
              static HpackParseResult SoftMetadataLimitExceededError(
         | 
| 220 | 
            +
                  grpc_metadata_batch* metadata, uint32_t frame_length, uint32_t limit) {
         | 
| 221 | 
            +
                HpackParseResult p{HpackParseStatus::kSoftMetadataLimitExceeded};
         | 
| 222 | 
            +
                p.metadata_limit_exceeded_ =
         | 
| 223 | 
            +
                    MetadataLimitExceeded{frame_length, limit, metadata};
         | 
| 224 | 
            +
                return p;
         | 
| 225 | 
            +
              }
         | 
| 226 | 
            +
             | 
| 227 | 
            +
              static HpackParseResult HardMetadataLimitExceededError(
         | 
| 228 | 
            +
                  grpc_metadata_batch* metadata, uint32_t frame_length, uint32_t limit) {
         | 
| 229 | 
            +
                HpackParseResult p{HpackParseStatus::kHardMetadataLimitExceeded};
         | 
| 230 | 
            +
                p.metadata_limit_exceeded_ =
         | 
| 231 | 
            +
                    MetadataLimitExceeded{frame_length, limit, metadata};
         | 
| 232 | 
            +
                return p;
         | 
| 233 | 
            +
              }
         | 
| 234 | 
            +
             | 
| 235 | 
            +
              static HpackParseResult HardMetadataLimitExceededByKeyError(
         | 
| 236 | 
            +
                  uint32_t key_length, uint32_t limit) {
         | 
| 237 | 
            +
                HpackParseResult p{HpackParseStatus::kHardMetadataLimitExceededByKey};
         | 
| 238 | 
            +
                p.metadata_limit_exceeded_by_atom_ =
         | 
| 239 | 
            +
                    MetadataLimitExceededByAtom{key_length, limit};
         | 
| 240 | 
            +
                return p;
         | 
| 241 | 
            +
              }
         | 
| 242 | 
            +
             | 
| 243 | 
            +
              static HpackParseResult HardMetadataLimitExceededByValueError(
         | 
| 244 | 
            +
                  absl::string_view key, uint32_t value_length, uint32_t limit) {
         | 
| 245 | 
            +
                HpackParseResult p{HpackParseStatus::kHardMetadataLimitExceededByValue};
         | 
| 246 | 
            +
                p.metadata_limit_exceeded_by_atom_ =
         | 
| 247 | 
            +
                    MetadataLimitExceededByAtom{value_length, limit};
         | 
| 248 | 
            +
                p.key_ = std::string(key);
         | 
| 249 | 
            +
                return p;
         | 
| 250 | 
            +
              }
         | 
| 251 | 
            +
             | 
| 252 | 
            +
              // Compute the absl::Status that goes along with this HpackParseResult.
         | 
| 253 | 
            +
              // (may be cached, so this is not thread safe)
         | 
| 254 | 
            +
              absl::Status Materialize() const;
         | 
| 255 | 
            +
             | 
| 256 | 
            +
             private:
         | 
| 257 | 
            +
              explicit HpackParseResult(HpackParseStatus status) : status_(status) {}
         | 
| 258 | 
            +
              absl::Status BuildMaterialized() const;
         | 
| 259 | 
            +
             | 
| 260 | 
            +
              struct VarintOutOfRange {
         | 
| 261 | 
            +
                uint8_t last_byte;
         | 
| 262 | 
            +
                uint32_t value;
         | 
| 263 | 
            +
              };
         | 
| 264 | 
            +
             | 
| 265 | 
            +
              struct MetadataLimitExceeded {
         | 
| 266 | 
            +
                uint32_t frame_length;
         | 
| 267 | 
            +
                uint32_t limit;
         | 
| 268 | 
            +
                grpc_metadata_batch* prior;
         | 
| 269 | 
            +
              };
         | 
| 270 | 
            +
             | 
| 271 | 
            +
              // atom here means one of either a key or a value - so this is used for when a
         | 
| 272 | 
            +
              // metadata limit is consumed by either of these.
         | 
| 273 | 
            +
              struct MetadataLimitExceededByAtom {
         | 
| 274 | 
            +
                uint32_t atom_length;
         | 
| 275 | 
            +
                uint32_t limit;
         | 
| 276 | 
            +
              };
         | 
| 277 | 
            +
             | 
| 278 | 
            +
              struct IllegalTableSizeChange {
         | 
| 279 | 
            +
                uint32_t new_size;
         | 
| 280 | 
            +
                uint32_t max_size;
         | 
| 281 | 
            +
              };
         | 
| 282 | 
            +
             | 
| 283 | 
            +
              class StatusWrapper {
         | 
| 284 | 
            +
               public:
         | 
| 285 | 
            +
                explicit StatusWrapper(HpackParseStatus status) : status_(status) {}
         | 
| 286 | 
            +
             | 
| 287 | 
            +
                StatusWrapper(const StatusWrapper&) = default;
         | 
| 288 | 
            +
                StatusWrapper& operator=(const StatusWrapper&) = default;
         | 
| 289 | 
            +
                StatusWrapper(StatusWrapper&& other) noexcept
         | 
| 290 | 
            +
                    : status_(std::exchange(other.status_, HpackParseStatus::kMovedFrom)) {}
         | 
| 291 | 
            +
                StatusWrapper& operator=(StatusWrapper&& other) noexcept {
         | 
| 292 | 
            +
                  status_ = std::exchange(other.status_, HpackParseStatus::kMovedFrom);
         | 
| 293 | 
            +
                  return *this;
         | 
| 294 | 
            +
                }
         | 
| 295 | 
            +
             | 
| 296 | 
            +
                HpackParseStatus get() const { return status_; }
         | 
| 297 | 
            +
             | 
| 298 | 
            +
               private:
         | 
| 299 | 
            +
                HpackParseStatus status_;
         | 
| 300 | 
            +
              };
         | 
| 301 | 
            +
             | 
| 302 | 
            +
              StatusWrapper status_;
         | 
| 303 | 
            +
              union {
         | 
| 304 | 
            +
                // Set if status == kInvalidMetadata
         | 
| 305 | 
            +
                ValidateMetadataResult validate_metadata_result_;
         | 
| 306 | 
            +
                // Set if status == kVarintOutOfRange
         | 
| 307 | 
            +
                VarintOutOfRange varint_out_of_range_;
         | 
| 308 | 
            +
                // Set if status == kInvalidHpackIndex
         | 
| 309 | 
            +
                uint32_t invalid_hpack_index_;
         | 
| 310 | 
            +
                // Set if status == kHardMetadataLimitExceeded or
         | 
| 311 | 
            +
                // kSoftMetadataLimitExceeded
         | 
| 312 | 
            +
                MetadataLimitExceeded metadata_limit_exceeded_;
         | 
| 313 | 
            +
                // Set if status == kHardMetadataLimitExceededByKey or
         | 
| 314 | 
            +
                // kHardMetadataLimitExceededByValue
         | 
| 315 | 
            +
                MetadataLimitExceededByAtom metadata_limit_exceeded_by_atom_;
         | 
| 316 | 
            +
                // Set if status == kIllegalTableSizeChange
         | 
| 317 | 
            +
                IllegalTableSizeChange illegal_table_size_change_;
         | 
| 318 | 
            +
              };
         | 
| 319 | 
            +
              std::string key_;
         | 
| 320 | 
            +
              mutable absl::optional<absl::Status> materialized_status_;
         | 
| 321 | 
            +
            };
         | 
| 322 | 
            +
             | 
| 323 | 
            +
            }  // namespace grpc_core
         | 
| 324 | 
            +
             | 
| 325 | 
            +
            #endif  // GRPC_SRC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_HPACK_PARSE_RESULT_H
         |