grpc 1.82.0 → 1.82.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.
@@ -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"
@@ -811,6 +812,7 @@ grpc_chttp2_transport::grpc_chttp2_transport(
811
812
  Ref(), &init_keepalive_ping_locked),
812
813
  absl::OkStatus());
813
814
 
815
+ // TODO(tjagtap) : [PH2][P0] : Do this for PH2.
814
816
  if (flow_control.bdp_probe()) {
815
817
  bdp_ping_blocked = true;
816
818
  grpc_chttp2_act_on_flowctl_action(flow_control.PeriodicUpdate(), this,
@@ -854,6 +856,9 @@ grpc_chttp2_transport::grpc_chttp2_transport(
854
856
  epte->SetSocketNode(channelz_socket);
855
857
  }
856
858
  }
859
+
860
+ max_recv_message_length =
861
+ grpc_core::GetMaxRecvSizeFromChannelArgs(channel_args);
857
862
  }
858
863
 
859
864
  static void destroy_transport_locked(void* tp, grpc_error_handle /*error*/) {
@@ -874,6 +879,10 @@ static void close_transport_locked(grpc_chttp2_transport* t,
874
879
  grpc_error_handle error) {
875
880
  end_all_the_calls(t, error);
876
881
  cancel_pings(t, error);
882
+ if (t->transport_framing_endpoint_extension != nullptr) {
883
+ t->transport_framing_endpoint_extension->SetSendFrameCallback(nullptr);
884
+ t->transport_framing_endpoint_extension = nullptr;
885
+ }
877
886
  if (t->closed_with_error.ok()) {
878
887
  if (!grpc_error_has_clear_grpc_status(error)) {
879
888
  error =
@@ -1505,7 +1514,8 @@ static grpc_closure* add_closure_barrier(grpc_closure* closure) {
1505
1514
  return closure;
1506
1515
  }
1507
1516
 
1508
- static void null_then_sched_closure(grpc_closure** closure) {
1517
+ static void null_then_sched_closure_with_error(grpc_closure** closure,
1518
+ grpc_error_handle error) {
1509
1519
  grpc_closure* c = *closure;
1510
1520
  *closure = nullptr;
1511
1521
  // null_then_schedule_closure might be run during a start_batch which might
@@ -1514,7 +1524,11 @@ static void null_then_sched_closure(grpc_closure** closure) {
1514
1524
  // completion, have the application see it, and make a new operation on the
1515
1525
  // call which recycles the batch BEFORE the call to start_batch completes,
1516
1526
  // forcing a race.
1517
- grpc_core::ExecCtx::Run(DEBUG_LOCATION, c, absl::OkStatus());
1527
+ grpc_core::ExecCtx::Run(DEBUG_LOCATION, c, error);
1528
+ }
1529
+
1530
+ static void null_then_sched_closure(grpc_closure** closure) {
1531
+ null_then_sched_closure_with_error(closure, absl::OkStatus());
1518
1532
  }
1519
1533
 
1520
1534
  void grpc_chttp2_complete_closure_step(grpc_chttp2_transport* t,
@@ -2341,6 +2355,8 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_chttp2_transport* t,
2341
2355
  t->registered_method_matcher_cb(t->accept_stream_cb_user_data,
2342
2356
  s->recv_initial_metadata);
2343
2357
  }
2358
+ s->max_recv_message_length =
2359
+ GetMaxRecvSizeFromCallContext(s->arena, t->max_recv_message_length);
2344
2360
  null_then_sched_closure(&s->recv_initial_metadata_ready);
2345
2361
  }
2346
2362
  }
@@ -2413,7 +2429,36 @@ void grpc_chttp2_maybe_complete_recv_message(grpc_chttp2_transport* t,
2413
2429
  *s->call_failed_before_recv_message =
2414
2430
  (s->published_metadata[1] != GRPC_METADATA_PUBLISHED_AT_CLOSE);
2415
2431
  }
2416
- null_then_sched_closure(&s->recv_message_ready);
2432
+ if (s->seen_error && s->message_size_limit_exceeded) {
2433
+ null_then_sched_closure_with_error(&s->recv_message_ready, error);
2434
+ } else {
2435
+ null_then_sched_closure(&s->recv_message_ready);
2436
+ }
2437
+ } else if (s->seen_error && s->message_size_limit_exceeded) {
2438
+ null_then_sched_closure_with_error(&s->recv_message_ready, error);
2439
+ }
2440
+
2441
+ if (grpc_core::IsMessageSizeRefactoringEnabled() && s->seen_error &&
2442
+ s->message_size_limit_exceeded) {
2443
+ s->message_size_limit_exceeded = false;
2444
+ // Explicitly cancel the stream to fail the RPC immediately.
2445
+ // We delay the cancellation until the recv_message_ready closure is
2446
+ // executed to prevent re-entrancy issues. When the HTTP/2 frame deframer
2447
+ // in `grpc_deframe_unprocessed_incoming_frames`
2448
+ // returns a size violation error, invoking `grpc_chttp2_cancel_stream`
2449
+ // immediately triggers `grpc_chttp2_mark_stream_closed`. This in turn
2450
+ // synchronously re-enters `grpc_chttp2_maybe_complete_recv_message` while
2451
+ // the original deframing loop is still active on the call stack.
2452
+ //
2453
+ // Because the re-entrant invocation observes that the incoming frame
2454
+ // storage has been cleared but `s->recv_message_ready` is still non-null,
2455
+ // it preemptively schedules the closure as a standard/non-error stream
2456
+ // termination (i.e., via `null_then_sched_closure(...,
2457
+ // absl::OkStatus())`). By the time control returns to the initial (outer)
2458
+ // deframing loop to execute `null_then_sched_closure_with_error`, the
2459
+ // closure pointer is already null, causing the original error context to
2460
+ // be discarded.
2461
+ grpc_chttp2_cancel_stream(t, s, error, true, nullptr);
2417
2462
  }
2418
2463
  }();
2419
2464
 
@@ -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
  };
@@ -625,6 +625,8 @@ struct grpc_chttp2_transport final : public grpc_core::FilterStackTransport,
625
625
 
626
626
  GPR_NO_UNIQUE_ADDRESS grpc_core::latent_see::Flow write_flow;
627
627
 
628
+ std::optional<uint32_t> max_recv_message_length;
629
+
628
630
  // Current mitigation engine, retrieved once per connection.
629
631
  grpc_core::RefCountedPtr<grpc_core::MitigationEngine> mitigation_engine;
630
632
  };
@@ -714,6 +716,7 @@ struct grpc_chttp2_stream {
714
716
  grpc_metadata_batch trailing_metadata_buffer;
715
717
 
716
718
  grpc_slice_buffer frame_storage; // protected by t combiner
719
+ size_t num_frames = 0; // protected by t combiner
717
720
 
718
721
  grpc_core::Timestamp deadline = grpc_core::Timestamp::InfFuture();
719
722
 
@@ -773,6 +776,9 @@ struct grpc_chttp2_stream {
773
776
  // The last time a stream window update was received.
774
777
  grpc_core::Timestamp last_window_update_time =
775
778
  grpc_core::Timestamp::InfPast();
779
+
780
+ bool message_size_limit_exceeded = false;
781
+ std::optional<uint32_t> max_recv_message_length;
776
782
  };
777
783
 
778
784
  /// 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(