grpc 1.54.0 → 1.54.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grpc might be problematic. Click here for more details.

@@ -28,15 +28,14 @@
28
28
  #include <vector>
29
29
 
30
30
  #include "absl/strings/match.h"
31
+ #include "absl/strings/str_cat.h"
31
32
  #include "absl/strings/string_view.h"
32
33
 
33
- #include <grpc/impl/compression_types.h>
34
34
  #include <grpc/slice.h>
35
- #include <grpc/status.h>
35
+ #include <grpc/support/log.h>
36
36
 
37
37
  #include "src/core/ext/transport/chttp2/transport/hpack_constants.h"
38
38
  #include "src/core/ext/transport/chttp2/transport/hpack_encoder_table.h"
39
- #include "src/core/lib/compression/compression_internal.h"
40
39
  #include "src/core/lib/gprpp/time.h"
41
40
  #include "src/core/lib/slice/slice.h"
42
41
  #include "src/core/lib/slice/slice_buffer.h"
@@ -46,6 +45,280 @@
46
45
 
47
46
  namespace grpc_core {
48
47
 
48
+ // Forward decl for encoder
49
+ class HPackCompressor;
50
+
51
+ namespace hpack_encoder_detail {
52
+
53
+ class Encoder {
54
+ public:
55
+ Encoder(HPackCompressor* compressor, bool use_true_binary_metadata,
56
+ SliceBuffer& output);
57
+
58
+ void Encode(const Slice& key, const Slice& value);
59
+ template <typename MetadataTrait>
60
+ void Encode(MetadataTrait, const typename MetadataTrait::ValueType& value);
61
+
62
+ void AdvertiseTableSizeChange();
63
+ void EmitIndexed(uint32_t index);
64
+ GRPC_MUST_USE_RESULT
65
+ uint32_t EmitLitHdrWithNonBinaryStringKeyIncIdx(Slice key_slice,
66
+ Slice value_slice);
67
+ GRPC_MUST_USE_RESULT
68
+ uint32_t EmitLitHdrWithBinaryStringKeyIncIdx(Slice key_slice,
69
+ Slice value_slice);
70
+ void EmitLitHdrWithBinaryStringKeyNotIdx(Slice key_slice, Slice value_slice);
71
+ void EmitLitHdrWithBinaryStringKeyNotIdx(uint32_t key_index,
72
+ Slice value_slice);
73
+ void EmitLitHdrWithNonBinaryStringKeyNotIdx(Slice key_slice,
74
+ Slice value_slice);
75
+
76
+ void EncodeAlwaysIndexed(uint32_t* index, absl::string_view key, Slice value,
77
+ size_t transport_length);
78
+ void EncodeIndexedKeyWithBinaryValue(uint32_t* index, absl::string_view key,
79
+ Slice value);
80
+
81
+ void EncodeRepeatingSliceValue(const absl::string_view& key,
82
+ const Slice& slice, uint32_t* index,
83
+ size_t max_compression_size);
84
+
85
+ HPackEncoderTable& hpack_table();
86
+
87
+ private:
88
+ const bool use_true_binary_metadata_;
89
+ HPackCompressor* const compressor_;
90
+ SliceBuffer& output_;
91
+ };
92
+
93
+ // Compressor is partially specialized on CompressionTraits, but leaves
94
+ // MetadataTrait as variable.
95
+ // Via MetadataMap::StatefulCompressor it builds compression state for
96
+ // HPackCompressor.
97
+ // Each trait compressor gets to have some persistent state across the channel
98
+ // (declared as Compressor member variables).
99
+ // The compressors expose a single method:
100
+ // void EncodeWith(MetadataTrait, const MetadataTrait::ValueType, Encoder*);
101
+ // This method figures out how to encode the value, and then delegates to
102
+ // Encoder to perform the encoding.
103
+ template <typename MetadataTrait, typename CompressonTraits>
104
+ class Compressor;
105
+
106
+ // No compression encoder: just emit the key and value as literals.
107
+ template <typename MetadataTrait>
108
+ class Compressor<MetadataTrait, NoCompressionCompressor> {
109
+ public:
110
+ void EncodeWith(MetadataTrait, const typename MetadataTrait::ValueType& value,
111
+ Encoder* encoder) {
112
+ const Slice& slice = MetadataValueAsSlice<MetadataTrait>(value);
113
+ if (absl::EndsWith(MetadataTrait::key(), "-bin")) {
114
+ encoder->EmitLitHdrWithBinaryStringKeyNotIdx(
115
+ Slice::FromStaticString(MetadataTrait::key()), slice.Ref());
116
+ } else {
117
+ encoder->EmitLitHdrWithNonBinaryStringKeyNotIdx(
118
+ Slice::FromStaticString(MetadataTrait::key()), slice.Ref());
119
+ }
120
+ }
121
+ };
122
+
123
+ // Frequent key with no value compression encoder
124
+ template <typename MetadataTrait>
125
+ class Compressor<MetadataTrait, FrequentKeyWithNoValueCompressionCompressor> {
126
+ public:
127
+ void EncodeWith(MetadataTrait, const typename MetadataTrait::ValueType& value,
128
+ Encoder* encoder) {
129
+ const Slice& slice = MetadataValueAsSlice<MetadataTrait>(value);
130
+ encoder->EncodeRepeatingSliceValue(MetadataTrait::key(), slice,
131
+ &some_sent_value_,
132
+ HPackEncoderTable::MaxEntrySize());
133
+ }
134
+
135
+ private:
136
+ // Some previously sent value with this tag.
137
+ uint32_t some_sent_value_ = 0;
138
+ };
139
+
140
+ // Helper to determine if two objects have the same identity.
141
+ // Equivalent here => equality, but equality does not imply equivalency.
142
+ // For example, two slices with the same contents are equal, but not
143
+ // equivalent.
144
+ // Used as a much faster check for equality than the full equality check,
145
+ // since many metadatum that are stable have the same root object in metadata
146
+ // maps.
147
+ template <typename T>
148
+ static bool IsEquivalent(T a, T b) {
149
+ return a == b;
150
+ }
151
+
152
+ template <typename T>
153
+ static bool IsEquivalent(const Slice& a, const Slice& b) {
154
+ return a.is_equivalent(b);
155
+ }
156
+
157
+ template <typename T>
158
+ static void SaveCopyTo(const T& value, T& copy) {
159
+ copy = value;
160
+ }
161
+
162
+ static inline void SaveCopyTo(const Slice& value, Slice& copy) {
163
+ copy = value.Ref();
164
+ }
165
+
166
+ template <typename MetadataTrait>
167
+ class Compressor<MetadataTrait, StableValueCompressor> {
168
+ public:
169
+ void EncodeWith(MetadataTrait, const typename MetadataTrait::ValueType& value,
170
+ Encoder* encoder) {
171
+ auto& table = encoder->hpack_table();
172
+ if (previously_sent_value_ == value &&
173
+ table.ConvertableToDynamicIndex(previously_sent_index_)) {
174
+ encoder->EmitIndexed(table.DynamicIndex(previously_sent_index_));
175
+ return;
176
+ }
177
+ previously_sent_index_ = 0;
178
+ auto key = MetadataTrait::key();
179
+ const Slice& value_slice = MetadataValueAsSlice<MetadataTrait>(value);
180
+ if (hpack_constants::SizeForEntry(key.size(), value_slice.size()) >
181
+ HPackEncoderTable::MaxEntrySize()) {
182
+ encoder->EmitLitHdrWithNonBinaryStringKeyNotIdx(
183
+ Slice::FromStaticString(key), value_slice.Ref());
184
+ return;
185
+ }
186
+ encoder->EncodeAlwaysIndexed(
187
+ &previously_sent_index_, key, value_slice.Ref(),
188
+ hpack_constants::SizeForEntry(key.size(), value_slice.size()));
189
+ SaveCopyTo(value, previously_sent_value_);
190
+ }
191
+
192
+ private:
193
+ // Previously sent value
194
+ typename MetadataTrait::ValueType previously_sent_value_{};
195
+ // And its index in the table
196
+ uint32_t previously_sent_index_ = 0;
197
+ };
198
+
199
+ template <typename MetadataTrait, typename MetadataTrait::ValueType known_value>
200
+ class Compressor<
201
+ MetadataTrait,
202
+ KnownValueCompressor<typename MetadataTrait::ValueType, known_value>> {
203
+ public:
204
+ void EncodeWith(MetadataTrait, const typename MetadataTrait::ValueType& value,
205
+ Encoder* encoder) {
206
+ if (value != known_value) {
207
+ gpr_log(GPR_ERROR, "%s",
208
+ absl::StrCat("Not encoding bad ", MetadataTrait::key(), " header")
209
+ .c_str());
210
+ return;
211
+ }
212
+ Slice encoded(MetadataTrait::Encode(known_value));
213
+ const auto encoded_length = encoded.length();
214
+ encoder->EncodeAlwaysIndexed(&previously_sent_index_, MetadataTrait::key(),
215
+ std::move(encoded),
216
+ MetadataTrait::key().size() + encoded_length +
217
+ hpack_constants::kEntryOverhead);
218
+ }
219
+
220
+ private:
221
+ uint32_t previously_sent_index_ = 0;
222
+ };
223
+ template <typename MetadataTrait, size_t N>
224
+ class Compressor<MetadataTrait, SmallIntegralValuesCompressor<N>> {
225
+ public:
226
+ void EncodeWith(MetadataTrait, const typename MetadataTrait::ValueType& value,
227
+ Encoder* encoder) {
228
+ uint32_t* index = nullptr;
229
+ auto& table = encoder->hpack_table();
230
+ if (static_cast<size_t>(value) < N) {
231
+ index = &previously_sent_[static_cast<uint32_t>(value)];
232
+ if (table.ConvertableToDynamicIndex(*index)) {
233
+ encoder->EmitIndexed(table.DynamicIndex(*index));
234
+ return;
235
+ }
236
+ }
237
+ auto key = Slice::FromStaticString(MetadataTrait::key());
238
+ auto encoded_value = MetadataTrait::Encode(value);
239
+ if (index != nullptr) {
240
+ *index = encoder->EmitLitHdrWithNonBinaryStringKeyIncIdx(
241
+ std::move(key), std::move(encoded_value));
242
+ } else {
243
+ encoder->EmitLitHdrWithNonBinaryStringKeyNotIdx(std::move(key),
244
+ std::move(encoded_value));
245
+ }
246
+ }
247
+
248
+ private:
249
+ uint32_t previously_sent_[N] = {};
250
+ };
251
+
252
+ class SliceIndex {
253
+ public:
254
+ void EmitTo(absl::string_view key, const Slice& value, Encoder* encoder);
255
+
256
+ private:
257
+ struct ValueIndex {
258
+ ValueIndex(Slice value, uint32_t index)
259
+ : value(std::move(value)), index(index) {}
260
+ Slice value;
261
+ uint32_t index;
262
+ };
263
+ std::vector<ValueIndex> values_;
264
+ };
265
+
266
+ template <typename MetadataTrait>
267
+ class Compressor<MetadataTrait, SmallSetOfValuesCompressor> {
268
+ public:
269
+ void EncodeWith(MetadataTrait, const Slice& value, Encoder* encoder) {
270
+ index_.EmitTo(MetadataTrait::key(), value, encoder);
271
+ }
272
+
273
+ private:
274
+ SliceIndex index_;
275
+ };
276
+
277
+ struct PreviousTimeout {
278
+ Timeout timeout;
279
+ uint32_t index;
280
+ };
281
+
282
+ class TimeoutCompressorImpl {
283
+ public:
284
+ void EncodeWith(absl::string_view key, Timestamp deadline, Encoder* encoder);
285
+
286
+ private:
287
+ std::vector<PreviousTimeout> previous_timeouts_;
288
+ };
289
+
290
+ template <typename MetadataTrait>
291
+ class Compressor<MetadataTrait, TimeoutCompressor>
292
+ : public TimeoutCompressorImpl {
293
+ public:
294
+ void EncodeWith(MetadataTrait, const typename MetadataTrait::ValueType& value,
295
+ Encoder* encoder) {
296
+ TimeoutCompressorImpl::EncodeWith(MetadataTrait::key(), value, encoder);
297
+ }
298
+ };
299
+
300
+ template <>
301
+ class Compressor<HttpStatusMetadata, HttpStatusCompressor> {
302
+ public:
303
+ void EncodeWith(HttpStatusMetadata, uint32_t status, Encoder* encoder);
304
+ };
305
+
306
+ template <>
307
+ class Compressor<HttpMethodMetadata, HttpMethodCompressor> {
308
+ public:
309
+ void EncodeWith(HttpMethodMetadata, HttpMethodMetadata::ValueType method,
310
+ Encoder* encoder);
311
+ };
312
+
313
+ template <>
314
+ class Compressor<HttpSchemeMetadata, HttpSchemeCompressor> {
315
+ public:
316
+ void EncodeWith(HttpSchemeMetadata, HttpSchemeMetadata::ValueType value,
317
+ Encoder* encoder);
318
+ };
319
+
320
+ } // namespace hpack_encoder_detail
321
+
49
322
  class HPackCompressor {
50
323
  class SliceIndex;
51
324
 
@@ -75,87 +348,22 @@ class HPackCompressor {
75
348
  void EncodeHeaders(const EncodeHeaderOptions& options,
76
349
  const HeaderSet& headers, grpc_slice_buffer* output) {
77
350
  SliceBuffer raw;
78
- Encoder encoder(this, options.use_true_binary_metadata, raw);
351
+ hpack_encoder_detail::Encoder encoder(
352
+ this, options.use_true_binary_metadata, raw);
79
353
  headers.Encode(&encoder);
80
354
  Frame(options, raw, output);
81
355
  }
82
356
 
83
357
  template <typename HeaderSet>
84
358
  void EncodeRawHeaders(const HeaderSet& headers, SliceBuffer& output) {
85
- Encoder encoder(this, true, output);
359
+ hpack_encoder_detail::Encoder encoder(this, true, output);
86
360
  headers.Encode(&encoder);
87
361
  }
88
362
 
89
363
  private:
90
- class Encoder {
91
- public:
92
- Encoder(HPackCompressor* compressor, bool use_true_binary_metadata,
93
- SliceBuffer& output);
94
-
95
- void Encode(const Slice& key, const Slice& value);
96
- void Encode(HttpPathMetadata, const Slice& value);
97
- void Encode(HttpAuthorityMetadata, const Slice& value);
98
- void Encode(HttpStatusMetadata, uint32_t status);
99
- void Encode(GrpcTimeoutMetadata, Timestamp deadline);
100
- void Encode(TeMetadata, TeMetadata::ValueType value);
101
- void Encode(ContentTypeMetadata, ContentTypeMetadata::ValueType value);
102
- void Encode(HttpSchemeMetadata, HttpSchemeMetadata::ValueType value);
103
- void Encode(HttpMethodMetadata, HttpMethodMetadata::ValueType method);
104
- void Encode(UserAgentMetadata, const Slice& slice);
105
- void Encode(GrpcStatusMetadata, grpc_status_code status);
106
- void Encode(GrpcEncodingMetadata, grpc_compression_algorithm value);
107
- void Encode(GrpcAcceptEncodingMetadata, CompressionAlgorithmSet value);
108
- void Encode(GrpcTagsBinMetadata, const Slice& slice);
109
- void Encode(GrpcTraceBinMetadata, const Slice& slice);
110
- void Encode(GrpcMessageMetadata, const Slice& slice) {
111
- if (slice.empty()) return;
112
- EmitLitHdrWithNonBinaryStringKeyNotIdx(
113
- Slice::FromStaticString("grpc-message"), slice.Ref());
114
- }
115
- template <typename Which>
116
- void Encode(Which, const typename Which::ValueType& value) {
117
- const Slice& slice = MetadataValueAsSlice<Which>(value);
118
- if (absl::EndsWith(Which::key(), "-bin")) {
119
- EmitLitHdrWithBinaryStringKeyNotIdx(
120
- Slice::FromStaticString(Which::key()), slice.Ref());
121
- } else {
122
- EmitLitHdrWithNonBinaryStringKeyNotIdx(
123
- Slice::FromStaticString(Which::key()), slice.Ref());
124
- }
125
- }
126
-
127
- private:
128
- friend class SliceIndex;
129
-
130
- void AdvertiseTableSizeChange();
131
- void EmitIndexed(uint32_t index);
132
- void EmitLitHdrWithNonBinaryStringKeyIncIdx(Slice key_slice,
133
- Slice value_slice);
134
- void EmitLitHdrWithBinaryStringKeyIncIdx(Slice key_slice,
135
- Slice value_slice);
136
- void EmitLitHdrWithBinaryStringKeyNotIdx(Slice key_slice,
137
- Slice value_slice);
138
- void EmitLitHdrWithBinaryStringKeyNotIdx(uint32_t key_index,
139
- Slice value_slice);
140
- void EmitLitHdrWithNonBinaryStringKeyNotIdx(Slice key_slice,
141
- Slice value_slice);
142
-
143
- void EncodeAlwaysIndexed(uint32_t* index, absl::string_view key,
144
- Slice value, size_t transport_length);
145
- void EncodeIndexedKeyWithBinaryValue(uint32_t* index, absl::string_view key,
146
- Slice value);
147
-
148
- void EncodeRepeatingSliceValue(const absl::string_view& key,
149
- const Slice& slice, uint32_t* index,
150
- size_t max_compression_size);
151
-
152
- const bool use_true_binary_metadata_;
153
- HPackCompressor* const compressor_;
154
- SliceBuffer& output_;
155
- };
156
-
157
364
  static constexpr size_t kNumFilterValues = 64;
158
365
  static constexpr uint32_t kNumCachedGrpcStatusValues = 16;
366
+ friend class hpack_encoder_detail::Encoder;
159
367
 
160
368
  void Frame(const EncodeHeaderOptions& options, SliceBuffer& raw,
161
369
  grpc_slice_buffer* output);
@@ -168,49 +376,23 @@ class HPackCompressor {
168
376
  bool advertise_table_size_change_ = false;
169
377
  HPackEncoderTable table_;
170
378
 
171
- class SliceIndex {
172
- public:
173
- void EmitTo(absl::string_view key, const Slice& value, Encoder* encoder);
174
-
175
- private:
176
- struct ValueIndex {
177
- ValueIndex(Slice value, uint32_t index)
178
- : value(std::move(value)), index(index) {}
179
- Slice value;
180
- uint32_t index;
181
- };
182
- std::vector<ValueIndex> values_;
183
- };
379
+ grpc_metadata_batch::StatefulCompressor<hpack_encoder_detail::Compressor>
380
+ compression_state_;
381
+ };
184
382
 
185
- struct PreviousTimeout {
186
- Timeout timeout;
187
- uint32_t index;
188
- };
383
+ namespace hpack_encoder_detail {
189
384
 
190
- // Index into table_ for the te:trailers metadata element
191
- uint32_t te_index_ = 0;
192
- // Index into table_ for the content-type metadata element
193
- uint32_t content_type_index_ = 0;
194
- // Index into table_ for the user-agent metadata element
195
- uint32_t user_agent_index_ = 0;
196
- // Cached grpc-status values
197
- uint32_t cached_grpc_status_[kNumCachedGrpcStatusValues] = {};
198
- // Cached grpc-encoding values
199
- uint32_t cached_grpc_encoding_[GRPC_COMPRESS_ALGORITHMS_COUNT] = {};
200
- // Cached grpc-accept-encoding value
201
- uint32_t grpc_accept_encoding_index_ = 0;
202
- // The grpc-accept-encoding string referred to by grpc_accept_encoding_index_
203
- CompressionAlgorithmSet grpc_accept_encoding_;
204
- // Index of something that was sent with grpc-tags-bin
205
- uint32_t grpc_tags_bin_index_ = 0;
206
- // Index of something that was sent with grpc-trace-bin
207
- uint32_t grpc_trace_bin_index_ = 0;
208
- // The user-agent string referred to by user_agent_index_
209
- Slice user_agent_;
210
- SliceIndex path_index_;
211
- SliceIndex authority_index_;
212
- std::vector<PreviousTimeout> previous_timeouts_;
213
- };
385
+ template <typename MetadataTrait>
386
+ void Encoder::Encode(MetadataTrait,
387
+ const typename MetadataTrait::ValueType& value) {
388
+ compressor_->compression_state_
389
+ .Compressor<MetadataTrait, typename MetadataTrait::CompressionTraits>::
390
+ EncodeWith(MetadataTrait(), value, this);
391
+ }
392
+
393
+ inline HPackEncoderTable& Encoder::hpack_table() { return compressor_->table_; }
394
+
395
+ } // namespace hpack_encoder_detail
214
396
 
215
397
  } // namespace grpc_core
216
398
 
@@ -23,6 +23,8 @@
23
23
  namespace grpc_core {
24
24
 
25
25
  uint32_t HPackEncoderTable::AllocateIndex(size_t element_size) {
26
+ GPR_DEBUG_ASSERT(element_size >= 32);
27
+
26
28
  uint32_t new_index = tail_remote_index_ + table_elems_ + 1;
27
29
  GPR_DEBUG_ASSERT(element_size <= MaxEntrySize());
28
30
 
@@ -50,6 +50,8 @@ class HPackEncoderTable {
50
50
  uint32_t max_size() const { return max_table_size_; }
51
51
  // Get the current table size
52
52
  uint32_t test_only_table_size() const { return table_size_; }
53
+ // Get the number of entries in the table
54
+ uint32_t test_only_table_elems() const { return table_elems_; }
53
55
 
54
56
  // Convert an element index into a dynamic index
55
57
  uint32_t DynamicIndex(uint32_t index) const {