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 e5fc1b0..c0363fc 100755
--- a/lib/cpp/src/async/TEvhttpClientChannel.cpp
+++ b/lib/cpp/src/async/TEvhttpClientChannel.cpp
@@ -20,6 +20,13 @@
#include "TEvhttpClientChannel.h"
#include <evhttp.h>
#include "transport/TBufferTransports.h"
+#include <protocol/TProtocolException.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace apache::thrift::protocol;
+using apache::thrift::transport::TTransportException;
namespace apache { namespace thrift { namespace async {
@@ -37,7 +44,7 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 701f8bd..b92422c 100755
--- a/lib/cpp/src/async/TEvhttpServer.cpp
+++ b/lib/cpp/src/async/TEvhttpServer.cpp
@@ -22,6 +22,8 @@
#include "transport/TBufferTransports.h"
#include <evhttp.h>
+#include <iostream>
+
#ifndef HTTP_INTERNAL // libevent < 2
#define HTTP_INTERNAL 500
#endif
@@ -55,12 +57,12 @@
// 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 @@
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 @@
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) success;
std::auto_ptr<RequestContext> 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 @@
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;
}
}