grpc 1.83.0 → 1.83.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,6 +21,7 @@
21
21
  #include <grpc/support/port_platform.h>
22
22
  #include <inttypes.h>
23
23
 
24
+ #include <cstdint>
24
25
  #include <functional>
25
26
  #include <memory>
26
27
  #include <optional>
@@ -44,6 +45,7 @@
44
45
  #include "src/core/lib/surface/call.h"
45
46
  #include "src/core/lib/transport/transport.h"
46
47
  #include "src/core/telemetry/call_tracer.h"
48
+ #include "src/core/transport/message_size_service_config.h"
47
49
  #include "src/core/util/grpc_check.h"
48
50
  #include "src/core/util/latent_see.h"
49
51
  #include "absl/status/status.h"
@@ -75,8 +77,6 @@ ServerCompressionFilter::Create(const ChannelArgs& args, ChannelFilter::Args) {
75
77
 
76
78
  ChannelCompression::ChannelCompression(const ChannelArgs& args)
77
79
  : max_recv_size_(GetMaxRecvSizeFromChannelArgs(args)),
78
- message_size_service_config_parser_index_(
79
- MessageSizeParser::ParserIndex()),
80
80
  default_compression_algorithm_(
81
81
  DefaultCompressionAlgorithmFromChannelArgs(args).value_or(
82
82
  GRPC_COMPRESS_NONE)),
@@ -118,26 +118,25 @@ MessageHandle ChannelCompression::CompressMessage(
118
118
  return message;
119
119
  }
120
120
  // Try to compress the payload.
121
- SliceBuffer tmp;
122
- SliceBuffer* payload = message->payload();
123
- bool did_compress = grpc_msg_compress(algorithm, payload->c_slice_buffer(),
124
- tmp.c_slice_buffer());
121
+ std::optional<SliceBuffer> compressed =
122
+ MessageCompress(algorithm, *message->payload());
123
+
125
124
  // If we achieved compression send it as compressed, otherwise send it as (to
126
125
  // avoid spending cycles on the receiver decompressing).
127
- if (did_compress) {
126
+ if (compressed.has_value()) {
128
127
  if (GRPC_TRACE_FLAG_ENABLED(compression)) {
129
128
  const char* algo_name;
130
- const size_t before_size = payload->Length();
131
- const size_t after_size = tmp.Length();
129
+ GRPC_CHECK(grpc_compression_algorithm_name(algorithm, &algo_name));
130
+ const size_t before_size = message->payload()->Length();
131
+ const size_t after_size = compressed->Length();
132
132
  const float savings_ratio = 1.0f - (static_cast<float>(after_size) /
133
133
  static_cast<float>(before_size));
134
- GRPC_CHECK(grpc_compression_algorithm_name(algorithm, &algo_name));
135
134
  LOG(INFO) << absl::StrFormat(
136
135
  "Compressed[%s] %" PRIuPTR " bytes vs. %" PRIuPTR
137
136
  " bytes (%.2f%% savings)",
138
137
  algo_name, before_size, after_size, 100 * savings_ratio);
139
138
  }
140
- tmp.Swap(payload);
139
+ *message->payload() = std::move(*compressed);
141
140
  flags |= GRPC_WRITE_INTERNAL_COMPRESS;
142
141
  if (call_tracer != nullptr) {
143
142
  call_tracer->RecordSendCompressedMessage(*message);
@@ -148,7 +147,7 @@ MessageHandle ChannelCompression::CompressMessage(
148
147
  GRPC_CHECK(grpc_compression_algorithm_name(algorithm, &algo_name));
149
148
  LOG(INFO) << "Algorithm '" << algo_name
150
149
  << "' enabled but decided not to compress. Input size: "
151
- << payload->Length();
150
+ << message->payload()->Length();
152
151
  }
153
152
  }
154
153
  return message;
@@ -180,15 +179,17 @@ absl::StatusOr<MessageHandle> ChannelCompression::DecompressMessage(
180
179
  return std::move(message);
181
180
  }
182
181
  // Try to decompress the payload.
183
- SliceBuffer decompressed_slices;
184
- if (grpc_msg_decompress(args.algorithm, message->payload()->c_slice_buffer(),
185
- decompressed_slices.c_slice_buffer()) == 0) {
186
- return absl::InternalError(
187
- absl::StrCat("Unexpected error decompressing data for algorithm ",
188
- CompressionAlgorithmAsString(args.algorithm)));
182
+ std::optional<uint32_t> max_output_size = IsMessageSizeRefactoringEnabled()
183
+ ? args.max_recv_message_length
184
+ : std::nullopt;
185
+ absl::StatusOr<SliceBuffer> decompressed_slices =
186
+ MessageDecompress(args.algorithm, *message->payload(), max_output_size);
187
+ if (!decompressed_slices.ok()) {
188
+ return decompressed_slices.status();
189
189
  }
190
- // Swap the decompressed slices into the message.
191
- message->payload()->Swap(&decompressed_slices);
190
+
191
+ // Move the decompressed slices into the message.
192
+ *message->payload() = std::move(*decompressed_slices);
192
193
  message->mutable_flags() &= ~GRPC_WRITE_INTERNAL_COMPRESS;
193
194
  message->mutable_flags() |= GRPC_WRITE_INTERNAL_TEST_ONLY_WAS_COMPRESSED;
194
195
  if (call_tracer != nullptr) {
@@ -213,18 +214,10 @@ grpc_compression_algorithm ChannelCompression::HandleOutgoingMetadata(
213
214
  ChannelCompression::DecompressArgs ChannelCompression::HandleIncomingMetadata(
214
215
  const grpc_metadata_batch& incoming_metadata) {
215
216
  // Configure max receive size.
216
- auto max_recv_message_length = max_recv_size_;
217
- const MessageSizeParsedConfig* limits =
218
- MessageSizeParsedConfig::GetFromCallContext(
219
- GetContext<Arena>(), message_size_service_config_parser_index_);
220
- if (limits != nullptr && limits->max_recv_size().has_value() &&
221
- (!max_recv_message_length.has_value() ||
222
- *limits->max_recv_size() < *max_recv_message_length)) {
223
- max_recv_message_length = limits->max_recv_size();
224
- }
225
- return DecompressArgs{incoming_metadata.get(GrpcEncodingMetadata())
226
- .value_or(GRPC_COMPRESS_NONE),
227
- max_recv_message_length};
217
+ return DecompressArgs{
218
+ incoming_metadata.get(GrpcEncodingMetadata())
219
+ .value_or(GRPC_COMPRESS_NONE),
220
+ GetMaxRecvSizeFromCallContext(GetContext<Arena>(), max_recv_size_)};
228
221
  }
229
222
 
230
223
  void ClientCompressionFilter::Call::OnClientInitialMetadata(
@@ -107,7 +107,6 @@ class ChannelCompression {
107
107
  private:
108
108
  // Max receive message length, if set.
109
109
  std::optional<uint32_t> max_recv_size_;
110
- size_t message_size_service_config_parser_index_;
111
110
  // The default, channel-level, compression algorithm.
112
111
  grpc_compression_algorithm default_compression_algorithm_;
113
112
  // Enabled compression algorithms.
@@ -106,6 +106,7 @@
106
106
  #include "src/core/telemetry/stats_data.h"
107
107
  #include "src/core/telemetry/tcp_tracer.h"
108
108
  #include "src/core/transport/auth_context.h"
109
+ #include "src/core/transport/message_size_service_config.h"
109
110
  #include "src/core/util/bitset.h"
110
111
  #include "src/core/util/crash.h"
111
112
  #include "src/core/util/debug_location.h"
@@ -816,6 +817,7 @@ grpc_chttp2_transport::grpc_chttp2_transport(
816
817
  Ref(), &init_keepalive_ping_locked),
817
818
  absl::OkStatus());
818
819
 
820
+ // TODO(tjagtap) : [PH2][P0] : Do this for PH2.
819
821
  if (flow_control.bdp_probe()) {
820
822
  bdp_ping_blocked = true;
821
823
  grpc_chttp2_act_on_flowctl_action(flow_control.PeriodicUpdate(), this,
@@ -859,6 +861,9 @@ grpc_chttp2_transport::grpc_chttp2_transport(
859
861
  epte->SetSocketNode(channelz_socket);
860
862
  }
861
863
  }
864
+
865
+ max_recv_message_length =
866
+ grpc_core::GetMaxRecvSizeFromChannelArgs(channel_args);
862
867
  }
863
868
 
864
869
  static void destroy_transport_locked(void* tp, grpc_error_handle /*error*/) {
@@ -879,6 +884,10 @@ static void close_transport_locked(grpc_chttp2_transport* t,
879
884
  grpc_error_handle error) {
880
885
  end_all_the_calls(t, error);
881
886
  cancel_pings(t, error);
887
+ if (t->transport_framing_endpoint_extension != nullptr) {
888
+ t->transport_framing_endpoint_extension->SetSendFrameCallback(nullptr);
889
+ t->transport_framing_endpoint_extension = nullptr;
890
+ }
882
891
  if (t->closed_with_error.ok()) {
883
892
  if (!grpc_error_has_clear_grpc_status(error)) {
884
893
  error =
@@ -1507,7 +1516,8 @@ static grpc_closure* add_closure_barrier(grpc_closure* closure) {
1507
1516
  return closure;
1508
1517
  }
1509
1518
 
1510
- static void null_then_sched_closure(grpc_closure** closure) {
1519
+ static void null_then_sched_closure_with_error(grpc_closure** closure,
1520
+ grpc_error_handle error) {
1511
1521
  grpc_closure* c = *closure;
1512
1522
  *closure = nullptr;
1513
1523
  // null_then_schedule_closure might be run during a start_batch which might
@@ -1516,7 +1526,11 @@ static void null_then_sched_closure(grpc_closure** closure) {
1516
1526
  // completion, have the application see it, and make a new operation on the
1517
1527
  // call which recycles the batch BEFORE the call to start_batch completes,
1518
1528
  // forcing a race.
1519
- grpc_core::ExecCtx::Run(DEBUG_LOCATION, c, absl::OkStatus());
1529
+ grpc_core::ExecCtx::Run(DEBUG_LOCATION, c, error);
1530
+ }
1531
+
1532
+ static void null_then_sched_closure(grpc_closure** closure) {
1533
+ null_then_sched_closure_with_error(closure, absl::OkStatus());
1520
1534
  }
1521
1535
 
1522
1536
  void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
@@ -2343,6 +2357,8 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_chttp2_transport* t,
2343
2357
  t->registered_method_matcher_cb(t->accept_stream_cb_user_data,
2344
2358
  s->recv_initial_metadata);
2345
2359
  }
2360
+ s->max_recv_message_length =
2361
+ GetMaxRecvSizeFromCallContext(s->arena, t->max_recv_message_length);
2346
2362
  null_then_sched_closure(&s->recv_initial_metadata_ready);
2347
2363
  }
2348
2364
  }
@@ -2415,7 +2431,36 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* t,
2415
2431
  *s->call_failed_before_recv_message =
2416
2432
  (s->published_metadata[1] != GRPC_METADATA_PUBLISHED_AT_CLOSE);
2417
2433
  }
2418
- null_then_sched_closure(&s->recv_message_ready);
2434
+ if (s->seen_error && s->message_size_limit_exceeded) {
2435
+ null_then_sched_closure_with_error(&s->recv_message_ready, error);
2436
+ } else {
2437
+ null_then_sched_closure(&s->recv_message_ready);
2438
+ }
2439
+ } else if (s->seen_error && s->message_size_limit_exceeded) {
2440
+ null_then_sched_closure_with_error(&s->recv_message_ready, error);
2441
+ }
2442
+
2443
+ if (grpc_core::IsMessageSizeRefactoringEnabled() && s->seen_error &&
2444
+ s->message_size_limit_exceeded) {
2445
+ s->message_size_limit_exceeded = false;
2446
+ // Explicitly cancel the stream to fail the RPC immediately.
2447
+ // We delay the cancellation until the recv_message_ready closure is
2448
+ // executed to prevent re-entrancy issues. When the HTTP/2 frame deframer
2449
+ // in `grpc_deframe_unprocessed_incoming_frames`
2450
+ // returns a size violation error, invoking `grpc_chttp2_cancel_stream`
2451
+ // immediately triggers `grpc_chttp2_mark_stream_closed`. This in turn
2452
+ // synchronously re-enters `grpc_chttp2_maybe_complete_recv_message` while
2453
+ // the original deframing loop is still active on the call stack.
2454
+ //
2455
+ // Because the re-entrant invocation observes that the incoming frame
2456
+ // storage has been cleared but `s->recv_message_ready` is still non-null,
2457
+ // it preemptively schedules the closure as a standard/non-error stream
2458
+ // termination (i.e., via `null_then_sched_closure(...,
2459
+ // absl::OkStatus())`). By the time control returns to the initial (outer)
2460
+ // deframing loop to execute `null_then_sched_closure_with_error`, the
2461
+ // closure pointer is already null, causing the original error context to
2462
+ // be discarded.
2463
+ grpc_chttp2_cancel_stream(t, s, error, true, nullptr);
2419
2464
  }
2420
2465
  }();
2421
2466
 
@@ -48,6 +48,7 @@ absl::Status grpc_chttp2_data_parser_begin_frame(uint8_t flags,
48
48
  } else {
49
49
  s->received_last_frame = false;
50
50
  }
51
+ ++s->num_frames;
51
52
 
52
53
  return absl::OkStatus();
53
54
  }
@@ -123,6 +124,24 @@ grpc_core::Poll<grpc_error_handle> grpc_deframe_unprocessed_incoming_frames(
123
124
  (static_cast<uint32_t>(header[3]) << 8) |
124
125
  static_cast<uint32_t>(header[4]);
125
126
 
127
+ if (grpc_core::IsMessageSizeRefactoringEnabled()) {
128
+ if (s->max_recv_message_length.has_value() &&
129
+ length > *(s->max_recv_message_length)) {
130
+ error = GRPC_ERROR_CREATE(
131
+ absl::StrFormat("%s: Received message larger than max (%d vs. %u)",
132
+ s->t->is_client ? "CLIENT" : "SERVER", length,
133
+ *(s->max_recv_message_length)));
134
+ error = grpc_error_set_int(error, grpc_core::StatusIntProperty::kStreamId,
135
+ static_cast<intptr_t>(s->id));
136
+ // Attach the explicit gRPC status code to fail the RPC correctly.
137
+ error =
138
+ grpc_error_set_int(error, grpc_core::StatusIntProperty::kRpcStatus,
139
+ GRPC_STATUS_RESOURCE_EXHAUSTED);
140
+ s->message_size_limit_exceeded = true;
141
+ return error;
142
+ }
143
+ }
144
+
126
145
  if (slices->length < length + GRPC_HEADER_SIZE_IN_BYTES) {
127
146
  if (min_progress_size != nullptr) {
128
147
  *min_progress_size = length + GRPC_HEADER_SIZE_IN_BYTES - slices->length;
@@ -138,6 +157,7 @@ grpc_core::Poll<grpc_error_handle> grpc_deframe_unprocessed_incoming_frames(
138
157
  grpc_slice_buffer_move_first_into_buffer(slices, GRPC_HEADER_SIZE_IN_BYTES,
139
158
  header);
140
159
  grpc_slice_buffer_move_first(slices, length, stream_out->c_slice_buffer());
160
+ s->num_frames = 0;
141
161
  }
142
162
 
143
163
  return absl::OkStatus();
@@ -148,8 +168,20 @@ grpc_error_handle grpc_chttp2_data_parser_parse(void* /*parser*/,
148
168
  grpc_chttp2_stream* s,
149
169
  const grpc_slice& slice,
150
170
  int is_last) {
151
- grpc_core::CSliceRef(slice);
152
- grpc_slice_buffer_add(&s->frame_storage, slice);
171
+ const size_t slice_len = GRPC_SLICE_LENGTH(slice);
172
+ bool is_small_frame = 0 < slice_len && slice_len < GRPC_SLICE_INLINED_SIZE;
173
+ bool multiple_small_frames =
174
+ (s->num_frames >= 64) &&
175
+ ((s->frame_storage.length / s->num_frames) < GRPC_SLICE_INLINED_SIZE);
176
+ if (GPR_UNLIKELY(multiple_small_frames && is_small_frame &&
177
+ grpc_core::IsHeaderDataFrameEnabled())) {
178
+ uint8_t* append_ptr =
179
+ grpc_slice_buffer_tiny_add(&s->frame_storage, slice_len);
180
+ memcpy(append_ptr, GRPC_SLICE_START_PTR(slice), slice_len);
181
+ } else {
182
+ grpc_core::CSliceRef(slice);
183
+ grpc_slice_buffer_add(&s->frame_storage, slice);
184
+ }
153
185
  grpc_chttp2_maybe_complete_recv_message(t, s);
154
186
 
155
187
  if (is_last) {
@@ -31,11 +31,15 @@
31
31
  #include "absl/strings/string_view.h"
32
32
 
33
33
  void grpc_chttp2_goaway_parser_init(grpc_chttp2_goaway_parser* p) {
34
- p->debug_data = nullptr;
34
+ if (!grpc_core::IsPh2Perf01Enabled()) {
35
+ p->debug_data = nullptr;
36
+ }
35
37
  }
36
38
 
37
39
  void grpc_chttp2_goaway_parser_destroy(grpc_chttp2_goaway_parser* p) {
38
- gpr_free(p->debug_data);
40
+ if (!grpc_core::IsPh2Perf01Enabled()) {
41
+ gpr_free(p->debug_data);
42
+ }
39
43
  }
40
44
 
41
45
  grpc_error_handle grpc_chttp2_goaway_parser_begin_frame(
@@ -45,10 +49,14 @@ grpc_error_handle grpc_chttp2_goaway_parser_begin_frame(
45
49
  absl::StrFormat("goaway frame too short (%d bytes)", length));
46
50
  }
47
51
 
48
- gpr_free(p->debug_data);
49
52
  p->debug_length = length - 8;
50
- p->debug_data = static_cast<char*>(gpr_malloc(p->debug_length));
51
- p->debug_pos = 0;
53
+ if (grpc_core::IsPh2Perf01Enabled()) {
54
+ p->debug_slice_buffer.Clear();
55
+ } else {
56
+ gpr_free(p->debug_data);
57
+ p->debug_data = static_cast<char*>(gpr_malloc(p->debug_length));
58
+ p->debug_pos = 0;
59
+ }
52
60
  p->state = GRPC_CHTTP2_GOAWAY_LSI0;
53
61
  return absl::OkStatus();
54
62
  }
@@ -130,24 +138,48 @@ grpc_error_handle grpc_chttp2_goaway_parser_parse(void* parser,
130
138
  ++cur;
131
139
  [[fallthrough]];
132
140
  case GRPC_CHTTP2_GOAWAY_DEBUG:
133
- if (end != cur) {
134
- memcpy(p->debug_data + p->debug_pos, cur,
135
- static_cast<size_t>(end - cur));
136
- }
137
- GRPC_CHECK((size_t)(end - cur) < UINT32_MAX - p->debug_pos);
138
- p->debug_pos += static_cast<uint32_t>(end - cur);
139
- p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
140
- if (is_last) {
141
- t->http2_ztrace_collector.Append([p]() {
142
- return grpc_core::H2GoAwayTrace<true>{
143
- p->last_stream_id, p->error_code,
144
- std::string(absl::string_view(p->debug_data, p->debug_length))};
145
- });
146
- grpc_chttp2_add_incoming_goaway(
147
- t, p->error_code, p->last_stream_id,
148
- absl::string_view(p->debug_data, p->debug_length));
149
- gpr_free(p->debug_data);
150
- p->debug_data = nullptr;
141
+ if (grpc_core::IsPh2Perf01Enabled()) {
142
+ if (end != cur) {
143
+ p->debug_slice_buffer.AppendIndexed(
144
+ grpc_core::Slice::FromCopiedBuffer(
145
+ cur, static_cast<size_t>(end - cur)));
146
+ }
147
+ GRPC_CHECK(p->debug_slice_buffer.Length() <= p->debug_length);
148
+ p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
149
+ if (is_last) {
150
+ std::string debug_str = p->debug_slice_buffer.JoinIntoString();
151
+
152
+ grpc_chttp2_add_incoming_goaway(t, p->error_code, p->last_stream_id,
153
+ absl::string_view(debug_str));
154
+
155
+ t->http2_ztrace_collector.Append(
156
+ [last_stream_id = p->last_stream_id, error_code = p->error_code,
157
+ debug_str = std::move(debug_str)]() mutable {
158
+ return grpc_core::H2GoAwayTrace<true>{
159
+ last_stream_id, error_code, std::move(debug_str)};
160
+ });
161
+ p->debug_slice_buffer.Clear();
162
+ }
163
+ } else {
164
+ if (end != cur) {
165
+ memcpy(p->debug_data + p->debug_pos, cur,
166
+ static_cast<size_t>(end - cur));
167
+ }
168
+ GRPC_CHECK((size_t)(end - cur) < UINT32_MAX - p->debug_pos);
169
+ p->debug_pos += static_cast<uint32_t>(end - cur);
170
+ p->state = GRPC_CHTTP2_GOAWAY_DEBUG;
171
+ if (is_last) {
172
+ t->http2_ztrace_collector.Append([p]() {
173
+ return grpc_core::H2GoAwayTrace<true>{
174
+ p->last_stream_id, p->error_code,
175
+ std::string(absl::string_view(p->debug_data, p->debug_length))};
176
+ });
177
+ grpc_chttp2_add_incoming_goaway(
178
+ t, p->error_code, p->last_stream_id,
179
+ absl::string_view(p->debug_data, p->debug_length));
180
+ gpr_free(p->debug_data);
181
+ p->debug_data = nullptr;
182
+ }
151
183
  }
152
184
  return absl::OkStatus();
153
185
  }
@@ -44,6 +44,7 @@ struct grpc_chttp2_goaway_parser {
44
44
  uint32_t last_stream_id;
45
45
  uint32_t error_code;
46
46
  char* debug_data;
47
+ grpc_core::SliceBuffer debug_slice_buffer;
47
48
  uint32_t debug_length;
48
49
  uint32_t debug_pos;
49
50
  };
@@ -629,6 +629,8 @@ struct grpc_chttp2_transport final : public grpc_core::FilterStackTransport,
629
629
 
630
630
  GPR_NO_UNIQUE_ADDRESS grpc_core::latent_see::Flow write_flow;
631
631
 
632
+ std::optional<uint32_t> max_recv_message_length;
633
+
632
634
  // Current mitigation engine, retrieved once per connection.
633
635
  grpc_core::RefCountedPtr<grpc_core::MitigationEngine> mitigation_engine;
634
636
  };
@@ -718,6 +720,7 @@ struct grpc_chttp2_stream {
718
720
  grpc_metadata_batch trailing_metadata_buffer;
719
721
 
720
722
  grpc_slice_buffer frame_storage; // protected by t combiner
723
+ size_t num_frames = 0; // protected by t combiner
721
724
 
722
725
  grpc_core::Timestamp deadline = grpc_core::Timestamp::InfFuture();
723
726
 
@@ -777,6 +780,9 @@ struct grpc_chttp2_stream {
777
780
  // The last time a stream window update was received.
778
781
  grpc_core::Timestamp last_window_update_time =
779
782
  grpc_core::Timestamp::InfPast();
783
+
784
+ bool message_size_limit_exceeded = false;
785
+ std::optional<uint32_t> max_recv_message_length;
780
786
  };
781
787
 
782
788
  /// Transport writing call flow:
@@ -430,6 +430,14 @@ static grpc_error_handle init_frame_parser(grpc_chttp2_transport* t,
430
430
  t->incoming_frame_type));
431
431
  }
432
432
  t->is_first_frame = false;
433
+
434
+ if (grpc_core::IsPh2Perf01Enabled() &&
435
+ t->incoming_frame_size > t->settings.acked().max_frame_size()) {
436
+ return GRPC_ERROR_CREATE(absl::StrFormat(
437
+ "Frame size %d is larger than max frame size %d",
438
+ t->incoming_frame_size, t->settings.acked().max_frame_size()));
439
+ }
440
+
433
441
  if (t->expect_continuation_stream_id != 0) {
434
442
  if (t->incoming_frame_type != GRPC_CHTTP2_FRAME_CONTINUATION) {
435
443
  return GRPC_ERROR_CREATE(