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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3ca88dea Enforce internal_port gating of builtin services in pb 
protocols (#3511)
3ca88dea is described below

commit 3ca88deae01d6c9f9ca1e7313f9c0ce8db966e90
Author: Bright Chen <[email protected]>
AuthorDate: Wed Sep 2 16:55:13 2026 +0800

    Enforce internal_port gating of builtin services in pb protocols (#3511)
---
 src/brpc/builtin/bad_method_service.cpp        |   9 +
 src/brpc/details/controller_private_accessor.h |  16 +-
 src/brpc/details/server_private_accessor.h     |  23 +++
 src/brpc/nshead_pb_service_adaptor.cpp         |   3 +
 src/brpc/policy/baidu_rpc_protocol.cpp         |  27 +--
 src/brpc/policy/http_rpc_protocol.cpp          |  15 +-
 src/brpc/policy/hulu_pbrpc_protocol.cpp        |   7 +-
 src/brpc/policy/mongo_protocol.cpp             |  14 +-
 src/brpc/policy/sofa_pbrpc_protocol.cpp        |   3 +
 test/brpc_server_unittest.cpp                  | 222 +++++++++++++++++++++++++
 10 files changed, 305 insertions(+), 34 deletions(-)

diff --git a/src/brpc/builtin/bad_method_service.cpp 
b/src/brpc/builtin/bad_method_service.cpp
index 5d5ed326..dde401f4 100644
--- a/src/brpc/builtin/bad_method_service.cpp
+++ b/src/brpc/builtin/bad_method_service.cpp
@@ -45,6 +45,15 @@ void 
BadMethodService::no_method(::google::protobuf::RpcController* cntl_base,
 
     std::ostringstream os;
     os << "Missing method name for service=" << request->service_name() << '.';
+
+    // Requests from the public port must not learn anything more about the
+    // services of the server when ServerOptions.internal_port is set,
+    // especially not the methods of a builtin service.
+    if (cntl->is_security_mode()) {
+        cntl->SetFailed(ENOMETHOD, "%s", os.str().c_str());
+        return;
+    }
+
     const Server::ServiceProperty* sp = ServerPrivateAccessor(server)
         .FindServicePropertyAdaptively(request->service_name());
     if (sp != nullptr && sp->service != nullptr) {
diff --git a/src/brpc/details/controller_private_accessor.h 
b/src/brpc/details/controller_private_accessor.h
index fc4b9666..1aad5b2b 100644
--- a/src/brpc/details/controller_private_accessor.h
+++ b/src/brpc/details/controller_private_accessor.h
@@ -71,31 +71,31 @@ public:
         return _cntl->_current_call.stream_user_data;
     }
 
-    ControllerPrivateAccessor &set_security_mode(bool security_mode) {
+    ControllerPrivateAccessor& set_security_mode(bool security_mode) {
         _cntl->set_flag(Controller::FLAGS_SECURITY_MODE, security_mode);
         return *this;
     }
 
-    ControllerPrivateAccessor &set_remote_side(const butil::EndPoint& pt) {
+    ControllerPrivateAccessor& set_remote_side(const butil::EndPoint& pt) {
         _cntl->_remote_side = pt;
         return *this;
     }
 
-    ControllerPrivateAccessor &set_local_side(const butil::EndPoint& pt) {
+    ControllerPrivateAccessor& set_local_side(const butil::EndPoint& pt) {
         _cntl->_local_side = pt;
         return *this;
     }
  
-    ControllerPrivateAccessor &set_auth_context(const AuthContext* ctx) {
+    ControllerPrivateAccessor& set_auth_context(const AuthContext* ctx) {
         _cntl->set_auth_context(ctx);
         return *this;
     }
 
     // Overloaded set_span methods to support both shared_ptr and raw pointer
-    ControllerPrivateAccessor &set_span(const std::shared_ptr<Span>& span);
-    ControllerPrivateAccessor &set_span(Span* span);
+    ControllerPrivateAccessor& set_span(const std::shared_ptr<Span>& span);
+    ControllerPrivateAccessor& set_span(Span* span);
     
-    ControllerPrivateAccessor &set_request_protocol(ProtocolType protocol) {
+    ControllerPrivateAccessor& set_request_protocol(ProtocolType protocol) {
         _cntl->_request_protocol = protocol;
         return *this;
     }
@@ -196,7 +196,7 @@ private:
 // utility only useable by brpc developers.
 class RPCSender {
 public:
-    virtual ~RPCSender() {}
+    virtual ~RPCSender() = default;
     virtual int IssueRPC(int64_t start_realtime_us) = 0;
 };
 
diff --git a/src/brpc/details/server_private_accessor.h 
b/src/brpc/details/server_private_accessor.h
index d553b4dc..ee7929dd 100644
--- a/src/brpc/details/server_private_accessor.h
+++ b/src/brpc/details/server_private_accessor.h
@@ -104,6 +104,29 @@ private:
     const Server* _server;
 };
 
+// Reject accesses to builtin services when the server is in security mode,
+// in which case they are only reachable from ServerOptions.internal_port.
+// Returns true if the access was rejected, in which case `cntl` was already
+// SetFailed() and the caller must stop dispatching the request immediately.
+// NOTE: Call this after ControllerPrivateAccessor::set_security_mode() and
+// before the method is counted by MethodStatus::OnRequested(), so that
+// rejected accesses do not pollute the stats of the method. `mp` may point
+// to BadMethodService which is builtin as well and lists the methods of the
+// requested service, so protocols dispatching to BadMethodService must call
+// this beforehand, or make sure the listing is hidden in security mode.
+inline bool RejectBuiltinAccess(Controller* cntl, const Server& server,
+                                const Server::MethodProperty* mp) {
+    if (!cntl->is_security_mode() ||
+        (!mp->is_builtin_service && !mp->params.is_tabbed)) {
+        return false;
+    }
+    cntl->SetFailed(EPERM, "Not allowed to access builtin services, try "
+                                    "ServerOptions.internal_port=%d instead if 
you're in "
+                                    "internal network",
+                    server.options().internal_port);
+    return true;
+}
+
 // Count one error if release() is not called before destruction of this 
object.
 class ScopedNonServiceError {
 public:
diff --git a/src/brpc/nshead_pb_service_adaptor.cpp 
b/src/brpc/nshead_pb_service_adaptor.cpp
index 956e1508..17e29228 100644
--- a/src/brpc/nshead_pb_service_adaptor.cpp
+++ b/src/brpc/nshead_pb_service_adaptor.cpp
@@ -122,6 +122,9 @@ void NsheadPbServiceAdaptor::ProcessNsheadRequest(
                                   meta->full_method_name().c_str());
             break;
         }
+        if (RejectBuiltinAccess(controller, server, sp)) {
+            break;
+        }
         pbdone->status = sp->status;
         sp->status->OnRequested();
 
diff --git a/src/brpc/policy/baidu_rpc_protocol.cpp 
b/src/brpc/policy/baidu_rpc_protocol.cpp
index f39463e8..5a6451b0 100644
--- a/src/brpc/policy/baidu_rpc_protocol.cpp
+++ b/src/brpc/policy/baidu_rpc_protocol.cpp
@@ -714,13 +714,13 @@ void ProcessRpcRequest(InputMessageBase* msg_base) {
         google::protobuf::Service* svc = nullptr;
         google::protobuf::MethodDescriptor* method = nullptr;
         if (nullptr != server->options().baidu_master_service) {
-          if (socket->is_overcrowded() &&
+            if (socket->is_overcrowded() &&
               !server->options().ignore_eovercrowded &&
               !server->options().baidu_master_service->ignore_eovercrowded()) {
-            cntl->SetFailed(EOVERCROWDED, "Connection to %s is overcrowded",
-                            
butil::endpoint2str(socket->remote_side()).c_str());
+                cntl->SetFailed(EOVERCROWDED, "Connection to %s is 
overcrowded",
+                                
butil::endpoint2str(socket->remote_side()).c_str());
             break;
-          }
+            }
             svc = server->options().baidu_master_service;
             auto sampled_request = new SampledRequest;
             
sampled_request->meta.set_service_name(request_meta.service_name());
@@ -732,10 +732,8 @@ void ProcessRpcRequest(InputMessageBase* msg_base) {
             if (method_status) {
                 int rejected_cc = 0;
                 if (!method_status->OnRequested(&rejected_cc, cntl.get())) {
-                    cntl->SetFailed(
-                        ELIMIT,
-                        "Rejected by %s's ConcurrencyLimiter, concurrency=%d",
-                        butil::class_name<BaiduMasterService>(), rejected_cc);
+                    cntl->SetFailed(ELIMIT, "Rejected by %s's 
ConcurrencyLimiter, concurrency=%d",
+                                    butil::class_name<BaiduMasterService>(), 
rejected_cc);
                     break;
                 }
             }
@@ -744,9 +742,8 @@ void ProcessRpcRequest(InputMessageBase* msg_base) {
             }
 
             messages = BaiduProxyPBMessages::Get();
-            msg->payload.cutn(
-                &((SerializedRequest*)messages->Request())->serialized_data(),
-                req_size - meta.attachment_size());
+            
msg->payload.cutn(&((SerializedRequest*)messages->Request())->serialized_data(),
+                              req_size - meta.attachment_size());
             if (!msg->payload.empty()) {
                 cntl->request_attachment().swap(msg->payload);
             }
@@ -759,7 +756,7 @@ void ProcessRpcRequest(InputMessageBase* msg_base) {
                     server_accessor.FindServicePropertyByName(svc_name);
                 if (nullptr == sp) {
                     cntl->SetFailed(ENOSERVICE, "Fail to find service=%s",
-                        request_meta.service_name().c_str());
+                                    request_meta.service_name().c_str());
                     break;
                 }
                 svc_name = sp->service->GetDescriptor()->full_name();
@@ -772,7 +769,11 @@ void ProcessRpcRequest(InputMessageBase* msg_base) {
                                 request_meta.service_name().c_str(),
                                 request_meta.method_name().c_str());
                 break;
-            } else if (mp->service->GetDescriptor() == 
BadMethodService::descriptor()) {
+            }
+            if (RejectBuiltinAccess(cntl.get(), *server, mp)) {
+                break;
+            }
+            if (mp->service->GetDescriptor() == 
BadMethodService::descriptor()) {
                 BadMethodRequest breq;
                 BadMethodResponse bres;
                 breq.set_service_name(request_meta.service_name());
diff --git a/src/brpc/policy/http_rpc_protocol.cpp 
b/src/brpc/policy/http_rpc_protocol.cpp
index 9d63de23..f09f2c83 100644
--- a/src/brpc/policy/http_rpc_protocol.cpp
+++ b/src/brpc/policy/http_rpc_protocol.cpp
@@ -1573,6 +1573,13 @@ void ProcessHttpRequest(InputMessageBase *msg) {
         }
         return;
     } else if (mp->service->GetDescriptor() == BadMethodService::descriptor()) 
{
+        // NOTE: Unlike pb protocols, a http request falls back to
+        // BadMethodService whenever the URL only carries a service name,
+        // no matter whether the service is builtin or not. Rejecting it here
+        // would turn a helpful "missing method name" hint into a confusing
+        // "not allowed to access builtin services" for normal services, so the
+        // request is dispatched instead and BadMethodService itself hides the
+        // list of available methods in security mode.
         BadMethodRequest breq;
         BadMethodResponse bres;
         butil::StringSplitter split(path.c_str(), '/');
@@ -1580,6 +1587,9 @@ void ProcessHttpRequest(InputMessageBase *msg) {
         mp->service->CallMethod(mp->method, cntl, &breq, &bres, nullptr);
         return;
     }
+    if (RejectBuiltinAccess(cntl, *server, mp)) {
+        return;
+    }
     // Switch to service-specific error.
     non_service_error.release();
     MethodStatus* method_status = mp->status;
@@ -1620,11 +1630,6 @@ void ProcessHttpRequest(InputMessageBase *msg) {
         if (!server->AcceptRequest(cntl)) {
             return;
         }
-    } else if (security_mode) {
-        cntl->SetFailed(EPERM, "Not allowed to access builtin services, try "
-                        "ServerOptions.internal_port=%d instead if you're in"
-                        " internal network", server->options().internal_port);
-        return;
     }
 
     google::protobuf::Service* svc = mp->service;
diff --git a/src/brpc/policy/hulu_pbrpc_protocol.cpp 
b/src/brpc/policy/hulu_pbrpc_protocol.cpp
index cb397a49..4bacd9e5 100644
--- a/src/brpc/policy/hulu_pbrpc_protocol.cpp
+++ b/src/brpc/policy/hulu_pbrpc_protocol.cpp
@@ -449,8 +449,11 @@ void ProcessHuluRequest(InputMessageBase* msg_base) {
             cntl->SetFailed(ENOMETHOD, "Fail to find method=%d of service=%s",
                             meta.method_index(), meta.service_name().c_str());
             break;
-        } else if (sp->service->GetDescriptor()
-                   == BadMethodService::descriptor()) {
+        }
+        if (RejectBuiltinAccess(cntl.get(), *server, sp)) {
+            break;
+        }
+        if (sp->service->GetDescriptor() == BadMethodService::descriptor()) {
             BadMethodRequest breq;
             BadMethodResponse bres;
             breq.set_service_name(meta.service_name());
diff --git a/src/brpc/policy/mongo_protocol.cpp 
b/src/brpc/policy/mongo_protocol.cpp
index cae64b5b..3c7262d4 100644
--- a/src/brpc/policy/mongo_protocol.cpp
+++ b/src/brpc/policy/mongo_protocol.cpp
@@ -197,11 +197,11 @@ void ProcessMongoRequest(InputMessageBase* msg_base) {
                      << " of MongoService should be equal to 1!";
     }
 
-    const Server::MethodProperty *mp =
-            ServerPrivateAccessor(server)
-            .FindMethodPropertyByFullName(srv_des->method(0)->full_name());
+    ServerPrivateAccessor server_accessor(server);
+    const Server::MethodProperty *mp = 
server_accessor.FindMethodPropertyByFullName(
+        srv_des->method(0)->full_name());
 
-    MongoContextMessage *context_msg =
+    MongoContextMessage* context_msg =
         dynamic_cast<MongoContextMessage*>(socket->parsing_context());
     if (nullptr == context_msg) {
         LOG(WARNING) << "socket context wasn't set correctly";
@@ -212,8 +212,10 @@ void ProcessMongoRequest(InputMessageBase* msg_base) {
     mongo_done->cntl.set_mongo_session_data(context_msg->context());
 
     ControllerPrivateAccessor accessor(&(mongo_done->cntl));
+    const bool security_mode = server->options().security_mode() &&
+                               socket->user() == server_accessor.acceptor();
     accessor.set_server(server)
-        .set_security_mode(server->options().security_mode())
+        .set_security_mode(security_mode)
         .set_peer_id(socket->id())
         .set_remote_side(socket->remote_side())
         .set_local_side(socket->local_side())
@@ -233,7 +235,7 @@ void ProcessMongoRequest(InputMessageBase* msg_base) {
             break;
         }
 
-        if 
(!ServerPrivateAccessor(server).AddConcurrency(&(mongo_done->cntl))) {
+        if (!server_accessor.AddConcurrency(&(mongo_done->cntl))) {
             mongo_done->cntl.SetFailed(
                 ELIMIT, "Reached server's max_concurrency=%d",
                 server->options().max_concurrency);
diff --git a/src/brpc/policy/sofa_pbrpc_protocol.cpp 
b/src/brpc/policy/sofa_pbrpc_protocol.cpp
index 6b663c19..d0c42cc4 100644
--- a/src/brpc/policy/sofa_pbrpc_protocol.cpp
+++ b/src/brpc/policy/sofa_pbrpc_protocol.cpp
@@ -410,6 +410,9 @@ void ProcessSofaRequest(InputMessageBase* msg_base) {
                             meta.method().c_str());
             break;
         }
+        if (RejectBuiltinAccess(cntl.get(), *server, sp)) {
+            break;
+        }
         if (socket->is_overcrowded() &&
             !server->options().ignore_eovercrowded &&
             !sp->ignore_eovercrowded) {
diff --git a/test/brpc_server_unittest.cpp b/test/brpc_server_unittest.cpp
index ed0268e8..8e386b2a 100644
--- a/test/brpc_server_unittest.cpp
+++ b/test/brpc_server_unittest.cpp
@@ -1483,6 +1483,228 @@ TEST_F(ServerTest, add_builtin_service) {
     }
 }
 
+// Call the builtin `brpc.version` service through a pb protocol.
+void CallVersionByPb(const butil::EndPoint& ep,
+                     brpc::ProtocolType protocol,
+                     brpc::Controller* cntl) {
+    brpc::ChannelOptions copt;
+    copt.protocol = protocol;
+    copt.max_retry = 0;
+    brpc::Channel chan;
+    ASSERT_EQ(0, chan.Init(ep, &copt));
+    brpc::VersionRequest req;
+    brpc::VersionResponse res;
+    brpc::version_Stub stub(&chan);
+    stub.default_method(cntl, &req, &res, nullptr);
+}
+
+// Call the same builtin service the way a browser would.
+void CallVersionByHttp(const butil::EndPoint& ep,
+                       brpc::Controller* cntl) {
+    brpc::ChannelOptions copt;
+    copt.protocol = brpc::PROTOCOL_HTTP;
+    copt.max_retry = 0;
+    brpc::Channel chan;
+    ASSERT_EQ(0, chan.Init(ep, &copt));
+    cntl->http_request().uri() = "/version";
+    chan.CallMethod(nullptr, cntl, nullptr, nullptr, nullptr);
+}
+
+// Call an ordinary (non-builtin) service through a pb protocol.
+void CallEchoByPb(const butil::EndPoint& ep,
+                  brpc::ProtocolType protocol,
+                  brpc::Controller* cntl) {
+    brpc::ChannelOptions copt;
+    copt.protocol = protocol;
+    copt.max_retry = 0;
+    brpc::Channel chan;
+    ASSERT_EQ(0, chan.Init(ep, &copt));
+    test::EchoRequest req;
+    test::EchoResponse res;
+    req.set_message(EXP_REQUEST);
+    test::EchoService_Stub stub(&chan);
+    stub.Echo(cntl, &req, &res, nullptr);
+}
+
+// Builtin services must be gated by ServerOptions.internal_port no matter
+// which protocol carries the request.
+TEST_F(ServerTest, builtin_services_are_gated_by_internal_port) {
+    const struct {
+        brpc::ProtocolType protocol;
+        const char* name;
+    } cases[] = {
+        { brpc::PROTOCOL_BAIDU_STD, "baidu_std" },
+        { brpc::PROTOCOL_HULU_PBRPC, "hulu_pbrpc" },
+        { brpc::PROTOCOL_SOFA_PBRPC, "sofa_pbrpc" },
+    };
+
+    butil::EndPoint ep;
+    ASSERT_EQ(0, str2endpoint("127.0.0.1:8613", &ep));
+    butil::EndPoint internal_ep;
+    ASSERT_EQ(0, str2endpoint("127.0.0.1:8614", &internal_ep));
+
+    brpc::Server server;
+    EchoServiceImpl echo_svc;
+    ASSERT_EQ(0, server.AddService(&echo_svc, 
brpc::SERVER_DOESNT_OWN_SERVICE));
+    brpc::ServerOptions opt;
+    opt.internal_port = internal_ep.port;
+    ASSERT_EQ(0, server.Start(ep, &opt));
+    ASSERT_TRUE(server.options().security_mode());
+
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+        // Not reachable from the public port ...
+        brpc::Controller cntl;
+        CallVersionByPb(ep, cases[i].protocol, &cntl);
+        ASSERT_EQ(EPERM, cntl.ErrorCode())
+            << cases[i].name << ": " << cntl.ErrorText();
+
+        // ... but reachable from internal_port.
+        cntl.Reset();
+        CallVersionByPb(internal_ep, cases[i].protocol, &cntl);
+        ASSERT_FALSE(cntl.Failed())
+            << cases[i].name << ": " << cntl.ErrorText();
+
+        // Ordinary services on the public port are unaffected.
+        cntl.Reset();
+        CallEchoByPb(ep, cases[i].protocol, &cntl);
+        ASSERT_FALSE(cntl.Failed())
+            << cases[i].name << ": " << cntl.ErrorText();
+    }
+
+    // http was gated before, make sure it stays that way.
+    brpc::Controller cntl;
+    CallVersionByHttp(ep, &cntl);
+    ASSERT_TRUE(cntl.Failed());
+    ASSERT_EQ(brpc::HTTP_STATUS_FORBIDDEN, cntl.http_response().status_code())
+        << cntl.ErrorText();
+    cntl.Reset();
+    CallVersionByHttp(internal_ep, &cntl);
+    ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText();
+
+    ASSERT_EQ(0, server.Stop(0));
+    ASSERT_EQ(0, server.Join());
+}
+
+// A service-name-only URL is dispatched to the builtin BadMethodService which
+// lists the methods of the service.
+void CallServiceWithoutMethodByHttp(const butil::EndPoint& ep,
+                                    brpc::Controller* cntl) {
+    brpc::ChannelOptions copt;
+    copt.protocol = brpc::PROTOCOL_HTTP;
+    copt.max_retry = 0;
+    brpc::Channel chan;
+    ASSERT_EQ(0, chan.Init(ep, &copt));
+    cntl->http_request().uri() = "/EchoService";
+    chan.CallMethod(nullptr, cntl, nullptr, nullptr, nullptr);
+}
+
+// Ask for the builtin BadMethodService on purpose, which a pb client can do
+// since the service is registered like any other builtin service.
+void CallBadMethodByPb(const butil::EndPoint& ep,
+                       brpc::ProtocolType protocol,
+                       brpc::Controller* cntl) {
+    brpc::ChannelOptions copt;
+    copt.protocol = protocol;
+    copt.max_retry = 0;
+    brpc::Channel chan;
+    ASSERT_EQ(0, chan.Init(ep, &copt));
+    brpc::BadMethodRequest req;
+    brpc::BadMethodResponse res;
+    req.set_service_name("EchoService");
+    brpc::badmethod_Stub stub(&chan);
+    stub.no_method(cntl, &req, &res, nullptr);
+}
+
+// BadMethodService is builtin as well and it lists the methods of a service,
+// so it must not be reachable from the public port in security mode. The http
+// fallback to BadMethodService is an exception: it must keep reporting the
+// missing method name, only without listing the methods.
+TEST_F(ServerTest, bad_method_does_not_leak_methods_in_security_mode) {
+    butil::EndPoint ep;
+    ASSERT_EQ(0, str2endpoint("127.0.0.1:8613", &ep));
+    butil::EndPoint internal_ep;
+    ASSERT_EQ(0, str2endpoint("127.0.0.1:8614", &internal_ep));
+
+    brpc::Server server;
+    EchoServiceImpl echo_svc;
+    ASSERT_EQ(0, server.AddService(&echo_svc, 
brpc::SERVER_DOESNT_OWN_SERVICE));
+    brpc::ServerOptions opt;
+    opt.internal_port = internal_ep.port;
+    ASSERT_EQ(0, server.Start(ep, &opt));
+    ASSERT_TRUE(server.options().security_mode());
+
+    const struct {
+        brpc::ProtocolType protocol;
+        const char* name;
+    } cases[] = {
+        { brpc::PROTOCOL_BAIDU_STD, "baidu_std" },
+        { brpc::PROTOCOL_HULU_PBRPC, "hulu_pbrpc" },
+        { brpc::PROTOCOL_SOFA_PBRPC, "sofa_pbrpc" },
+    };
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+        brpc::Controller cntl;
+        CallBadMethodByPb(ep, cases[i].protocol, &cntl);
+        ASSERT_EQ(EPERM, cntl.ErrorCode())
+            << cases[i].name << ": " << cntl.ErrorText();
+        ASSERT_EQ(std::string::npos, cntl.ErrorText().find("Available 
methods"))
+            << cases[i].name << ": " << cntl.ErrorText();
+
+        cntl.Reset();
+        CallBadMethodByPb(internal_ep, cases[i].protocol, &cntl);
+        ASSERT_EQ(brpc::ENOMETHOD, cntl.ErrorCode())
+            << cases[i].name << ": " << cntl.ErrorText();
+        ASSERT_NE(std::string::npos, cntl.ErrorText().find("Available 
methods"))
+            << cases[i].name << ": " << cntl.ErrorText();
+    }
+
+    // http still tells that the method name is missing, but without listing
+    // the methods of the service.
+    brpc::Controller cntl;
+    CallServiceWithoutMethodByHttp(ep, &cntl);
+    ASSERT_TRUE(cntl.Failed());
+    ASSERT_EQ(brpc::HTTP_STATUS_NOT_FOUND, cntl.http_response().status_code())
+        << cntl.ErrorText();
+    ASSERT_NE(std::string::npos, cntl.ErrorText().find("Missing method name"))
+        << cntl.ErrorText();
+    ASSERT_EQ(std::string::npos, cntl.ErrorText().find("Available methods"))
+        << cntl.ErrorText();
+
+    cntl.Reset();
+    CallServiceWithoutMethodByHttp(internal_ep, &cntl);
+    ASSERT_TRUE(cntl.Failed());
+    ASSERT_EQ(brpc::HTTP_STATUS_NOT_FOUND, cntl.http_response().status_code())
+        << cntl.ErrorText();
+    ASSERT_NE(std::string::npos, cntl.ErrorText().find("Available methods"))
+        << cntl.ErrorText();
+
+    ASSERT_EQ(0, server.Stop(0));
+    ASSERT_EQ(0, server.Join());
+}
+
+// Without internal_port the server is not in security mode and builtin
+// services stay reachable from the only port, which is the default behavior.
+TEST_F(ServerTest, builtin_services_are_open_without_internal_port) {
+    butil::EndPoint ep;
+    ASSERT_EQ(0, str2endpoint("127.0.0.1:8613", &ep));
+
+    brpc::Server server;
+    EchoServiceImpl echo_svc;
+    ASSERT_EQ(0, server.AddService(&echo_svc, 
brpc::SERVER_DOESNT_OWN_SERVICE));
+    ASSERT_EQ(0, server.Start(ep, nullptr));
+    ASSERT_FALSE(server.options().security_mode());
+
+    brpc::Controller cntl;
+    CallVersionByPb(ep, brpc::PROTOCOL_BAIDU_STD, &cntl);
+    ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText();
+
+    cntl.Reset();
+    CallVersionByHttp(ep, &cntl);
+    ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText();
+
+    ASSERT_EQ(0, server.Stop(0));
+    ASSERT_EQ(0, server.Join());
+}
+
 TEST_F(ServerTest, base64_to_string) {
     // We test two cases as following. If these two tests can be passed, we
     // can prove that the pb_bytes_to_base64 flag is working in both client 
side


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

Reply via email to