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;
......
...@@ -264,11 +264,20 @@ void ProcessHttpResponse(InputMessageBase* msg) { ...@@ -264,11 +264,20 @@ void ProcessHttpResponse(InputMessageBase* msg) {
accessor.set_readable_progressive_attachment(imsg_guard.get()); accessor.set_readable_progressive_attachment(imsg_guard.get());
const int sc = res_header->status_code(); const int sc = res_header->status_code();
if (sc < 200 || sc >= 300) { if (sc < 200 || sc >= 300) {
cntl->SetFailed(EHTTP, "HTTP/%d.%d %d %s", // Even if the body is for streaming purpose, a non-OK status
// code indicates that the body is probably the error text
// which is helpful for debugging.
// content may be binary data, so the size limit is a must.
std::string body_str;
res_body.copy_to(
&body_str, std::min((int)res_body.size(),
FLAGS_http_max_error_length));
cntl->SetFailed(EHTTP, "HTTP/%d.%d %d %s: %.*s",
res_header->major_version(), res_header->major_version(),
res_header->minor_version(), res_header->minor_version(),
static_cast<int>(res_header->status_code()), static_cast<int>(res_header->status_code()),
res_header->reason_phrase()); res_header->reason_phrase(),
(int)body_str.size(), body_str.c_str());
} else if (cntl->response() != NULL && } else if (cntl->response() != NULL &&
cntl->response()->GetDescriptor()->field_count() != 0) { cntl->response()->GetDescriptor()->field_count() != 0) {
cntl->SetFailed(ERESPONSE, "A protobuf response can't be parsed" cntl->SetFailed(ERESPONSE, "A protobuf response can't be parsed"
...@@ -284,7 +293,6 @@ void ProcessHttpResponse(InputMessageBase* msg) { ...@@ -284,7 +293,6 @@ void ProcessHttpResponse(InputMessageBase* msg) {
if (!res_body.empty()) { if (!res_body.empty()) {
// Use content as error text if it's present. Notice that // Use content as error text if it's present. Notice that
// content may be binary data, so the size limit is a must. // content may be binary data, so the size limit is a must.
// TODO: Print body in better way.
std::string body_str; std::string body_str;
res_body.copy_to( res_body.copy_to(
&body_str, std::min((int)res_body.size(), &body_str, std::min((int)res_body.size(),
...@@ -363,29 +371,19 @@ void ProcessHttpResponse(InputMessageBase* msg) { ...@@ -363,29 +371,19 @@ void ProcessHttpResponse(InputMessageBase* msg) {
accessor.OnResponse(cid, saved_error); accessor.OnResponse(cid, saved_error);
} }
void UpdateResponseHeader(int status_code, Controller* cntl) {
DCHECK(cntl->Failed());
HttpHeader* resp_header = &cntl->http_response();
resp_header->set_status_code(status_code);
cntl->response_attachment().clear();
cntl->response_attachment().append(cntl->ErrorText());
}
void SerializeHttpRequest(butil::IOBuf* /*not used*/, void SerializeHttpRequest(butil::IOBuf* /*not used*/,
Controller* cntl, Controller* cntl,
const google::protobuf::Message* request) { const google::protobuf::Message* request) {
if (request != NULL) { if (request != NULL) {
// If request is not NULL, message body will be serialized json, // If request is not NULL, message body will be serialized json,
if (!request->IsInitialized()) { if (!request->IsInitialized()) {
cntl->SetFailed( return cntl->SetFailed(
EREQUEST, "Missing required fields in request: %s", EREQUEST, "Missing required fields in request: %s",
request->InitializationErrorString().c_str()); request->InitializationErrorString().c_str());
return UpdateResponseHeader(HTTP_STATUS_BAD_REQUEST, cntl);
} }
if (!cntl->request_attachment().empty()) { if (!cntl->request_attachment().empty()) {
cntl->SetFailed(EREQUEST, "request_attachment must be empty " return cntl->SetFailed(EREQUEST, "request_attachment must be empty "
"when request is not NULL"); "when request is not NULL");
return UpdateResponseHeader(HTTP_STATUS_BAD_REQUEST, cntl);
} }
butil::IOBufAsZeroCopyOutputStream wrapper(&cntl->request_attachment()); butil::IOBufAsZeroCopyOutputStream wrapper(&cntl->request_attachment());
const HttpContentType content_type const HttpContentType content_type
...@@ -394,10 +392,8 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/, ...@@ -394,10 +392,8 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
// Serialize content as protobuf // Serialize content as protobuf
if (!request->SerializeToZeroCopyStream(&wrapper)) { if (!request->SerializeToZeroCopyStream(&wrapper)) {
cntl->request_attachment().clear(); cntl->request_attachment().clear();
cntl->SetFailed(EREQUEST, "Fail to serialize %s", return cntl->SetFailed(EREQUEST, "Fail to serialize %s",
request->GetTypeName().c_str()); request->GetTypeName().c_str());
UpdateResponseHeader(HTTP_STATUS_BAD_REQUEST, cntl);
return;
} }
} else { } else {
// Serialize content as json // Serialize content as json
...@@ -409,10 +405,7 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/, ...@@ -409,10 +405,7 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
: json2pb::OUTPUT_ENUM_BY_NAME); : json2pb::OUTPUT_ENUM_BY_NAME);
if (!json2pb::ProtoMessageToJson(*request, &wrapper, opt, &err)) { if (!json2pb::ProtoMessageToJson(*request, &wrapper, opt, &err)) {
cntl->request_attachment().clear(); cntl->request_attachment().clear();
cntl->SetFailed(EREQUEST, "Fail to convert request to json, %s", return cntl->SetFailed(EREQUEST, "Fail to convert request to json, %s", err.c_str());
err.c_str());
UpdateResponseHeader(HTTP_STATUS_BAD_REQUEST, cntl);
return;
} }
// Set content-type if user did not. // Set content-type if user did not.
if (cntl->http_request().content_type().empty()) { if (cntl->http_request().content_type().empty()) {
...@@ -425,15 +418,13 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/, ...@@ -425,15 +418,13 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
} }
// Make RPC fail if uri() is not OK (previous SetHttpURL/operator= failed) // Make RPC fail if uri() is not OK (previous SetHttpURL/operator= failed)
if (!cntl->http_request().uri().status().ok()) { if (!cntl->http_request().uri().status().ok()) {
cntl->SetFailed(EREQUEST, "%s", return cntl->SetFailed(EREQUEST, "%s",
cntl->http_request().uri().status().error_cstr()); cntl->http_request().uri().status().error_cstr());
return UpdateResponseHeader(HTTP_STATUS_BAD_REQUEST, cntl);
} }
if (cntl->request_compress_type() != COMPRESS_TYPE_NONE) { if (cntl->request_compress_type() != COMPRESS_TYPE_NONE) {
if (cntl->request_compress_type() != COMPRESS_TYPE_GZIP) { if (cntl->request_compress_type() != COMPRESS_TYPE_GZIP) {
cntl->SetFailed(EREQUEST, "http does not support %s", return cntl->SetFailed(EREQUEST, "http does not support %s",
CompressTypeToCStr(cntl->request_compress_type())); CompressTypeToCStr(cntl->request_compress_type()));
return UpdateResponseHeader(HTTP_STATUS_BAD_REQUEST, cntl);
} }
const size_t request_size = cntl->request_attachment().size(); const size_t request_size = cntl->request_attachment().size();
if (request_size >= (size_t)FLAGS_http_body_compress_threshold) { if (request_size >= (size_t)FLAGS_http_body_compress_threshold) {
...@@ -499,17 +490,14 @@ void PackHttpRequest(butil::IOBuf* buf, ...@@ -499,17 +490,14 @@ void PackHttpRequest(butil::IOBuf* buf,
const butil::IOBuf& /*unused*/, const butil::IOBuf& /*unused*/,
const Authenticator* auth) { const Authenticator* auth) {
if (cntl->connection_type() == CONNECTION_TYPE_SINGLE) { if (cntl->connection_type() == CONNECTION_TYPE_SINGLE) {
cntl->SetFailed(EREQUEST, "http can't work with CONNECTION_TYPE_SINGLE"); return cntl->SetFailed(EREQUEST, "http can't work with CONNECTION_TYPE_SINGLE");
return UpdateResponseHeader(HTTP_STATUS_BAD_REQUEST, cntl);
} }
ControllerPrivateAccessor accessor(cntl); ControllerPrivateAccessor accessor(cntl);
HttpHeader* header = &cntl->http_request(); HttpHeader* header = &cntl->http_request();
if (auth != NULL && header->GetHeader(common->AUTHORIZATION) == NULL) { if (auth != NULL && header->GetHeader(common->AUTHORIZATION) == NULL) {
std::string auth_data; std::string auth_data;
if (auth->GenerateCredential(&auth_data) != 0) { if (auth->GenerateCredential(&auth_data) != 0) {
cntl->SetFailed(EREQUEST, "Fail to GenerateCredential"); return cntl->SetFailed(EREQUEST, "Fail to GenerateCredential");
UpdateResponseHeader(HTTP_STATUS_BAD_REQUEST, cntl);
return;
} }
header->SetHeader(common->AUTHORIZATION, auth_data); header->SetHeader(common->AUTHORIZATION, auth_data);
} }
...@@ -534,7 +522,8 @@ inline bool SupportGzip(Controller* cntl) { ...@@ -534,7 +522,8 @@ inline bool SupportGzip(Controller* cntl) {
return encodings->find(common->GZIP) != std::string::npos; return encodings->find(common->GZIP) != std::string::npos;
} }
inline int ErrorCode2StatusCode(int error_code) { // Called in controller.cpp as well
int ErrorCode2StatusCode(int error_code) {
switch (error_code) { switch (error_code) {
case ENOSERVICE: case ENOSERVICE:
case ENOMETHOD: case ENOMETHOD:
...@@ -609,8 +598,7 @@ static void SendHttpResponse(Controller *cntl, ...@@ -609,8 +598,7 @@ static void SendHttpResponse(Controller *cntl,
res_header->set_content_type(common->CONTENT_TYPE_PROTO); res_header->set_content_type(common->CONTENT_TYPE_PROTO);
} }
} else { } else {
cntl->SetFailed(ERESPONSE, "Fail to serialize %s", cntl->SetFailed(ERESPONSE, "Fail to serialize %s", res->GetTypeName().c_str());
res->GetTypeName().c_str());
} }
} else { } else {
std::string err; std::string err;
...@@ -625,8 +613,7 @@ static void SendHttpResponse(Controller *cntl, ...@@ -625,8 +613,7 @@ static void SendHttpResponse(Controller *cntl,
res_header->set_content_type(common->CONTENT_TYPE_JSON); res_header->set_content_type(common->CONTENT_TYPE_JSON);
} }
} else { } else {
cntl->SetFailed(ERESPONSE, "Fail to convert response to json, %s", cntl->SetFailed(ERESPONSE, "Fail to convert response to json, %s", err.c_str());
err.c_str());
} }
} }
} }
...@@ -733,8 +720,7 @@ static void SendHttpResponse(Controller *cntl, ...@@ -733,8 +720,7 @@ static void SendHttpResponse(Controller *cntl,
// EPIPE is common in pooled connections + backup requests. // EPIPE is common in pooled connections + backup requests.
const int errcode = errno; const int errcode = errno;
PLOG_IF(WARNING, errcode != EPIPE) << "Fail to write into " << *socket; PLOG_IF(WARNING, errcode != EPIPE) << "Fail to write into " << *socket;
cntl->SetFailed(errcode, "Fail to write into %s", cntl->SetFailed(errcode, "Fail to write into %s", socket->description().c_str());
socket->description().c_str());
return; return;
} }
if (span) { if (span) {
...@@ -1131,8 +1117,6 @@ void ProcessHttpRequest(InputMessageBase *msg) { ...@@ -1131,8 +1117,6 @@ void ProcessHttpRequest(InputMessageBase *msg) {
if (!server->IsRunning()) { if (!server->IsRunning()) {
cntl->SetFailed(ELOGOFF, "Server is stopping"); cntl->SetFailed(ELOGOFF, "Server is stopping");
cntl->http_response().set_status_code(HTTP_STATUS_FORBIDDEN);
cntl->http_response().SetHeader(common->CONNECTION, common->CLOSE);
return SendHttpResponse(cntl.release(), server, NULL); return SendHttpResponse(cntl.release(), server, NULL);
} }
...@@ -1172,7 +1156,6 @@ void ProcessHttpRequest(InputMessageBase *msg) { ...@@ -1172,7 +1156,6 @@ void ProcessHttpRequest(InputMessageBase *msg) {
} else { } else {
cntl->SetFailed(ENOMETHOD, "Fail to find method on `%s'", path.c_str()); cntl->SetFailed(ENOMETHOD, "Fail to find method on `%s'", path.c_str());
} }
cntl->http_response().set_status_code(HTTP_STATUS_NOT_FOUND);
return SendHttpResponse(cntl.release(), server, NULL); return SendHttpResponse(cntl.release(), server, NULL);
} else if (sp->service->GetDescriptor() == BadMethodService::descriptor()) { } else if (sp->service->GetDescriptor() == BadMethodService::descriptor()) {
BadMethodRequest breq; BadMethodRequest breq;
...@@ -1214,7 +1197,6 @@ void ProcessHttpRequest(InputMessageBase *msg) { ...@@ -1214,7 +1197,6 @@ void ProcessHttpRequest(InputMessageBase *msg) {
cntl->SetFailed(EPERM, "Not allowed to access builtin services, try " cntl->SetFailed(EPERM, "Not allowed to access builtin services, try "
"ServerOptions.internal_port=%d instead if you're in" "ServerOptions.internal_port=%d instead if you're in"
" internal network", server->options().internal_port); " internal network", server->options().internal_port);
cntl->http_response().set_status_code(HTTP_STATUS_FORBIDDEN);
return SendHttpResponse(cntl.release(), server, method_status); return SendHttpResponse(cntl.release(), server, method_status);
} }
...@@ -1242,7 +1224,6 @@ void ProcessHttpRequest(InputMessageBase *msg) { ...@@ -1242,7 +1224,6 @@ void ProcessHttpRequest(InputMessageBase *msg) {
cntl->SetFailed(EREQUEST, "%s needs to be created from a" cntl->SetFailed(EREQUEST, "%s needs to be created from a"
" non-empty json, it has required fields.", " non-empty json, it has required fields.",
req->GetDescriptor()->full_name().c_str()); req->GetDescriptor()->full_name().c_str());
cntl->http_response().set_status_code(HTTP_STATUS_BAD_REQUEST);
return SendHttpResponse(cntl.release(), server, method_status); return SendHttpResponse(cntl.release(), server, method_status);
} // else all fields of the request are optional. } // else all fields of the request are optional.
} else { } else {
......
...@@ -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