Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add base64 compilation option for trpc-over-http codec #35

Merged
merged 1 commit into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/en/http_protocol_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,17 @@ the service initialization phase.
# ...
```

## Processing transparent information

For HTTP RPC services, the framework will perform the following processing on transparent information during encoding and decoding.
* Decode: When receiving a request packet, the framework extracts the data named `trpc-trans-info` from the HTTP headers, parses its content in JSON format, and uses the parsed key-value pairs as transparent information for the request. Users can retrieve it using the `ServerContext::GetPbReqTransInfo` interface.
* Encode: When responding with a reply packet, the framework converts the transparent information set by the user through the `ServerContext::AddReqTransInfo` interface into an HTTP header named `trpc-trans-info` with a value of a JSON string.

Note that by default, the framework does not perform base64 encoding/decoding on the values of transparent information. If needed, you can enable it by adding the compilation option `trpc_enable_http_transinfo_base64`.
```
build --define trpc_enable_http_transinfo_base64=true
```

# FAQ

## How to write routing rules to match all paths?
Expand Down
12 changes: 12 additions & 0 deletions docs/zh/http_protocol_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,18 @@ tRPC 提供一套 HTTP 流式读取/写入数据分片的接口,可以分片
# ...
```

## 透传信息处理

对于HTTP RPC 服务,框架在编解码时会对透传信息进行如下处理:
* 解码:框架在收到请求包时,会从HTTP头部中取出名称为`“trpc-trans-info”`的数据,将其内容按JSON格式进行解析,然后将解析到的键值对作为请求的透传信息。用户可以通过`“ServerContext::GetPbReqTransInfo”`接口获取。
* 编码:框架在进行回包响应时,会将用户通过`“ServerContext::AddRspTransInfo”`接口设置的透传信息,转换成一个名称为
`“trpc-trans-info”`,值为JSON串的HTTP头部。

注意框架默认不会对透传信息中的值进行base64编解码,如果有需要,可以通过添加`“trpc_enable_http_transinfo_base64”`编译选项来开启:
```
build --define trpc_enable_http_transinfo_base64=true
```

# FAQ

## 如果匹配所有路径需要怎么写路由规则?
Expand Down
6 changes: 6 additions & 0 deletions trpc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,9 @@ config_setting(
name = "trpc_include_overload_control",
values = {"define": "trpc_include_overload_control=true"},
)

