Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/extensions/common/dubbo/message.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/extensions/common/dubbo/message.h"
2
3
#include "source/common/common/logger.h"
4
#include "source/extensions/common/dubbo/hessian2_utils.h"
5
6
namespace Envoy {
7
namespace Extensions {
8
namespace Common {
9
namespace Dubbo {
10
11
0
void RequestContent::initialize(Buffer::Instance& buffer, uint64_t length) {
12
0
  ASSERT(content_buffer_.length() == 0, "content buffer has been initialized");
13
14
0
  content_buffer_.move(buffer, length);
15
16
  // Clear the types, arguments and attachments.
17
0
  types_.clear();
18
0
  argvs_.clear();
19
0
  attachs_.clear();
20
21
  // Set both decoded and updated to false since the content has been initialized
22
  // by raw buffer.
23
0
  decoded_ = false;
24
0
  updated_ = false;
25
0
}
26
27
0
void RequestContent::initialize(std::string&& types, ArgumentVec&& argvs, Attachments&& attachs) {
28
0
  ASSERT(content_buffer_.length() == 0, "content buffer has been initialized");
29
30
  // Set the types, arguments and attachments.
31
0
  types_ = std::move(types);
32
0
  argvs_ = std::move(argvs);
33
0
  attachs_ = std::move(attachs);
34
35
  // Encode the types, arguments and attachments into the content buffer.
36
0
  encodeEverything();
37
38
  // Set decoded to true since the content has been initialized by types,
39
  // arguments and attachments.
40
0
  decoded_ = true;
41
0
  updated_ = false;
42
0
}
43
44
0
const Buffer::Instance& RequestContent::buffer() {
45
  // Ensure the attachments in the buffer is latest.
46
47
0
  if (content_buffer_.length() == 0) {
48
0
    encodeEverything();
49
0
  } else {
50
0
    encodeAttachments();
51
0
  }
52
53
0
  return content_buffer_;
54
0
}
55
56
0
void RequestContent::bufferMoveTo(Buffer::Instance& buffer) { buffer.move(content_buffer_); }
57
58
0
const ArgumentVec& RequestContent::arguments() {
59
0
  lazyDecode();
60
61
0
  return argvs_;
62
0
}
63
64
0
const Attachments& RequestContent::attachments() {
65
0
  lazyDecode();
66
67
0
  return attachs_;
68
0
}
69
70
0
void RequestContent::setAttachment(absl::string_view key, absl::string_view val) {
71
0
  lazyDecode();
72
73
0
  updated_ = true;
74
0
  attachs_[key] = val;
75
0
}
76
77
0
void RequestContent::delAttachment(absl::string_view key) {
78
0
  lazyDecode();
79
80
0
  updated_ = true;
81
0
  attachs_.erase(key);
82
0
}
83
84
0
void RequestContent::lazyDecode() {
85
0
  if (decoded_) {
86
0
    return;
87
0
  }
88
0
  decoded_ = true;
89
90
  // Decode the content buffer into types, arguments and attachments.
91
0
  Hessian2::Decoder decoder(std::make_unique<BufferReader>(content_buffer_));
92
93
  // Handle the types and arguments.
94
0
  if (auto element = decoder.decode<Hessian2::Object>(); element != nullptr) {
95
0
    uint32_t number = 0;
96
97
0
    if (element->type() == Hessian2::Object::Type::Integer) {
98
0
      ASSERT(element->toInteger().has_value());
99
0
      if (int32_t direct_num = element->toInteger().value(); direct_num == -1) {
100
0
        if (auto types = decoder.decode<std::string>(); types != nullptr) {
101
0
          types_ = *types;
102
0
          number = Hessian2Utils::getParametersNumber(types_);
103
0
        } else {
104
0
          ENVOY_LOG(error, "Cannot parse RpcInvocation parameter types from buffer");
105
0
          handleBrokenValue();
106
0
          return;
107
0
        }
108
0
      } else if (direct_num >= 0) {
109
0
        number = direct_num;
110
0
      } else {
111
0
        ENVOY_LOG(error, "Invalid RpcInvocation parameter number {}", direct_num);
112
0
        handleBrokenValue();
113
0
        return;
114
0
      }
115
0
    } else if (element->type() == Hessian2::Object::Type::String) {
116
0
      ASSERT(element->toString().has_value());
117
0
      types_ = element->toString().value().get();
118
0
      number = Hessian2Utils::getParametersNumber(types_);
119
0
    }
120
121
0
    for (uint32_t i = 0; i < number; i++) {
122
0
      if (auto result = decoder.decode<Hessian2::Object>(); result != nullptr) {
123
0
        argvs_.push_back(std::move(result));
124
0
      } else {
125
0
        ENVOY_LOG(error, "Cannot parse RpcInvocation parameter from buffer");
126
0
        handleBrokenValue();
127
0
        return;
128
0
      }
129
0
    }
130
0
  } else {
131
0
    ENVOY_LOG(error, "Cannot parse RpcInvocation from buffer");
132
0
    handleBrokenValue();
133
0
    return;
134
0
  }
135
136
  // Record the size of the arguments in the content buffer. This is useful for
137
  // re-encoding the attachments.
138
0
  argvs_size_ = decoder.offset();
139
140
  // Handle the attachments.
141
0
  auto map = decoder.decode<Hessian2::Object>();
142
0
  if (map == nullptr || map->type() != Hessian2::Object::Type::UntypedMap) {
143
0
    return;
144
0
  }
145
146
0
  for (auto& [key, val] : map->toMutableUntypedMap().value().get()) {
147
0
    if (key->type() != Hessian2::Object::Type::String ||
148
0
        val->type() != Hessian2::Object::Type::String) {
149
0
      continue;
150
0
    }
151
0
    attachs_.emplace(std::move(key->toMutableString().value().get()),
152
0
                     std::move(val->toMutableString().value().get()));
153
0
  }
154
0
}
155
156
0
void RequestContent::encodeAttachments() {
157
  // Do nothing if the attachments have not been updated.
158
0
  if (!updated_) {
159
0
    return;
160
0
  }
161
162
  // Ensure the content has been decoded before re-encoding it.
163
0
  lazyDecode();
164
165
0
  const uint64_t buffer_length = content_buffer_.length();
166
0
  ASSERT(buffer_length > 0, "content buffer is empty");
167
168
  // The size of arguments will be set when doing lazyDecode() or encodeEverything().
169
0
  if (buffer_length < argvs_size_) {
170
0
    ENVOY_LOG(error, "arguments size {} is larger than content buffer {}", argvs_size_,
171
0
              buffer_length);
172
0
    handleBrokenValue();
173
0
    return;
174
0
  }
175
176
  // Create a new buffer to hold the re-encoded content.
177
178
0
  Buffer::OwnedImpl new_content_buffer;
179
  // Copy the types and arguments into the new buffer.
180
0
  new_content_buffer.move(content_buffer_, argvs_size_);
181
182
  // Encode the attachments into the new buffer.
183
0
  Hessian2::Encoder encoder(std::make_unique<BufferWriter>(new_content_buffer));
184
0
  new_content_buffer.writeByte('H');
185
0
  for (auto& [key, val] : attachs_) {
186
0
    encoder.encode(key);
187
0
    encoder.encode(val);
188
0
  }
189
0
  new_content_buffer.writeByte('Z');
190
191
  // Clear the content buffer and move the new buffer into it.
192
0
  content_buffer_.drain(content_buffer_.length());
193
0
  content_buffer_.move(new_content_buffer);
194
195
0
  updated_ = false;
196
0
}
197
198
0
void RequestContent::encodeEverything() {
199
0
  ASSERT(content_buffer_.length() == 0, "content buffer contains something");
200
201
  // Encode the types, arguments and attachments into the content buffer.
202
0
  Hessian2::Encoder encoder(std::make_unique<BufferWriter>(content_buffer_));
203
204
  // Encode the types into the content buffer first.
205
0
  if (!types_.empty()) {
206
0
    encoder.encode(types_);
207
0
  } else if (!argvs_.empty()) {
208
0
    encoder.encode(static_cast<int32_t>(argvs_.size()));
209
0
  } else {
210
0
    encoder.encode(types_);
211
0
  }
212
213
  // Encode the arguments into the content buffer.
214
0
  for (auto& arg : argvs_) {
215
0
    encoder.encode(*arg);
216
0
  }
217
218
  // Record the size of the arguments in the content buffer. This is useful for
219
  // re-encoding the attachments.
220
0
  argvs_size_ = content_buffer_.length();
221
222
  // Encode the attachments into the content buffer.
223
0
  content_buffer_.writeByte('H');
224
0
  for (auto& [key, val] : attachs_) {
225
0
    encoder.encode(key);
226
0
    encoder.encode(val);
227
0
  }
228
0
  content_buffer_.writeByte('Z');
229
230
0
  updated_ = false;
231
0
}
232
233
0
void RequestContent::handleBrokenValue() {
234
  // Because the lazy decoding is used, Envoy cannot reject the message with broken
235
  // content. Instead, it will reset the whole content to an empty state.
236
237
  // Clear everything.
238
0
  content_buffer_.drain(content_buffer_.length());
239
0
  types_.clear();
240
0
  argvs_.clear();
241
0
  attachs_.clear();
242
243
  // Encode everything.
244
0
  encodeEverything();
245
246
0
  decoded_ = true;
247
0
  updated_ = false;
248
0
}
249
250
0
void ResponseContent::initialize(Buffer::Instance& buffer, uint64_t length) {
251
0
  ASSERT(content_buffer_.length() == 0, "content buffer has been initialized");
252
0
  content_buffer_.move(buffer, length);
253
254
  // Clear the result and attachments.
255
0
  result_ = nullptr;
256
0
  attachs_.clear();
257
258
  // Set both decoded and updated to false since the content has been initialized
259
  // by raw buffer.
260
0
  decoded_ = false;
261
0
  updated_ = false;
262
0
}
263
264
0
void ResponseContent::initialize(Hessian2::ObjectPtr&& value, Attachments&& attachs) {
265
0
  ASSERT(content_buffer_.length() == 0, "content buffer has been initialized");
266
267
  // Set the result and attachments.
268
0
  result_ = std::move(value);
269
0
  attachs_ = std::move(attachs);
270
271
  // Encode the result and attachments into the content buffer.
272
0
  encodeEverything();
273
274
  // Set decoded to true since the content has been initialized by result and attachments.
275
0
  decoded_ = true;
276
0
  updated_ = false;
277
0
}
278
279
0
const Buffer::Instance& ResponseContent::buffer() {
280
  // Ensure the attachments in the buffer is latest.
281
0
  if (content_buffer_.length() == 0) {
282
0
    encodeEverything();
283
0
  } else {
284
0
    encodeAttachments();
285
0
  }
286
287
0
  return content_buffer_;
288
0
}
289
290
0
void ResponseContent::bufferMoveTo(Buffer::Instance& buffer) { buffer.move(content_buffer_); }
291
292
0
const Hessian2::Object* ResponseContent::result() {
293
0
  lazyDecode();
294
295
0
  return result_.get();
296
0
}
297
298
0
const Attachments& ResponseContent::attachments() {
299
0
  lazyDecode();
300
301
0
  return attachs_;
302
0
}
303
304
0
void ResponseContent::setAttachment(absl::string_view key, absl::string_view val) {
305
0
  lazyDecode();
306
307
0
  updated_ = true;
308
0
  attachs_[key] = val;
309
0
}
310
311
0
void ResponseContent::delAttachment(absl::string_view key) {
312
0
  lazyDecode();
313
314
0
  updated_ = true;
315
0
  attachs_.erase(key);
316
0
}
317
318
0
void ResponseContent::lazyDecode() {
319
0
  if (decoded_) {
320
0
    return;
321
0
  }
322
0
  decoded_ = true;
323
324
  // Decode the content buffer into result and attachments.
325
0
  Hessian2::Decoder decoder(std::make_unique<BufferReader>(content_buffer_));
326
327
  // Handle the result.
328
0
  result_ = decoder.decode<Hessian2::Object>();
329
330
0
  if (result_ == nullptr) {
331
0
    ENVOY_LOG(error, "Cannot parse RpcResult from buffer");
332
0
    handleBrokenValue();
333
0
    return;
334
0
  }
335
336
  // Record the size of the result in the content buffer. This is useful for
337
  // re-encoding the attachments.
338
0
  result_size_ = decoder.offset();
339
340
  // Handle the attachments.
341
0
  auto map = decoder.decode<Hessian2::Object>();
342
0
  if (map == nullptr || map->type() != Hessian2::Object::Type::UntypedMap) {
343
0
    return;
344
0
  }
345
346
0
  for (auto& [key, val] : map->toMutableUntypedMap().value().get()) {
347
0
    if (key->type() != Hessian2::Object::Type::String ||
348
0
        val->type() != Hessian2::Object::Type::String) {
349
0
      continue;
350
0
    }
351
0
    attachs_.emplace(std::move(key->toMutableString().value().get()),
352
0
                     std::move(val->toMutableString().value().get()));
353
0
  }
354
0
}
355
356
0
void ResponseContent::encodeAttachments() {
357
0
  if (!updated_) {
358
0
    return;
359
0
  }
360
361
  // Ensure the content has been decoded before re-encoding it.
362
0
  lazyDecode();
363
364
0
  const uint64_t buffer_length = content_buffer_.length();
365
0
  ASSERT(buffer_length > 0, "content buffer is empty");
366
367
0
  if (buffer_length < result_size_) {
368
0
    ENVOY_LOG(error, "result size {} is larger than content buffer {}", result_size_,
369
0
              buffer_length);
370
0
    handleBrokenValue();
371
0
    return;
372
0
  }
373
374
  // Create a new buffer to hold the re-encoded content.
375
0
  Buffer::OwnedImpl new_content_buffer;
376
377
  // Copy the result into the new buffer.
378
0
  new_content_buffer.move(content_buffer_, result_size_);
379
380
  // Encode the attachments into the new buffer.
381
0
  Hessian2::Encoder encoder(std::make_unique<BufferWriter>(new_content_buffer));
382
0
  new_content_buffer.writeByte('H');
383
0
  for (auto& [key, val] : attachs_) {
384
0
    encoder.encode(key);
385
0
    encoder.encode(val);
386
0
  }
387
0
  new_content_buffer.writeByte('Z');
388
389
  // Clear the content buffer and move the new buffer into it.
390
0
  content_buffer_.drain(content_buffer_.length());
391
0
  content_buffer_.move(new_content_buffer);
392
393
0
  updated_ = false;
394
0
}
395
396
0
void ResponseContent::encodeEverything() {
397
0
  ASSERT(content_buffer_.length() == 0, "content buffer contains something");
398
399
  // Encode the result and attachments into the content buffer.
400
0
  Hessian2::Encoder encoder(std::make_unique<BufferWriter>(content_buffer_));
401
0
  if (result_ == nullptr) {
402
0
    content_buffer_.writeByte('N');
403
0
  } else {
404
0
    encoder.encode(*result_);
405
0
  }
406
407
  // Record the size of the result in the content buffer. This is useful for
408
  // re-encoding the attachments.
409
0
  result_size_ = content_buffer_.length();
410
411
0
  content_buffer_.writeByte('H');
412
0
  for (auto& [key, val] : attachs_) {
413
0
    encoder.encode(key);
414
0
    encoder.encode(val);
415
0
  }
416
0
  content_buffer_.writeByte('Z');
417
418
0
  updated_ = false;
419
0
}
420
421
0
void ResponseContent::handleBrokenValue() {
422
  // Because the lazy decoding is used, Envoy cannot reject the message with broken
423
  // content. Instead, it will reset the whole content to an empty state.
424
425
  // Clear everything.
426
0
  content_buffer_.drain(content_buffer_.length());
427
0
  result_ = nullptr;
428
0
  attachs_.clear();
429
430
  // Encode everything.
431
0
  encodeEverything();
432
433
0
  decoded_ = true;
434
0
  updated_ = false;
435
0
}
436
437
} // namespace Dubbo
438
} // namespace Common
439
} // namespace Extensions
440
} // namespace Envoy