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
diff --git a/test/cpp/Makefile.am b/test/cpp/Makefile.am
index a828e57..6c62cfb 100755
--- a/test/cpp/Makefile.am
+++ b/test/cpp/Makefile.am
@@ -87,7 +87,7 @@
 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 @@
 
 AM_CPPFLAGS = $(BOOST_CPPFLAGS)
 AM_CXXFLAGS = -Wall
+AM_LDFLAGS = $(BOOST_LDFLAGS)
 
 clean-local:
 	$(RM) -r gen-cpp
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
index ceea838..3f22ad2 100644
--- a/test/cpp/src/TestClient.cpp
+++ b/test/cpp/src/TestClient.cpp
@@ -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::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 @@
   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 @@
       ("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 @@
       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 @@
   }
   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;
diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp
old mode 100644
new mode 100755
index 9ba0509..2c9d43a
--- a/test/cpp/src/TestServer.cpp
+++ b/test/cpp/src/TestServer.cpp
@@ -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::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 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 @@
   // 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 @@
     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;