This is an automated email from the ASF dual-hosted git repository.

wwbmmm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new fb619582 http response uses brpc error code (#1927)
fb619582 is described below

commit fb619582a045e88520db8eb441a329912706038c
Author: chenBright <[email protected]>
AuthorDate: Mon Sep 26 10:10:22 2022 +0800

    http response uses brpc error code (#1927)
    
    * http response uses brpc error code
    
    * add gflag for using http error code
    
    * add unit test of http error code
---
 src/brpc/policy/http_rpc_protocol.cpp |  14 ++-
 test/brpc_server_unittest.cpp         | 157 ++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 1 deletion(-)

diff --git a/src/brpc/policy/http_rpc_protocol.cpp 
b/src/brpc/policy/http_rpc_protocol.cpp
index 7ae08cb7..6e32598f 100644
--- a/src/brpc/policy/http_rpc_protocol.cpp
+++ b/src/brpc/policy/http_rpc_protocol.cpp
@@ -77,6 +77,9 @@ DEFINE_bool(pb_enum_as_number, false,
 
 DEFINE_string(request_id_header, "x-request-id", "The http header to mark a 
session");
 
+DEFINE_bool(use_http_error_code, false, "Whether set the x-bd-error-code 
header "
+                                        "of http response to brpc error code");
+
 // Read user address from the header specified by -http_header_of_user_ip
 static bool GetUserAddressFromHeaderImpl(const HttpHeader& headers,
                                          butil::EndPoint* user_addr) {
@@ -395,7 +398,16 @@ void ProcessHttpResponse(InputMessageBase* msg) {
                     &err, std::min((int)res_body.size(),
                                         FLAGS_http_max_error_length));
             }
-            cntl->SetFailed(EHTTP, "%s", err.c_str());
+            // If server return brpc error code by x-bd-error-code,
+            // set the returned error code to controller. Otherwise,
+            // set EHTTP to controller uniformly.
+            const std::string* error_code_ptr = 
res_header->GetHeader(common->ERROR_CODE);
+            int error_code = error_code_ptr ? strtol(error_code_ptr->data(), 
NULL, 10) : 0;
+            if (FLAGS_use_http_error_code && error_code != 0) {
+                cntl->SetFailed(error_code, "%s", err.c_str());
+            } else {
+                cntl->SetFailed(EHTTP, "%s", err.c_str());
+            }
             if (cntl->response() == NULL ||
                 cntl->response()->GetDescriptor()->field_count() == 0) {
                 // A http call. Http users may need the body(containing a html,
diff --git a/test/brpc_server_unittest.cpp b/test/brpc_server_unittest.cpp
index 98747a04..c22b6b53 100644
--- a/test/brpc_server_unittest.cpp
+++ b/test/brpc_server_unittest.cpp
@@ -64,6 +64,11 @@ int main(int argc, char* argv[]) {
 namespace brpc {
 DECLARE_bool(enable_threads_service);
 DECLARE_bool(enable_dir_service);
+
+namespace policy {
+DECLARE_bool(use_http_error_code);
+}
+
 }
 
 namespace {
@@ -929,6 +934,158 @@ TEST_F(ServerTest, restful_mapping) {
     ASSERT_EQ(0u, server1._global_restful_map->size());
 }
 
+TEST_F(ServerTest, http_error_code) {
+    brpc::policy::FLAGS_use_http_error_code = true;
+
+    const int port = 9200;
+    // missing_required_fields -> brpc::EREQUEST
+    {
+        brpc::Server server1;
+        EchoServiceV1 service_v1;
+        ASSERT_EQ(0, server1.AddService(&service_v1, 
brpc::SERVER_DOESNT_OWN_SERVICE));
+        ASSERT_EQ(0, server1.Start(port, NULL));
+
+        brpc::Channel http_channel;
+        brpc::ChannelOptions chan_options;
+        chan_options.protocol = "http";
+        ASSERT_EQ(0, http_channel.Init("0.0.0.0", port, &chan_options));
+        brpc::Controller cntl;
+        cntl.http_request().uri() = "/EchoService/Echo";
+        http_channel.CallMethod(NULL, &cntl, NULL, NULL, NULL);
+        ASSERT_TRUE(cntl.Failed());
+        ASSERT_EQ(brpc::EREQUEST, cntl.ErrorCode());
+        LOG(INFO) << cntl.ErrorText();
+        ASSERT_EQ(brpc::HTTP_STATUS_BAD_REQUEST, 
cntl.http_response().status_code());
+        ASSERT_EQ(0, service_v1.ncalled.load());
+    }
+
+    // disallow_http_body_to_pb -> brpc::ERESPONSE
+    {
+        brpc::Server server1;
+        EchoServiceV1 service_v1;
+        brpc::ServiceOptions svc_opt;
+        svc_opt.allow_http_body_to_pb = false;
+        svc_opt.restful_mappings = "/access_echo1=>Echo";
+        ASSERT_EQ(0, server1.AddService(&service_v1, svc_opt));
+        ASSERT_EQ(0, server1.Start(port, NULL));
+        brpc::Channel http_channel;
+        brpc::ChannelOptions chan_options;
+        chan_options.protocol = "http";
+        ASSERT_EQ(0, http_channel.Init("0.0.0.0", port, &chan_options));
+        brpc::Controller cntl;
+        cntl.http_request().uri() = "/access_echo1";
+        http_channel.CallMethod(NULL, &cntl, NULL, NULL, NULL);
+        ASSERT_TRUE(cntl.Failed());
+        ASSERT_EQ(brpc::ERESPONSE, cntl.ErrorCode());
+        ASSERT_EQ(brpc::HTTP_STATUS_INTERNAL_SERVER_ERROR,
+            cntl.http_response().status_code());
+        ASSERT_EQ(1, service_v1.ncalled.load());
+    }
+
+    // restful_mapping -> brpc::ENOMETHOD
+    {
+        brpc::Server server1;
+        EchoServiceV1 service_v1;
+        ASSERT_EQ(0u, server1.service_count());
+        ASSERT_EQ(0, server1.AddService(
+            &service_v1,
+            brpc::SERVER_DOESNT_OWN_SERVICE,
+            "/v1/echo/ => Echo,"
+
+            // Map another path to the same method is ok.
+            "/v3/echo => Echo,"
+
+            // end with wildcard
+            "/v2/echo/* => Echo,"
+
+            // single-component path should be OK
+            "/v4_echo => Echo,"
+
+            // heading slash can be ignored
+            " v5/echo => Echo,"
+
+            // with or without wildcard can coexist.
+            " /v6/echo => Echo,"
+            " /v6/echo/* => Echo2,"
+            " /v6/abc/*/def => Echo3,"
+            " /v6/echo/*.flv => Echo4,"
+            " /v6/*.flv => Echo5,"
+            " *.flv => Echo,"
+        ));
+        ASSERT_EQ(1u, server1.service_count());
+        ASSERT_TRUE(server1._global_restful_map);
+        ASSERT_EQ(1UL, server1._global_restful_map->size());
+
+        ASSERT_EQ(0, server1.Start(port, NULL));
+        brpc::Channel http_channel;
+        brpc::ChannelOptions chan_options;
+        chan_options.protocol = "http";
+        ASSERT_EQ(0, http_channel.Init("0.0.0.0", port, &chan_options));
+        brpc::Controller cntl;
+        cntl.http_request().uri() = "/v3/echo/anything";
+        cntl.http_request().set_method(brpc::HTTP_METHOD_POST);
+        cntl.request_attachment().append("{\"message\":\"foo\"}");
+        http_channel.CallMethod(NULL, &cntl, NULL, NULL, NULL);
+        ASSERT_TRUE(cntl.Failed());
+        ASSERT_EQ(brpc::ENOMETHOD, cntl.ErrorCode());
+        LOG(INFO) << "Expected error: " << cntl.ErrorText();
+        ASSERT_EQ(0, service_v1.ncalled.load());
+    }
+
+    // max_concurrency -> brpc::ELIMIT
+    {
+        brpc::Server server1;
+        EchoServiceImpl service1;
+        ASSERT_EQ(0, server1.AddService(&service1, 
brpc::SERVER_DOESNT_OWN_SERVICE));
+        server1.MaxConcurrencyOf("test.EchoService.Echo") = 1;
+        ASSERT_EQ(1, server1.MaxConcurrencyOf("test.EchoService.Echo"));
+        server1.MaxConcurrencyOf(&service1, "Echo") = 2;
+        ASSERT_EQ(2, server1.MaxConcurrencyOf(&service1, "Echo"));
+
+        ASSERT_EQ(0, server1.Start(port, NULL));
+        brpc::Channel http_channel;
+        brpc::ChannelOptions chan_options;
+        chan_options.protocol = "http";
+        ASSERT_EQ(0, http_channel.Init("0.0.0.0", port, &chan_options));
+
+        brpc::Channel normal_channel;
+        ASSERT_EQ(0, normal_channel.Init("0.0.0.0", port, NULL));
+        test::EchoService_Stub stub(&normal_channel);
+
+        brpc::Controller cntl1;
+        cntl1.http_request().uri() = "/EchoService/Echo";
+        cntl1.http_request().set_method(brpc::HTTP_METHOD_POST);
+        
cntl1.request_attachment().append("{\"message\":\"hello\",\"sleep_us\":100000}");
+        http_channel.CallMethod(NULL, &cntl1, NULL, NULL, brpc::DoNothing());
+
+        brpc::Controller cntl2;
+        test::EchoRequest req;
+        test::EchoResponse res;
+        req.set_message("hello");
+        req.set_sleep_us(100000);
+        stub.Echo(&cntl2, &req, &res, brpc::DoNothing());
+
+        bthread_usleep(20000);
+        LOG(INFO) << "Send other requests";
+
+        brpc::Controller cntl3;
+        cntl3.http_request().uri() = "/EchoService/Echo";
+        cntl3.http_request().set_method(brpc::HTTP_METHOD_POST);
+        cntl3.request_attachment().append("{\"message\":\"hello\"}");
+        http_channel.CallMethod(NULL, &cntl3, NULL, NULL, NULL);
+        ASSERT_TRUE(cntl3.Failed());
+        ASSERT_EQ(brpc::ELIMIT, cntl3.ErrorCode());
+        ASSERT_EQ(brpc::HTTP_STATUS_SERVICE_UNAVAILABLE, 
cntl3.http_response().status_code());
+
+        brpc::Join(cntl1.call_id());
+        brpc::Join(cntl2.call_id());
+        ASSERT_FALSE(cntl1.Failed()) << cntl1.ErrorText();
+        ASSERT_FALSE(cntl2.Failed()) << cntl2.ErrorText();
+    }
+
+    brpc::policy::FLAGS_use_http_error_code = false;
+}
+
 TEST_F(ServerTest, conflict_name_between_restful_mapping_and_builtin) {
     const int port = 9200;
     EchoServiceV1 service_v1;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to