THRIFT-195. python: Add a simple THttpServer


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@739638 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/py/src/server/THttpServer.py b/lib/py/src/server/THttpServer.py
new file mode 100644
index 0000000..7a75619
--- /dev/null
+++ b/lib/py/src/server/THttpServer.py
@@ -0,0 +1,50 @@
+# Copyright (c) 2006- Facebook
+# Distributed under the Thrift Software License
+#
+# See accompanying file LICENSE or visit the Thrift site at:
+# http://developers.facebook.com/thrift/
+
+import BaseHTTPServer
+
+from thrift.server import TServer
+from thrift.transport import TTransport
+
+class THttpServer(TServer.TServer):
+  """A simple HTTP-based Thrift server
+
+  This class is not very performant, but it is useful (for example) for
+  acting as a mock version of an Apache-based PHP Thrift endpoint."""
+
+  def __init__(self, processor, server_address,
+      inputProtocolFactory, outputProtocolFactory = None):
+    """Set up protocol factories and HTTP server.
+
+    See BaseHTTPServer for server_address.
+    See TServer for protocol factories."""
+
+    if outputProtocolFactory is None:
+      outputProtocolFactory = inputProtocolFactory
+
+    TServer.TServer.__init__(self, processor, None, None, None,
+        inputProtocolFactory, outputProtocolFactory)
+
+    thttpserver = self
+
+    class RequestHander(BaseHTTPServer.BaseHTTPRequestHandler):
+      def do_POST(self):
+        # Don't care about the request path.
+        self.send_response(200)
+        self.send_header("content-type", "application/x-thrift")
+        self.end_headers()
+
+        itrans = TTransport.TFileObjectTransport(self.rfile)
+        otrans = TTransport.TFileObjectTransport(self.wfile)
+        iprot = thttpserver.inputProtocolFactory.getProtocol(itrans)
+        oprot = thttpserver.outputProtocolFactory.getProtocol(otrans)
+        thttpserver.processor.process(iprot, oprot)
+        otrans.flush()
+
+    self.httpd = BaseHTTPServer.HTTPServer(server_address, RequestHander)
+
+  def serve(self):
+    self.httpd.serve_forever()
diff --git a/test/py/RunClientServer.py b/test/py/RunClientServer.py
index b4fd382..34f883e 100755
--- a/test/py/RunClientServer.py
+++ b/test/py/RunClientServer.py
@@ -19,6 +19,8 @@
         argv = [sys.executable, relfile("TestClient.py")]
         if server_class in FRAMED:
             argv.append('--framed')
+        if server_class == 'THttpServer':
+            argv.append('--http=/')
         ret = subprocess.call(argv)
         if ret != 0:
             raise Exception("subprocess failed")
@@ -29,5 +31,11 @@
     # wait for shutdown
     time.sleep(1)
 
-map(runTest, ["TForkingServer", "TThreadPoolServer",
-              "TThreadedServer", "TSimpleServer", "TNonblockingServer"])
+map(runTest, [
+  "TSimpleServer",
+  "TThreadedServer",
+  "TThreadPoolServer",
+  "TForkingServer",
+  "TNonblockingServer",
+  "THttpServer",
+  ])
diff --git a/test/py/TestClient.py b/test/py/TestClient.py
index 501d197..944e384 100755
--- a/test/py/TestClient.py
+++ b/test/py/TestClient.py
@@ -8,6 +8,7 @@
 from ThriftTest.ttypes import *
 from thrift.transport import TTransport
 from thrift.transport import TSocket
+from thrift.transport import THttpClient
 from thrift.protocol import TBinaryProtocol
 import unittest
 import time
@@ -15,13 +16,15 @@
 
 
 parser = OptionParser()
-parser.set_defaults(framed=False, verbose=1, host='localhost', port=9090)
+parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090)
 parser.add_option("--port", type="int", dest="port",
     help="connect to server at port")
 parser.add_option("--host", type="string", dest="host",
     help="connect to server")
 parser.add_option("--framed", action="store_true", dest="framed",
     help="use framed transport")
+parser.add_option("--http", dest="http_path",
+    help="Use the HTTP transport with the specified path")
 parser.add_option('-v', '--verbose', action="store_const", 
     dest="verbose", const=2,
     help="verbose output")
@@ -33,13 +36,17 @@
 
 class AbstractTest(unittest.TestCase):
   def setUp(self):
-    socket = TSocket.TSocket(options.host, options.port)
-
-    # Frame or buffer depending upon args
-    if options.framed:
-      self.transport = TTransport.TFramedTransport(socket)
+    if options.http_path:
+      self.transport = THttpClient.THttpClient(
+          options.host, options.port, options.http_path)
     else:
-      self.transport = TTransport.TBufferedTransport(socket)
+      socket = TSocket.TSocket(options.host, options.port)
+
+      # frame or buffer depending upon args
+      if options.framed:
+        self.transport = TTransport.TFramedTransport(socket)
+      else:
+        self.transport = TTransport.TBufferedTransport(socket)
 
     self.transport.open()
 
diff --git a/test/py/TestServer.py b/test/py/TestServer.py
index a7bf6d0..7abb624 100755
--- a/test/py/TestServer.py
+++ b/test/py/TestServer.py
@@ -9,7 +9,7 @@
 from thrift.transport import TTransport
 from thrift.transport import TSocket
 from thrift.protocol import TBinaryProtocol
-from thrift.server import TServer, TNonblockingServer
+from thrift.server import TServer, TNonblockingServer, THttpServer
 
 class TestHandler:
 
@@ -77,15 +77,20 @@
   def testTypedef(self, thing):
     return thing
 
+pfactory = TBinaryProtocol.TBinaryProtocolFactory()
 handler = TestHandler()
 processor = ThriftTest.Processor(handler)
-transport = TSocket.TServerSocket(9090)
-tfactory = TTransport.TBufferedTransportFactory()
-pfactory = TBinaryProtocol.TBinaryProtocolFactory()
 
-if sys.argv[1] == "TNonblockingServer":
-  server = TNonblockingServer.TNonblockingServer(processor, transport)
+if sys.argv[1] == "THttpServer":
+  server = THttpServer.THttpServer(processor, ('', 9090), pfactory)
 else:
-  ServerClass = getattr(TServer, sys.argv[1])
-  server = ServerClass(processor, transport, tfactory, pfactory)
+  transport = TSocket.TServerSocket(9090)
+  tfactory = TTransport.TBufferedTransportFactory()
+
+  if sys.argv[1] == "TNonblockingServer":
+    server = TNonblockingServer.TNonblockingServer(processor, transport)
+  else:
+    ServerClass = getattr(TServer, sys.argv[1])
+    server = ServerClass(processor, transport, tfactory, pfactory)
+
 server.serve()