Commit 7acd1623 authored by gejun's avatar gejun

Controller.SetFailed sets status_code as well

parent c1966538
...@@ -45,7 +45,6 @@ void BthreadsService::default_method(::google::protobuf::RpcController* cntl_bas ...@@ -45,7 +45,6 @@ void BthreadsService::default_method(::google::protobuf::RpcController* cntl_bas
if (*endptr == '\0' || *endptr == '/') { if (*endptr == '\0' || *endptr == '/') {
::bthread::print_task(os, tid); ::bthread::print_task(os, tid);
} else { } else {
cntl->http_response().set_status_code(HTTP_STATUS_NOT_FOUND);
cntl->SetFailed(ENOMETHOD, "path=%s is not a bthread id", cntl->SetFailed(ENOMETHOD, "path=%s is not a bthread id",
constraint.c_str()); constraint.c_str());
} }
......
...@@ -372,7 +372,6 @@ static void DisplayResult(Controller* cntl, ...@@ -372,7 +372,6 @@ static void DisplayResult(Controller* cntl,
if (use_html) { if (use_html) {
resp.append("</pre></body></html>"); resp.append("</pre></body></html>");
} }
cntl->http_response().set_status_code(HTTP_STATUS_OK);
return; return;
} }
} }
...@@ -481,7 +480,6 @@ static void DisplayResult(Controller* cntl, ...@@ -481,7 +480,6 @@ static void DisplayResult(Controller* cntl,
if (use_html) { if (use_html) {
resp.append("</pre></body></html>"); resp.append("</pre></body></html>");
} }
cntl->http_response().set_status_code(HTTP_STATUS_OK);
} }
static void DoProfiling(ProfilingType type, static void DoProfiling(ProfilingType type,
......
...@@ -47,9 +47,9 @@ void IdsService::default_method(::google::protobuf::RpcController* cntl_base, ...@@ -47,9 +47,9 @@ void IdsService::default_method(::google::protobuf::RpcController* cntl_base,
if (*endptr == '\0' || *endptr == '/') { if (*endptr == '\0' || *endptr == '/') {
bthread::id_status(id, os); bthread::id_status(id, os);
} else { } else {
cntl->http_response().set_status_code(HTTP_STATUS_NOT_FOUND);
cntl->SetFailed(ENOMETHOD, "path=%s is not a bthread_id", cntl->SetFailed(ENOMETHOD, "path=%s is not a bthread_id",
constraint.c_str()); constraint.c_str());
return;
} }
} }
os.move_to(cntl->response_attachment()); os.move_to(cntl->response_attachment());
......
...@@ -43,7 +43,6 @@ void SocketsService::default_method(::google::protobuf::RpcController* cntl_base ...@@ -43,7 +43,6 @@ void SocketsService::default_method(::google::protobuf::RpcController* cntl_base
if (*endptr == '\0' || *endptr == '/') { if (*endptr == '\0' || *endptr == '/') {
Socket::DebugSocket(os, sid); Socket::DebugSocket(os, sid);
} else { } else {
cntl->http_response().set_status_code(HTTP_STATUS_NOT_FOUND);
cntl->SetFailed(ENOMETHOD, "path=%s is not a SocketId", cntl->SetFailed(ENOMETHOD, "path=%s is not a SocketId",
constraint.c_str()); constraint.c_str());
} }
......
...@@ -318,11 +318,9 @@ void VarsService::default_method(::google::protobuf::RpcController* cntl_base, ...@@ -318,11 +318,9 @@ void VarsService::default_method(::google::protobuf::RpcController* cntl_base,
cntl->http_response().set_content_type("application/json"); cntl->http_response().set_content_type("application/json");
os.move_to(cntl->response_attachment()); os.move_to(cntl->response_attachment());
} else if (rc < 0) { } else if (rc < 0) {
cntl->http_response().set_status_code(HTTP_STATUS_NOT_FOUND);
cntl->SetFailed(ENOMETHOD, "Fail to find any bvar by `%s'", cntl->SetFailed(ENOMETHOD, "Fail to find any bvar by `%s'",
cntl->http_request().unresolved_path().c_str()); cntl->http_request().unresolved_path().c_str());
} else { } else {
cntl->http_response().set_status_code(HTTP_STATUS_NOT_FOUND);
cntl->SetFailed(ENODATA, "`%s' does not have value series", cntl->SetFailed(ENODATA, "`%s' does not have value series",
cntl->http_request().unresolved_path().c_str()); cntl->http_request().unresolved_path().c_str());
} }
...@@ -419,7 +417,6 @@ void VarsService::default_method(::google::protobuf::RpcController* cntl_base, ...@@ -419,7 +417,6 @@ void VarsService::default_method(::google::protobuf::RpcController* cntl_base,
return; return;
} }
if (!options.white_wildcards.empty() && ndump == 0) { if (!options.white_wildcards.empty() && ndump == 0) {
cntl->http_response().set_status_code(HTTP_STATUS_NOT_FOUND);
cntl->SetFailed(ENOMETHOD, "Fail to find any bvar by `%s'", cntl->SetFailed(ENOMETHOD, "Fail to find any bvar by `%s'",
options.white_wildcards.c_str()); options.white_wildcards.c_str());
} }
......
...@@ -251,6 +251,9 @@ void Channel::CallMethod(const google::protobuf::MethodDescriptor* method, ...@@ -251,6 +251,9 @@ void Channel::CallMethod(const google::protobuf::MethodDescriptor* method,
// in correlation_id. negative max_retry causes undefined behavior. // in correlation_id. negative max_retry causes undefined behavior.
cntl->set_max_retry(0); cntl->set_max_retry(0);
} }
// HTTP needs this field to be set before any SetFailed()
cntl->_request_protocol = _options.protocol;
cntl->_preferred_index = _preferred_index;
cntl->_retry_policy = _options.retry_policy; cntl->_retry_policy = _options.retry_policy;
const CallId correlation_id = cntl->call_id(); const CallId correlation_id = cntl->call_id();
const int rc = bthread_id_lock_and_reset_range( const int rc = bthread_id_lock_and_reset_range(
...@@ -321,8 +324,6 @@ void Channel::CallMethod(const google::protobuf::MethodDescriptor* method, ...@@ -321,8 +324,6 @@ void Channel::CallMethod(const google::protobuf::MethodDescriptor* method,
cntl->_single_server_id = _server_id; cntl->_single_server_id = _server_id;
cntl->_remote_side = _server_address; cntl->_remote_side = _server_address;
} }
cntl->_request_protocol = _options.protocol;
cntl->_preferred_index = _preferred_index;
// Share the lb with controller. // Share the lb with controller.
cntl->_lb = _lb; cntl->_lb = _lb;
......
...@@ -355,6 +355,30 @@ void Controller::AppendServerIdentiy() { ...@@ -355,6 +355,30 @@ void Controller::AppendServerIdentiy() {
} }
} }
// Defined in http_rpc_protocol.cpp
namespace policy {
int ErrorCode2StatusCode(int error_code);
}
inline void UpdateResponseHeader(Controller* cntl) {
DCHECK(cntl->Failed());
if (cntl->request_protocol() == PROTOCOL_HTTP) {
if (cntl->ErrorCode() != EHTTP) {
// We assume that status code is already set along with EHTTP.
cntl->http_response().set_status_code(
policy::ErrorCode2StatusCode(cntl->ErrorCode()));
}
if (cntl->server() != NULL) {
// Override HTTP body at server-side to conduct error text
// to the client.
// The client-side should preserve body which may be a piece
// of useable data rather than error text.
cntl->response_attachment().clear();
cntl->response_attachment().append(cntl->ErrorText());
}
}
}
void Controller::SetFailed(const std::string& reason) { void Controller::SetFailed(const std::string& reason) {
_error_code = -1; _error_code = -1;
if (!_error_text.empty()) { if (!_error_text.empty()) {
...@@ -370,6 +394,7 @@ void Controller::SetFailed(const std::string& reason) { ...@@ -370,6 +394,7 @@ void Controller::SetFailed(const std::string& reason) {
_span->set_error_code(_error_code); _span->set_error_code(_error_code);
_span->Annotate(reason); _span->Annotate(reason);
} }
UpdateResponseHeader(this);
} }
void Controller::SetFailed(int error_code, const char* reason_fmt, ...) { void Controller::SetFailed(int error_code, const char* reason_fmt, ...) {
...@@ -398,6 +423,7 @@ void Controller::SetFailed(int error_code, const char* reason_fmt, ...) { ...@@ -398,6 +423,7 @@ void Controller::SetFailed(int error_code, const char* reason_fmt, ...) {
_span->set_error_code(_error_code); _span->set_error_code(_error_code);
_span->AnnotateCStr(_error_text.c_str() + old_size, 0); _span->AnnotateCStr(_error_text.c_str() + old_size, 0);
} }
UpdateResponseHeader(this);
} }
void Controller::CloseConnection(const char* reason_fmt, ...) { void Controller::CloseConnection(const char* reason_fmt, ...) {
...@@ -425,6 +451,7 @@ void Controller::CloseConnection(const char* reason_fmt, ...) { ...@@ -425,6 +451,7 @@ void Controller::CloseConnection(const char* reason_fmt, ...) {
_span->set_error_code(_error_code); _span->set_error_code(_error_code);
_span->AnnotateCStr(_error_text.c_str() + old_size, 0); _span->AnnotateCStr(_error_text.c_str() + old_size, 0);
} }
UpdateResponseHeader(this);
} }
bool Controller::IsCanceled() const { bool Controller::IsCanceled() const {
......
...@@ -333,7 +333,7 @@ public: ...@@ -333,7 +333,7 @@ public:
// Tell RPC to close the connection instead of sending back response. // Tell RPC to close the connection instead of sending back response.
// If this controller was not SetFailed() before, ErrorCode() will be // If this controller was not SetFailed() before, ErrorCode() will be
// set to ECLOSE. // set to ECLOSE.
// Notice that the actual closing does not take place immediately. // NOTE: the underlying connection is not closed immediately.
void CloseConnection(const char* reason_fmt, ...); void CloseConnection(const char* reason_fmt, ...);
// True if CloseConnection() was called. // True if CloseConnection() was called.
...@@ -384,6 +384,10 @@ public: ...@@ -384,6 +384,10 @@ public:
// Causes Failed() to return true on the client side. "reason" will be // Causes Failed() to return true on the client side. "reason" will be
// incorporated into the message returned by ErrorText(). // incorporated into the message returned by ErrorText().
// NOTE: Change http_response().status_code() according to `error_code'
// as well if the protocol is HTTP. If you want to overwrite the
// status_code, call http_response().set_status_code() after SetFailed()
// (rather than before SetFailed)
void SetFailed(const std::string& reason); void SetFailed(const std::string& reason);
void SetFailed(int error_code, const char* reason_fmt, ...) void SetFailed(int error_code, const char* reason_fmt, ...)
__attribute__ ((__format__ (__printf__, 3, 4))); __attribute__ ((__format__ (__printf__, 3, 4)));
......
...@@ -116,10 +116,11 @@ int HttpMessage::on_header_value(http_parser *parser, ...@@ -116,10 +116,11 @@ int HttpMessage::on_header_value(http_parser *parser,
<< http_message->_url << " HTTP/" << parser->http_major << http_message->_url << " HTTP/" << parser->http_major
<< '.' << parser->http_minor; << '.' << parser->http_minor;
} else { } else {
// NOTE: http_message->header().status_code() may not be set yet.
*vs << "[HTTP RESPONSE @" << butil::my_ip() << "]\n< HTTP/" *vs << "[HTTP RESPONSE @" << butil::my_ip() << "]\n< HTTP/"
<< parser->http_major << parser->http_major
<< '.' << parser->http_minor << ' ' << parser->status_code << '.' << parser->http_minor << ' ' << parser->status_code
<< ' ' << http_message->header().reason_phrase(); << ' ' << HttpReasonPhrase(parser->status_code);
} }
} }
if (first_entry) { if (first_entry) {
...@@ -215,7 +216,11 @@ int HttpMessage::OnBody(const char *at, const size_t length) { ...@@ -215,7 +216,11 @@ int HttpMessage::OnBody(const char *at, const size_t length) {
// only add prefix at first entry. // only add prefix at first entry.
*_vmsgbuilder << "\n<\n"; *_vmsgbuilder << "\n<\n";
} }
if (_read_body_progressively) { if (_read_body_progressively &&
// If the status_code is non-OK, the body is likely to be the error
// description which is very helpful for debugging. Otherwise
// the body is probably streaming data which is too long to print.
header().status_code() == HTTP_STATUS_OK) {
std::cerr << _vmsgbuilder->buf() << std::endl; std::cerr << _vmsgbuilder->buf() << std::endl;
delete _vmsgbuilder; delete _vmsgbuilder;
_vmsgbuilder = NULL; _vmsgbuilder = NULL;
......
This diff is collapsed.
...@@ -277,7 +277,7 @@ TEST_F(HttpTest, process_request_logoff) { ...@@ -277,7 +277,7 @@ TEST_F(HttpTest, process_request_logoff) {
_server._status = brpc::Server::READY; _server._status = brpc::Server::READY;
ProcessMessage(brpc::policy::ProcessHttpRequest, msg, false); ProcessMessage(brpc::policy::ProcessHttpRequest, msg, false);
ASSERT_EQ(1ll, _server._nerror.get_value()); ASSERT_EQ(1ll, _server._nerror.get_value());
CheckResponseCode(false, brpc::HTTP_STATUS_FORBIDDEN); CheckResponseCode(false, brpc::HTTP_STATUS_SERVICE_UNAVAILABLE);
} }
TEST_F(HttpTest, process_request_wrong_method) { TEST_F(HttpTest, process_request_wrong_method) {
...@@ -570,8 +570,12 @@ TEST_F(HttpTest, read_failed_chunked_response) { ...@@ -570,8 +570,12 @@ TEST_F(HttpTest, read_failed_chunked_response) {
cntl.http_request().uri() = "/DownloadService/DownloadFailed"; cntl.http_request().uri() = "/DownloadService/DownloadFailed";
cntl.response_will_be_read_progressively(); cntl.response_will_be_read_progressively();
channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); channel.CallMethod(NULL, &cntl, NULL, NULL, NULL);
ASSERT_TRUE(cntl.response_attachment().empty()); EXPECT_TRUE(cntl.response_attachment().empty());
ASSERT_TRUE(cntl.Failed()) << cntl.ErrorText(); ASSERT_TRUE(cntl.Failed());
ASSERT_NE(cntl.ErrorText().find("HTTP/1.1 500 Internal Server Error"),
std::string::npos) << cntl.ErrorText();
ASSERT_NE(cntl.ErrorText().find("Intentionally set controller failed"),
std::string::npos) << cntl.ErrorText();
ASSERT_EQ(0, svc.last_errno()); ASSERT_EQ(0, svc.last_errno());
} }
......
...@@ -486,6 +486,7 @@ TEST_F(ServerTest, missing_required_fields) { ...@@ -486,6 +486,7 @@ TEST_F(ServerTest, missing_required_fields) {
http_channel.CallMethod(NULL, &cntl, NULL, NULL, NULL); http_channel.CallMethod(NULL, &cntl, NULL, NULL, NULL);
ASSERT_TRUE(cntl.Failed()); ASSERT_TRUE(cntl.Failed());
ASSERT_EQ(brpc::EHTTP, cntl.ErrorCode()); ASSERT_EQ(brpc::EHTTP, cntl.ErrorCode());
LOG(INFO) << cntl.ErrorText();
ASSERT_EQ(brpc::HTTP_STATUS_BAD_REQUEST, cntl.http_response().status_code()); ASSERT_EQ(brpc::HTTP_STATUS_BAD_REQUEST, cntl.http_response().status_code());
ASSERT_EQ(0, service_v1.ncalled.load()); ASSERT_EQ(0, service_v1.ncalled.load());
......
#!/bin/bash #!/bin/bash
if [ -z "$1" ]; then if [ -z "$1" ]; then
echo "Usage1: patch_from_svn PATCHFILE (generated by 'svn diff -c REVISION')" echo "Usage1: patch_from_baidu PATCHFILE (generated by 'git diff --no-prefix')"
echo "Usage2: patch_from_svn SVN_DIR REVISION" echo "Usage2: patch_from_baidu GIT_DIR COMMIT"
exit 1 exit 1
fi fi
PATCHFILE=$1 PATCHFILE=$1
if [ -d "$1/.svn" ]; then if [ -d "$1/.git" ]; then
if [ -z "$2" ]; then if [ -z "$2" ]; then
echo "Second argument must be a SVN revision" echo "Second argument must be a git commit"
exit 1 exit 1
fi fi
CURRENT_DIR=`pwd` CURRENT_DIR=`pwd`
SVN_DIR=$1 GIT_DIR=$1
REV=$2 COMMIT=$2
PATCHFILE=$CURRENT_DIR/$REV.patch PATCHFILE=$CURRENT_DIR/$COMMIT.patch
echo "*** Generating diff of $SVN_DIR@$REV" echo "*** Generating diff of $GIT_DIR@$COMMIT"
cd $SVN_DIR && svn diff . -c $REV > $PATCHFILE cd $GIT_DIR && git diff --no-prefix $COMMIT^! > $PATCHFILE
cd $CURRENT_DIR cd $CURRENT_DIR
fi fi
MODIFIED_PATCHFILE=$(basename $(basename $PATCHFILE .patch) .diff).from_svn.patch MODIFIED_PATCHFILE=$(basename $(basename $PATCHFILE .patch) .diff).from_baidu.patch
# guess prefix of test files # guess prefix of test files
TEST_PREFIX="test_" TEST_PREFIX="test_"
TEST_SUFFIX= TEST_SUFFIX=
if fgrep -q " bthread/" $PATCHFILE; then if fgrep -q " src/baidu/rpc/" $PATCHFILE; then
TEST_PREFIX="brpc_"
TEST_SUFFIX="_unittest"
elif fgrep -q " bthread/" $PATCHFILE; then
TEST_PREFIX="bthread_" TEST_PREFIX="bthread_"
TEST_SUFFIX="_unittest" TEST_SUFFIX="_unittest"
elif fgrep -q " bvar/" $PATCHFILE; then elif fgrep -q " bvar/" $PATCHFILE; then
...@@ -35,7 +38,6 @@ fi ...@@ -35,7 +38,6 @@ fi
cat $PATCHFILE | sed -e 's/src\/baidu\/rpc\//src\/brpc\//g' \ cat $PATCHFILE | sed -e 's/src\/baidu\/rpc\//src\/brpc\//g' \
-e 's/\<baidu\/rpc\//brpc\//g' \ -e 's/\<baidu\/rpc\//brpc\//g' \
-e 's/\<baidu\-rpc\([^-]\)/brpc\1/g' \ -e 's/\<baidu\-rpc\([^-]\)/brpc\1/g' \
-e 's/\<src\/brpc\/test\/test_\(\S*\)\.cpp/test\/brpc_\1_unittest.cpp/g' \
-e 's/\<test\/test_bthread\.cpp/test\/bthread_unittest.cpp/g' \ -e 's/\<test\/test_bthread\.cpp/test\/bthread_unittest.cpp/g' \
-e 's/\<test\/test_object_pool\.cpp/test\/object_pool_unittest.cpp/g' \ -e 's/\<test\/test_object_pool\.cpp/test\/object_pool_unittest.cpp/g' \
-e 's/\<test\/test_resource_pool\.cpp/test\/resource_pool_unittest.cpp/g' \ -e 's/\<test\/test_resource_pool\.cpp/test\/resource_pool_unittest.cpp/g' \
...@@ -70,7 +72,7 @@ cat $PATCHFILE | sed -e 's/src\/baidu\/rpc\//src\/brpc\//g' \ ...@@ -70,7 +72,7 @@ cat $PATCHFILE | sed -e 's/src\/baidu\/rpc\//src\/brpc\//g' \
EXTRA_ARGS= EXTRA_ARGS=
if [ -z "$DO_RUN" ]; then if [ -z "$DO_RUN" ]; then
EXTRA_ARGS="--dry-run $EXTRA_ARGS" EXTRA_ARGS="--dry-run $EXTRA_ARGS"
echo "*** This is a dry-run. To really apply, run: DO_RUN=1 tools/patch_from_svn $1" echo "*** This is a dry-run. To really apply, run: DO_RUN=1 tools/patch_from_baidu $1"
fi fi
patch -p0 -u -l $EXTRA_ARGS < $MODIFIED_PATCHFILE patch -p0 -u -l $EXTRA_ARGS < $MODIFIED_PATCHFILE
if [ ! -z "$DO_RUN" ]; then if [ ! -z "$DO_RUN" ]; then
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment