/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 |