From: Roger Meier Date: Sun, 11 Sep 2011 07:28:54 +0000 (+0000) Subject: THRIFT-1243 TAsyncChannel callbacks X-Git-Tag: 0.8.0~91 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=08077bf9d8c6c212f5ff384c94423b6f76892358;p=common%2Fthrift.git THRIFT-1243 TAsyncChannel callbacks improved exception handling Patch: Alexandre Parenteau git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1167679 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/lib/cpp/src/async/TEvhttpClientChannel.cpp b/lib/cpp/src/async/TEvhttpClientChannel.cpp index e5fc1b06..c0363fc7 100755 --- a/lib/cpp/src/async/TEvhttpClientChannel.cpp +++ b/lib/cpp/src/async/TEvhttpClientChannel.cpp @@ -20,6 +20,13 @@ #include "TEvhttpClientChannel.h" #include #include "transport/TBufferTransports.h" +#include + +#include +#include + +using namespace apache::thrift::protocol; +using apache::thrift::transport::TTransportException; namespace apache { namespace thrift { namespace async { @@ -37,7 +44,7 @@ TEvhttpClientChannel::TEvhttpClientChannel( { conn_ = evhttp_connection_new(address, port); if (conn_ == NULL) { - abort(); // XXX + throw TException("evhttp_connection_new failed"); } evhttp_connection_set_base(conn_, eb); } @@ -59,19 +66,19 @@ void TEvhttpClientChannel::sendAndRecvMessage( struct evhttp_request* req = evhttp_request_new(response, this); if (req == NULL) { - abort(); // XXX + throw TException("evhttp_request_new failed"); } int rv; rv = evhttp_add_header(req->output_headers, "Host", host_.c_str()); if (rv != 0) { - abort(); // XXX + throw TException("evhttp_add_header failed"); } rv = evhttp_add_header(req->output_headers, "Content-Type", "application/x-thrift"); if (rv != 0) { - abort(); // XXX + throw TException("evhttp_add_header failed"); } uint8_t* obuf; @@ -79,12 +86,12 @@ void TEvhttpClientChannel::sendAndRecvMessage( sendBuf->getBuffer(&obuf, &sz); rv = evbuffer_add(req->output_buffer, obuf, sz); if (rv != 0) { - abort(); // XXX + throw TException("evbuffer_add failed"); } rv = evhttp_make_request(conn_, req, EVHTTP_REQ_POST, path_.c_str()); if (rv != 0) { - abort(); // XXX + throw TException("evhttp_make_request failed"); } } @@ -93,7 +100,8 @@ void TEvhttpClientChannel::sendMessage( const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message) { (void) cob; (void) message; - abort(); // XXX + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "Unexpected call to TEvhttpClientChannel::sendMessage"); } @@ -101,17 +109,36 @@ void TEvhttpClientChannel::recvMessage( const VoidCallback& cob, apache::thrift::transport::TMemoryBuffer* message) { (void) cob; (void) message; - abort(); // XXX + throw TProtocolException(TProtocolException::NOT_IMPLEMENTED, + "Unexpected call to TEvhttpClientChannel::recvMessage"); } void TEvhttpClientChannel::finish(struct evhttp_request* req) { if (req == NULL) { + try { cob_(); - return; + } catch(const TTransportException& e) { + if(e.getType() == TTransportException::END_OF_FILE) + throw TException("connect failed"); + else + throw; + } + return; } else if (req->response_code != 200) { + try { cob_(); - return; + } catch(const TTransportException& e) { + std::stringstream ss; + ss << "server returned code " << req->response_code; + if(req->response_code_line) + ss << ": " << req->response_code_line; + if(e.getType() == TTransportException::END_OF_FILE) + throw TException(ss.str()); + else + throw; + } + return; } recvBuf_->resetBuffer( EVBUFFER_DATA(req->input_buffer), @@ -123,7 +150,12 @@ void TEvhttpClientChannel::finish(struct evhttp_request* req) { /* static */ void TEvhttpClientChannel::response(struct evhttp_request* req, void* arg) { TEvhttpClientChannel* self = (TEvhttpClientChannel*)arg; - self->finish(req); + try { + self->finish(req); + } catch(std::exception& e) { + // don't propagate a C++ exception in C code (e.g. libevent) + std::cerr << "TEvhttpClientChannel::response exception thrown (ignored): " << e.what() << std::endl; + } } diff --git a/lib/cpp/src/async/TEvhttpServer.cpp b/lib/cpp/src/async/TEvhttpServer.cpp index 701f8bd0..b92422c6 100755 --- a/lib/cpp/src/async/TEvhttpServer.cpp +++ b/lib/cpp/src/async/TEvhttpServer.cpp @@ -22,6 +22,8 @@ #include "transport/TBufferTransports.h" #include +#include + #ifndef HTTP_INTERNAL // libevent < 2 #define HTTP_INTERNAL 500 #endif @@ -55,12 +57,12 @@ TEvhttpServer::TEvhttpServer(boost::shared_ptr processor, // Create event_base and evhttp. eb_ = event_base_new(); if (eb_ == NULL) { - abort(); // XXX + throw TException("event_base_new failed"); } eh_ = evhttp_new(eb_); if (eh_ == NULL) { event_base_free(eb_); - abort(); // XXX + throw TException("evhttp_new failed"); } // Bind to port. @@ -68,6 +70,7 @@ TEvhttpServer::TEvhttpServer(boost::shared_ptr processor, if (ret < 0) { evhttp_free(eh_); event_base_free(eb_); + throw TException("evhttp_bind_socket failed"); } // Register a handler. If you use the other constructor, @@ -89,7 +92,7 @@ TEvhttpServer::~TEvhttpServer() { int TEvhttpServer::serve() { if (eb_ == NULL) { - abort(); // XXX + throw TException("Unexpected call to TEvhttpServer::serve"); } return event_base_dispatch(eb_); } @@ -127,17 +130,19 @@ void TEvhttpServer::complete(RequestContext* ctx, bool success) { (void) success; std::auto_ptr ptr(ctx); - int code = 200; - const char* reason = "OK"; + int code = success ? 200 : 400; + const char* reason = success ? "OK" : "Bad Request"; int rv = evhttp_add_header(ctx->req->output_headers, "Content-Type", "application/x-thrift"); if (rv != 0) { // TODO: Log an error. + std::cerr << "evhttp_add_header failed " << __FILE__ << ":" << __LINE__ << std::endl; } struct evbuffer* buf = evbuffer_new(); if (buf == NULL) { // TODO: Log an error. + std::cerr << "evbuffer_new failed " << __FILE__ << ":" << __LINE__ << std::endl; } else { uint8_t* obuf; uint32_t sz; @@ -145,6 +150,7 @@ void TEvhttpServer::complete(RequestContext* ctx, bool success) { int ret = evbuffer_add(buf, obuf, sz); if (ret != 0) { // TODO: Log an error. + std::cerr << "evhttp_add failed with " << ret << " " << __FILE__ << ":" << __LINE__ << std::endl; } }