Lines
96.4 %
Functions
100 %
#include "source/extensions/common/dubbo/message.h"
#include "source/common/common/logger.h"
#include "source/extensions/common/dubbo/hessian2_utils.h"
namespace Envoy {
namespace Extensions {
namespace Common {
namespace Dubbo {
void RequestContent::initialize(Buffer::Instance& buffer, uint64_t length) {
ASSERT(content_buffer_.length() == 0, "content buffer has been initialized");
content_buffer_.move(buffer, length);
// Clear the types, arguments and attachments.
types_.clear();
argvs_.clear();
attachs_.clear();
// Set both decoded and updated to false since the content has been initialized
// by raw buffer.
decoded_ = false;
updated_ = false;
}
void RequestContent::initialize(std::string&& types, ArgumentVec&& argvs, Attachments&& attachs) {
// Set the types, arguments and attachments.
types_ = std::move(types);
argvs_ = std::move(argvs);
attachs_ = std::move(attachs);
// Encode the types, arguments and attachments into the content buffer.
encodeEverything();
// Set decoded to true since the content has been initialized by types,
// arguments and attachments.
decoded_ = true;
const Buffer::Instance& RequestContent::buffer() {
// Ensure the attachments in the buffer is latest.
if (content_buffer_.length() == 0) {
} else {
encodeAttachments();
return content_buffer_;
void RequestContent::bufferMoveTo(Buffer::Instance& buffer) { buffer.move(content_buffer_); }
const ArgumentVec& RequestContent::arguments() {
lazyDecode();
return argvs_;
const Attachments& RequestContent::attachments() {
return attachs_;
void RequestContent::setAttachment(absl::string_view key, absl::string_view val) {
updated_ = true;
attachs_[key] = val;
void RequestContent::delAttachment(absl::string_view key) {
attachs_.erase(key);
void RequestContent::lazyDecode() {
if (decoded_) {
return;
// Decode the content buffer into types, arguments and attachments.
Hessian2::Decoder decoder(std::make_unique<BufferReader>(content_buffer_));
// Handle the types and arguments.
if (auto element = decoder.decode<Hessian2::Object>(); element != nullptr) {
uint32_t number = 0;
if (element->type() == Hessian2::Object::Type::Integer) {
ASSERT(element->toInteger().has_value());
if (int32_t direct_num = element->toInteger().value(); direct_num == -1) {
if (auto types = decoder.decode<std::string>(); types != nullptr) {
types_ = *types;
number = Hessian2Utils::getParametersNumber(types_);
ENVOY_LOG(error, "Cannot parse RpcInvocation parameter types from buffer");
handleBrokenValue();
} else if (direct_num >= 0) {
number = direct_num;
ENVOY_LOG(error, "Invalid RpcInvocation parameter number {}", direct_num);
} else if (element->type() == Hessian2::Object::Type::String) {
ASSERT(element->toString().has_value());
types_ = element->toString().value().get();
for (uint32_t i = 0; i < number; i++) {
if (auto result = decoder.decode<Hessian2::Object>(); result != nullptr) {
argvs_.push_back(std::move(result));
ENVOY_LOG(error, "Cannot parse RpcInvocation parameter from buffer");
ENVOY_LOG(error, "Cannot parse RpcInvocation from buffer");
// Record the size of the arguments in the content buffer. This is useful for
// re-encoding the attachments.
argvs_size_ = decoder.offset();
// Handle the attachments.
auto map = decoder.decode<Hessian2::Object>();
if (map == nullptr || map->type() != Hessian2::Object::Type::UntypedMap) {
for (auto& [key, val] : map->toMutableUntypedMap().value().get()) {
if (key->type() != Hessian2::Object::Type::String ||
val->type() != Hessian2::Object::Type::String) {
continue;
attachs_.emplace(std::move(key->toMutableString().value().get()),
std::move(val->toMutableString().value().get()));
void RequestContent::encodeAttachments() {
// Do nothing if the attachments have not been updated.
if (!updated_) {
// Ensure the content has been decoded before re-encoding it.
const uint64_t buffer_length = content_buffer_.length();
ASSERT(buffer_length > 0, "content buffer is empty");
// The size of arguments will be set when doing lazyDecode() or encodeEverything().
if (buffer_length < argvs_size_) {
ENVOY_LOG(error, "arguments size {} is larger than content buffer {}", argvs_size_,
buffer_length);
// Create a new buffer to hold the re-encoded content.
Buffer::OwnedImpl new_content_buffer;
// Copy the types and arguments into the new buffer.
new_content_buffer.move(content_buffer_, argvs_size_);
// Encode the attachments into the new buffer.
Hessian2::Encoder encoder(std::make_unique<BufferWriter>(new_content_buffer));
new_content_buffer.writeByte('H');
for (auto& [key, val] : attachs_) {
encoder.encode(key);
encoder.encode(val);
new_content_buffer.writeByte('Z');
// Clear the content buffer and move the new buffer into it.
content_buffer_.drain(content_buffer_.length());
content_buffer_.move(new_content_buffer);
void RequestContent::encodeEverything() {
ASSERT(content_buffer_.length() == 0, "content buffer contains something");
Hessian2::Encoder encoder(std::make_unique<BufferWriter>(content_buffer_));
// Encode the types into the content buffer first.
if (!types_.empty()) {
encoder.encode(types_);
} else if (!argvs_.empty()) {
encoder.encode(static_cast<int32_t>(argvs_.size()));
// Encode the arguments into the content buffer.
for (auto& arg : argvs_) {
encoder.encode(*arg);
argvs_size_ = content_buffer_.length();
// Encode the attachments into the content buffer.
content_buffer_.writeByte('H');
content_buffer_.writeByte('Z');
void RequestContent::handleBrokenValue() {
// Because the lazy decoding is used, Envoy cannot reject the message with broken
// content. Instead, it will reset the whole content to an empty state.
// Clear everything.
// Encode everything.
void ResponseContent::initialize(Buffer::Instance& buffer, uint64_t length) {
// Clear the result and attachments.
result_ = nullptr;
void ResponseContent::initialize(Hessian2::ObjectPtr&& value, Attachments&& attachs) {
// Set the result and attachments.
result_ = std::move(value);
// Encode the result and attachments into the content buffer.
// Set decoded to true since the content has been initialized by result and attachments.
const Buffer::Instance& ResponseContent::buffer() {
void ResponseContent::bufferMoveTo(Buffer::Instance& buffer) { buffer.move(content_buffer_); }
const Hessian2::Object* ResponseContent::result() {
return result_.get();
const Attachments& ResponseContent::attachments() {
void ResponseContent::setAttachment(absl::string_view key, absl::string_view val) {
void ResponseContent::delAttachment(absl::string_view key) {
void ResponseContent::lazyDecode() {
// Decode the content buffer into result and attachments.
// Handle the result.
result_ = decoder.decode<Hessian2::Object>();
if (result_ == nullptr) {
ENVOY_LOG(error, "Cannot parse RpcResult from buffer");
// Record the size of the result in the content buffer. This is useful for
result_size_ = decoder.offset();
void ResponseContent::encodeAttachments() {
if (buffer_length < result_size_) {
ENVOY_LOG(error, "result size {} is larger than content buffer {}", result_size_,
// Copy the result into the new buffer.
new_content_buffer.move(content_buffer_, result_size_);
void ResponseContent::encodeEverything() {
content_buffer_.writeByte('N');
encoder.encode(*result_);
result_size_ = content_buffer_.length();
void ResponseContent::handleBrokenValue() {
} // namespace Dubbo
} // namespace Common
} // namespace Extensions
} // namespace Envoy