THRIFT-1222 Unhandled exception for TEvhttpServer request

Patch: Alexandre Parenteau

git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1147542 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Roger Meier 2011-07-17 07:28:28 +00:00
parent a35944bfe2
commit 7e056e7572
7 changed files with 226 additions and 13 deletions

14
compiler/cpp/src/generate/t_cpp_generator.cc Normal file → Executable file
View File

@ -231,28 +231,28 @@ class t_cpp_generator : public t_oop_generator {
std::string get_include_prefix(const t_program& program) const;
/**
* True iff we should generate pure enums for Thrift enums, instead of wrapper classes.
* True if we should generate pure enums for Thrift enums, instead of wrapper classes.
*/
bool gen_pure_enums_;
/**
* True iff we should generate local reflection metadata for TDenseProtocol.
* True if we should generate local reflection metadata for TDenseProtocol.
*/
bool gen_dense_;
/**
* True iff we should generate templatized reader/writer methods.
* True if we should generate templatized reader/writer methods.
*/
bool gen_templates_;
/**
* True iff we should use a path prefix in our #include statements for other
* True if we should use a path prefix in our #include statements for other
* thrift-generated header files.
*/
bool use_include_prefix_;
/**
* True iff we should generate "Continuation OBject"-style classes as well.
* True if we should generate "Continuation OBject"-style classes as well.
*/
bool gen_cob_style_;
@ -4142,6 +4142,10 @@ string t_cpp_generator::get_include_prefix(const t_program& program) const {
THRIFT_REGISTER_GENERATOR(cpp, "C++",
" cob_style: Generate \"Continuation OBject\"-style classes.\n"
" no_client_completion:\n"
" Omit calls to completion__() in CobClient class.\n"
" templates: Generate templatized reader/writer methods.\n"
" pure_enums: Generate pure enums instead of wrapper classes.\n"
" dense: Generate type specifications for the dense protocol.\n"
" include_prefix: Use full include paths in generated files.\n"

View File

@ -70,11 +70,13 @@ libthrift_la_SOURCES = src/Thrift.cpp \
src/server/TSimpleServer.cpp \
src/server/TThreadPoolServer.cpp \
src/server/TThreadedServer.cpp \
src/async/TAsyncChannel.cpp \
src/async/TAsyncChannel.cpp \
src/processor/PeekProcessor.cpp
libthriftnb_la_SOURCES = src/server/TNonblockingServer.cpp \
src/async/TAsyncProtocolProcessor.cpp
src/async/TAsyncProtocolProcessor.cpp \
src/async/TEvhttpServer.cpp \
src/async/TEvhttpClientChannel.cpp
libthriftz_la_SOURCES = src/transport/TZlibTransport.cpp

View File

@ -19,6 +19,7 @@
#include "TEvhttpClientChannel.h"
#include <evhttp.h>
#include "transport/TBufferTransports.h"
namespace apache { namespace thrift { namespace async {

View File

@ -22,6 +22,10 @@
#include "transport/TBufferTransports.h"
#include <evhttp.h>
#ifndef HTTP_INTERNAL // libevent < 2
#define HTTP_INTERNAL 500
#endif
using apache::thrift::transport::TMemoryBuffer;
namespace apache { namespace thrift { namespace async {
@ -98,7 +102,11 @@ TEvhttpServer::RequestContext::RequestContext(struct evhttp_request* req) : req(
void TEvhttpServer::request(struct evhttp_request* req, void* self) {
static_cast<TEvhttpServer*>(self)->process(req);
try {
static_cast<TEvhttpServer*>(self)->process(req);
} catch(std::exception& e) {
evhttp_send_reply(req, HTTP_INTERNAL, e.what(), 0);
}
}

View File

@ -87,7 +87,7 @@ StressTestNonBlocking_LDADD = \
THRIFT = $(top_builddir)/compiler/cpp/thrift
gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp: $(top_srcdir)/test/ThriftTest.thrift
$(THRIFT) --gen cpp:templates $<
$(THRIFT) --gen cpp:templates,cob_style -r $<
gen-cpp/ThriftTest.cpp gen-cpp/StressTest_types.cpp gen-cpp/StressTest_constants.cpp: $(top_srcdir)/test/StressTest.thrift
$(THRIFT) --gen cpp $<
@ -97,6 +97,7 @@ INCLUDES = \
AM_CPPFLAGS = $(BOOST_CPPFLAGS)
AM_CXXFLAGS = -Wall
AM_LDFLAGS = $(BOOST_LDFLAGS)
clean-local:
$(RM) -r gen-cpp

View File

@ -29,9 +29,12 @@
#include <transport/TTransportUtils.h>
#include <transport/TSocket.h>
#include <transport/TSSLSocket.h>
#include <async/TEvhttpClientChannel.h>
#include <server/TNonblockingServer.h> // <event.h>
#include <boost/shared_ptr.hpp>
#include <boost/program_options.hpp>
#include <tr1/functional>
#include "ThriftTest.h"
@ -41,6 +44,9 @@ using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace thrift::test;
using namespace apache::thrift::async;
using std::tr1::placeholders::_1;
//extern uint32_t g_socket_syscalls;
@ -56,6 +62,33 @@ uint64_t now()
return ret;
}
static void testString_clientReturn(const char* host, int port, event_base *base, TProtocolFactory* protocolFactory, ThriftTestCobClient* client) {
try {
string s;
client->recv_testString(s);
cout << "testString: " << s << endl;
} catch (TException& exn) {
cout << "Error: " << exn.what() << endl;
}
event_base_loopbreak(base); // end test
}
static void testVoid_clientReturn(const char* host, int port, event_base *base, TProtocolFactory* protocolFactory, ThriftTestCobClient* client) {
try {
client->recv_testVoid();
cout << "testVoid" << endl;
// next test
delete client;
shared_ptr<TAsyncChannel> channel(new TEvhttpClientChannel(host, "/", host, port, base));
client = new ThriftTestCobClient(channel, protocolFactory);
client->testString(tr1::bind(testString_clientReturn, host, port, base, protocolFactory, _1), "Test");
} catch (TException& exn) {
cout << "Error: " << exn.what() << endl;
}
}
int main(int argc, char** argv) {
string host = "localhost";
int port = 9090;
@ -71,7 +104,7 @@ int main(int argc, char** argv) {
("host", program_options::value<string>(&host)->default_value(host), "Host to connect")
("port", program_options::value<int>(&port)->default_value(port), "Port number to connect")
("domain-socket", program_options::value<string>(&domain_socket)->default_value(domain_socket), "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")
("transport", program_options::value<string>(&transport_type)->default_value(transport_type), "Transport: buffered, framed, http")
("transport", program_options::value<string>(&transport_type)->default_value(transport_type), "Transport: buffered, framed, http, evhttp")
("protocol", program_options::value<string>(&protocol_type)->default_value(protocol_type), "Protocol: binary, json")
("ssl", "Encrypted Transport using SSL")
("testloops,n", program_options::value<int>(&numTests)->default_value(numTests), "Number of Tests")
@ -99,6 +132,7 @@ int main(int argc, char** argv) {
if (transport_type == "buffered") {
} else if (transport_type == "framed") {
} else if (transport_type == "http") {
} else if (transport_type == "evhttp") {
} else {
throw invalid_argument("Unknown transport type "+transport_type);
}
@ -162,6 +196,25 @@ int main(int argc, char** argv) {
}
cout << endl;
if (transport_type.compare("evhttp") == 0) {
event_base *base = event_base_new();
cout << "Libevent Version: " << event_get_version() << endl;
cout << "Libevent Method: " << event_base_get_method(base) << endl;
#if LIBEVENT_VERSION_NUMBER >= 0x02000000
cout << "Libevent Features: 0x" << hex << event_base_get_features(base) << endl;
#endif
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
shared_ptr<TAsyncChannel> channel(new TEvhttpClientChannel(host.c_str(), "/", host.c_str(), port, base));
ThriftTestCobClient* client = new ThriftTestCobClient(channel, protocolFactory.get());
client->testVoid(tr1::bind(testVoid_clientReturn, host.c_str(), port, base, protocolFactory.get(), _1));
event_base_loop(base, 0);
return 0;
}
ThriftTestClient testClient(protocol);
uint64_t time_min = 0;

150
test/cpp/src/TestServer.cpp Normal file → Executable file
View File

@ -27,6 +27,9 @@
#include <server/TSimpleServer.h>
#include <server/TThreadedServer.h>
#include <server/TThreadPoolServer.h>
#include <async/TEvhttpServer.h>
#include <async/TAsyncBufferProcessor.h>
#include <async/TAsyncProtocolProcessor.h>
#include <server/TNonblockingServer.h>
#include <transport/TServerSocket.h>
#include <transport/TSSLServerSocket.h>
@ -52,6 +55,7 @@ using namespace apache::thrift::concurrency;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;
using namespace apache::thrift::server;
using namespace apache::thrift::async;
using namespace thrift::test;
@ -345,6 +349,137 @@ class TestProcessorEventHandler : public TProcessorEventHandler {
};
class TestHandlerAsync : public ThriftTestCobSvIf {
public:
TestHandlerAsync(shared_ptr<TestHandler>& handler) : _delegate(handler) {}
virtual ~TestHandlerAsync() {}
virtual void testVoid(std::tr1::function<void()> cob) {
_delegate->testVoid();
cob();
}
virtual void testString(std::tr1::function<void(std::string const& _return)> cob, const std::string& thing) {
std::string res;
_delegate->testString(res, thing);
cob(res);
}
virtual void testByte(std::tr1::function<void(int8_t const& _return)> cob, const int8_t thing) {
int8_t res = _delegate->testByte(thing);
cob(res);
}
virtual void testI32(std::tr1::function<void(int32_t const& _return)> cob, const int32_t thing) {
int32_t res = _delegate->testI32(thing);
cob(res);
}
virtual void testI64(std::tr1::function<void(int64_t const& _return)> cob, const int64_t thing) {
int64_t res = _delegate->testI64(thing);
cob(res);
}
virtual void testDouble(std::tr1::function<void(double const& _return)> cob, const double thing) {
double res = _delegate->testDouble(thing);
cob(res);
}
virtual void testStruct(std::tr1::function<void(Xtruct const& _return)> cob, const Xtruct& thing) {
Xtruct res;
_delegate->testStruct(res, thing);
cob(res);
}
virtual void testNest(std::tr1::function<void(Xtruct2 const& _return)> cob, const Xtruct2& thing) {
Xtruct2 res;
_delegate->testNest(res, thing);
cob(res);
}
virtual void testMap(std::tr1::function<void(std::map<int32_t, int32_t> const& _return)> cob, const std::map<int32_t, int32_t> & thing) {
std::map<int32_t, int32_t> res;
_delegate->testMap(res, thing);
cob(res);
}
virtual void testStringMap(std::tr1::function<void(std::map<std::string, std::string> const& _return)> cob, const std::map<std::string, std::string> & thing) {
std::map<std::string, std::string> res;
_delegate->testStringMap(res, thing);
cob(res);
}
virtual void testSet(std::tr1::function<void(std::set<int32_t> const& _return)> cob, const std::set<int32_t> & thing) {
std::set<int32_t> res;
_delegate->testSet(res, thing);
cob(res);
}
virtual void testList(std::tr1::function<void(std::vector<int32_t> const& _return)> cob, const std::vector<int32_t> & thing) {
std::vector<int32_t> res;
_delegate->testList(res, thing);
cob(res);
}
virtual void testEnum(std::tr1::function<void(Numberz::type const& _return)> cob, const Numberz::type thing) {
Numberz::type res = _delegate->testEnum(thing);
cob(res);
}
virtual void testTypedef(std::tr1::function<void(UserId const& _return)> cob, const UserId thing) {
UserId res = _delegate->testTypedef(thing);
cob(res);
}
virtual void testMapMap(std::tr1::function<void(std::map<int32_t, std::map<int32_t, int32_t> > const& _return)> cob, const int32_t hello) {
std::map<int32_t, std::map<int32_t, int32_t> > res;
_delegate->testMapMap(res, hello);
cob(res);
}
virtual void testInsanity(std::tr1::function<void(std::map<UserId, std::map<Numberz::type, Insanity> > const& _return)> cob, const Insanity& argument) {
std::map<UserId, std::map<Numberz::type, Insanity> > res;
_delegate->testInsanity(res, argument);
cob(res);
}
virtual void testMulti(std::tr1::function<void(Xtruct const& _return)> cob, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string> & arg3, const Numberz::type arg4, const UserId arg5) {
Xtruct res;
_delegate->testMulti(res, arg0, arg1, arg2, arg3, arg4, arg5);
cob(res);
}
virtual void testException(std::tr1::function<void()> cob, std::tr1::function<void(::apache::thrift::TDelayedException* _throw)> exn_cob, const std::string& arg) {
try {
_delegate->testException(arg);
} catch(const apache::thrift::TException& e) {
exn_cob(apache::thrift::TDelayedException::delayException(e));
return;
}
cob();
}
virtual void testMultiException(std::tr1::function<void(Xtruct const& _return)> cob, std::tr1::function<void(::apache::thrift::TDelayedException* _throw)> exn_cob, const std::string& arg0, const std::string& arg1) {
Xtruct res;
try {
_delegate->testMultiException(res, arg0, arg1);
} catch(const apache::thrift::TException& e) {
exn_cob(apache::thrift::TDelayedException::delayException(e));
return;
}
cob(res);
}
virtual void testOneway(std::tr1::function<void()> cob, const int32_t secondsToSleep) {
_delegate->testOneway(secondsToSleep);
cob();
}
protected:
shared_ptr<TestHandler> _delegate;
};
int main(int argc, char **argv) {
int port = 9090;
bool ssl = false;
@ -464,7 +599,7 @@ int main(int argc, char **argv) {
// Factory
shared_ptr<TTransportFactory> transportFactory;
if (transport_type == "http") {
if (transport_type == "http" && server_type != "nonblocking") {
shared_ptr<TTransportFactory> httpTransportFactory(new THttpServerTransportFactory());
transportFactory = httpTransportFactory;
} else if (transport_type == "framed") {
@ -522,8 +657,17 @@ int main(int argc, char **argv) {
threadedServer.serve();
} else if (server_type == "nonblocking") {
TNonblockingServer nonblockingServer(testProcessor, port);
nonblockingServer.serve();
if(transport_type == "http") {
shared_ptr<TestHandlerAsync> testHandlerAsync(new TestHandlerAsync(testHandler));
shared_ptr<TAsyncProcessor> testProcessorAsync(new ThriftTestAsyncProcessor(testHandlerAsync));
shared_ptr<TAsyncBufferProcessor> testBufferProcessor(new TAsyncProtocolProcessor(testProcessorAsync, protocolFactory));
TEvhttpServer nonblockingServer(testBufferProcessor, port);
nonblockingServer.serve();
} else {
TNonblockingServer nonblockingServer(testProcessor, port);
nonblockingServer.serve();
}
}
cout << "done." << endl;