# Whether to automatically perform base64 encoding on trans_info in trpc-over-http. Default close.
config_setting(
name = "trpc_enable_http_transinfo_base64",
values = {"define": "trpc_enable_http_transinfo_base64=true"},
)
22 changes: 22 additions & 0 deletions trpc/codec/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ cc_library(
name = "http_client_codec",
srcs = ["http_client_codec.cc"],
hdrs = ["http_client_codec.h"],
defines = [
] + select({
"//trpc:trpc_enable_http_transinfo_base64": ["TRPC_ENABLE_HTTP_TRANSINFO_BASE64"],
"//conditions:default": [],
}),
deps = [
":http_client_proto_checker_impl",
":http_protocol",
Expand All @@ -14,6 +19,7 @@ cc_library(
"//trpc/common:status",
"//trpc/serialization:serialization_factory",
"//trpc/util:ref_ptr",
"//trpc/util/http:base64",
"//trpc/util/http:request",
"//trpc/util/http:response",
],
Expand All @@ -22,6 +28,11 @@ cc_library(
cc_test(
name = "http_client_codec_test",
srcs = ["http_client_codec_test.cc"],
defines = [
] + select({
"//trpc:trpc_enable_http_transinfo_base64": ["TRPC_ENABLE_HTTP_TRANSINFO_BASE64"],
"//conditions:default": [],
}),
deps = [
":http_client_codec",
"//trpc/compressor/testing:compressor_testing",
Expand Down Expand Up @@ -89,13 +100,19 @@ cc_library(
name = "http_server_codec",
srcs = ["http_server_codec.cc"],
hdrs = ["http_server_codec.h"],
defines = [
] + select({
"//trpc:trpc_enable_http_transinfo_base64": ["TRPC_ENABLE_HTTP_TRANSINFO_BASE64"],
"//conditions:default": [],
}),
deps = [
":http_protocol",
":http_server_proto_checker_impl",
"//trpc/common:status",
"//trpc/runtime/iomodel/reactor/common:connection",
"//trpc/server:server_context",
"//trpc/util/buffer:noncontiguous_buffer",
"//trpc/util/http:base64",
"//trpc/util/http:request",
"//trpc/util/http:response",
],
Expand All @@ -104,6 +121,11 @@ cc_library(
cc_test(
name = "http_server_codec_test",
srcs = ["http_server_codec_test.cc"],
defines = [
] + select({
"//trpc:trpc_enable_http_transinfo_base64": ["TRPC_ENABLE_HTTP_TRANSINFO_BASE64"],
"//conditions:default": [],
}),
deps = [
":http_server_codec",
"@com_google_googletest//:gtest",
Expand Down
30 changes: 27 additions & 3 deletions trpc/codec/http/http_client_codec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,34 @@
#include "trpc/common/status.h"
#include "trpc/compressor/trpc_compressor.h"
#include "trpc/serialization/serialization_factory.h"
#include "trpc/util/http/base64.h"
#include "trpc/util/http/request.h"
#include "trpc/util/http/response.h"

namespace trpc {

namespace {

void SetTrpcTransInfo(const ClientContextPtr& ctx, trpc::http::RequestPtr& req) {
if (!ctx->GetPbReqTransInfo().empty()) {
rapidjson::StringBuffer str_buf;
rapidjson::Writer<rapidjson::StringBuffer> writer(str_buf);
writer.StartObject();
for (const auto& [name, value] : ctx->GetPbReqTransInfo()) {
writer.Key(name.c_str());
#ifdef TRPC_ENABLE_HTTP_TRANSINFO_BASE64
writer.String(http::Base64Encode(std::begin(value), std::end(value)).c_str());
#else
writer.String(value.c_str());
#endif
}
writer.EndObject();
req->AddHeader("trpc-trans-info", str_buf.GetString());
}
}

} // namespace

int HttpClientCodec::ZeroCopyCheck(const ConnectionPtr& conn, NoncontiguousBuffer& in, std::deque<std::any>& out) {
return HttpZeroCopyCheckResponse(conn, in, out);
}
Expand Down Expand Up @@ -102,9 +125,10 @@ bool HttpClientCodec::FillRequest(const ClientContextPtr& ctx, const ProtocolPtr
req->SetMethodType(http::OperationType::POST);
req->SetVersion("1.1");
req->SetUrl(ctx->GetFuncName());
for (const auto& kv : ctx->GetHttpHeaders()) {
req->AddHeader(kv.first, kv.second);
}

// set trpc-trans-info
SetTrpcTransInfo(ctx, req);

switch (ctx->GetReqEncodeType()) {
case serialization::kPbType:
req->SetHeaderIfNotPresent("Content-Type", "application/pb");
Expand Down
7 changes: 7 additions & 0 deletions trpc/codec/http/http_client_codec_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ TEST_F(HttpClientCodecTest, FillRequestAsPB) {
ClientContextPtr context = MakeRefCounted<ClientContext>();
context->SetRequest(req_protocol);
context->SetReqEncodeType(serialization::kPbType);
std::string test_k = "k", test_v = "v";
context->AddReqTransInfo(test_k, test_v);

test::helloworld::HelloRequest hello_req;
hello_req.set_msg("hello");
Expand All @@ -151,6 +153,11 @@ TEST_F(HttpClientCodecTest, FillRequestAsPB) {
ASSERT_EQ(req_ptr->request->GetHeader("Content-Length"), std::to_string(hello_req.ByteSizeLong()));
ASSERT_TRUE(req_ptr->request->HasHeader("Content-Type"));
ASSERT_EQ(req_ptr->request->GetHeader("Content-Type"), "application/pb");
#ifdef TRPC_ENABLE_HTTP_TRANSINFO_BASE64
ASSERT_EQ(req_ptr->request->GetHeader("trpc-trans-info"), "{\"k\":\"dg==\"}");
#else
ASSERT_EQ(req_ptr->request->GetHeader("trpc-trans-info"), "{\"k\":\"v\"}");
#endif
}

TEST_F(HttpClientCodecTest, FillRequestAsJson) {
Expand Down
68 changes: 55 additions & 13 deletions trpc/codec/http/http_server_codec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@

#include "trpc/codec/http/http_server_codec.h"

#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"

#include "trpc/codec/http/http_proto_checker.h"
#include "trpc/util/http/base64.h"
#include "trpc/util/http/request.h"
#include "trpc/util/http/response.h"
#include "trpc/util/string_helper.h"
Expand Down Expand Up @@ -77,6 +82,52 @@ bool SerializationTypeToContentType(uint32_t serialization_type, std::string* co
*content_type = iter->second;
return true;
}

void ParseTrpcTransInfo(std::string& value, HttpRequestProtocol* req) {
rapidjson::Document document;
document.Parse(value.c_str());
if (document.IsObject()) {
for (auto& mem : document.GetObject()) {
std::string key = mem.name.GetString();
if (document[key].IsString()) {
#ifdef TRPC_ENABLE_HTTP_TRANSINFO_BASE64
std::string ori_value = mem.value.GetString();
std::string decoded = http::Base64Decode(std::begin(ori_value), std::end(ori_value));
if (decoded.empty()) {
req->SetKVInfo(key, ori_value);
TRPC_LOG_TRACE("trpc transinfo key:" << key << ",value:" << ori_value);
} else {
req->SetKVInfo(key, decoded);
TRPC_LOG_TRACE("trpc transinfo key:" << key << ",value:" << decoded);
}
#else
req->SetKVInfo(key, mem.value.GetString());
TRPC_LOG_TRACE("trpc transinfo key:" << key << ",value:" << mem.value.GetString());
#endif
}
}
} else {
TRPC_LOG_ERROR("HTTP Header[trpc-trans-info] value need to be json format");
}
}

void SetTrpcTransInfo(const ServerContextPtr& ctx, HttpResponseProtocol* rsp) {
if (!ctx->GetPbRspTransInfo().empty()) {
rapidjson::StringBuffer str_buf;
rapidjson::Writer<rapidjson::StringBuffer> writer(str_buf);
writer.StartObject();
for (const auto& [name, value] : ctx->GetPbRspTransInfo()) {
writer.Key(name.c_str());
#ifdef TRPC_ENABLE_HTTP_TRANSINFO_BASE64
writer.String(http::Base64Encode(std::begin(value), std::end(value)).c_str());
#else
writer.String(value.c_str());
#endif
}
writer.EndObject();
rsp->response.AddHeader("trpc-trans-info", str_buf.GetString());
}
}
} // namespace

int HttpServerCodec::ZeroCopyCheck(const ConnectionPtr& conn, NoncontiguousBuffer& in, std::deque<std::any>& out) {
Expand Down Expand Up @@ -177,19 +228,7 @@ bool TrpcOverHttpServerCodec::ZeroCopyDecode(const ServerContextPtr& ctx, std::a
// Key-value pairs for trpc-over-http
value = http_req->GetHeader("trpc-trans-info");
if (!value.empty()) {
rapidjson::Document document;
document.Parse(value.c_str());
if (document.IsObject()) {
for (auto& mem : document.GetObject()) {
std::string key = mem.name.GetString();
if (document[key].IsString()) {
http_req_msg->SetKVInfo(key, mem.value.GetString());
TRPC_LOG_TRACE("trpc transinfo key:" << key << ",value:" << mem.value.GetString());
}
}
} else {
TRPC_LOG_ERROR("HTTP Header[trpc-trans-info] value need to be json format");
}
ParseTrpcTransInfo(value, http_req_msg);
}
http_req_msg->request = std::move(http_req);
} catch (const std::exception& ex) {
Expand Down Expand Up @@ -232,6 +271,9 @@ bool TrpcOverHttpServerCodec::ZeroCopyEncode(const ServerContextPtr& ctx, Protoc
http_rsp_msg->response.SetHeader(http::kHeaderContentEncoding,
http::CompressTypeToString(ctx->GetRspCompressType()));
}

// Set trans info into header
SetTrpcTransInfo(ctx, http_rsp_msg);
}

int http_status;
Expand Down
10 changes: 10 additions & 0 deletions trpc/codec/http/http_server_codec_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ void FillHttpRequest(http::RequestPtr& r) {
r->SetHeader("trpc-message-type", std::to_string(TrpcMessageType::TRPC_DEFAULT));
r->SetHeader("Content-Type", "application/json");
// Add: trpc-trans-info: json
#ifdef TRPC_ENABLE_HTTP_TRANSINFO_BASE64
r->SetHeader("trpc-trans-info", "{\"trpc-dyeing-key\": \"MTIz\",\"trpc-client-ip\": \"MC4wLjAuMA==\"}");
#else
r->SetHeader("trpc-trans-info", "{\"trpc-dyeing-key\": \"123\",\"trpc-client-ip\": \"0.0.0.0\"}");
#endif
r->SetContent("{\"msg\": \"helloworld\"}");
}

Expand Down Expand Up @@ -157,6 +161,7 @@ TEST_F(TrpcOverHttpServerCodecTest, Encode) {
ServerContextPtr context = MakeRefCounted<ServerContext>();
context->SetRequestMsg(codec_.CreateRequestObject());
context->SetResponseMsg(codec_.CreateResponseObject());
context->AddRspTransInfo("trpc-dyeing-key", "123");

http::RequestPtr r = std::make_shared<http::Request>();
FillHttpRequest(r);
Expand All @@ -180,6 +185,11 @@ TEST_F(TrpcOverHttpServerCodecTest, Encode) {
"trpc-call-type: 0\r\n"
"trpc-error-msg: \r\n"
"trpc-request-id: 1\r\n"
#ifdef TRPC_ENABLE_HTTP_TRANSINFO_BASE64
"trpc-trans-info: {\"trpc-dyeing-key\":\"MTIz\"}\r\n"
#else
"trpc-trans-info: {\"trpc-dyeing-key\":\"123\"}\r\n"
#endif
"trpc-message-type: 0\r\n"
"\r\n";
ASSERT_EQ(expect_out, FlattenSlow(out)) << "xxx compress type:" << context->GetReqCompressType();
Expand Down