[tor-commits] [ooni-probe/master] Implement very simple HTTP Request backend that does only the part of HTTP we need for testing

art at torproject.org art at torproject.org
Thu Nov 22 20:06:25 UTC 2012


commit 4522dc005ea3f9c5379d44cf58c3696c62b129a2
Author: Arturo Filastò <art at fuffa.org>
Date:   Thu Nov 22 21:05:22 2012 +0100

    Implement very simple HTTP Request backend that does only the part of HTTP we need for testing
---
 oonib/oonibackend.py              |    2 +-
 oonib/testhelpers/http_helpers.py |   95 ++++++++++++++++++++++++++++++-------
 2 files changed, 79 insertions(+), 18 deletions(-)

diff --git a/oonib/oonibackend.py b/oonib/oonibackend.py
index c712bc4..c747bfd 100644
--- a/oonib/oonibackend.py
+++ b/oonib/oonibackend.py
@@ -68,7 +68,7 @@ if config.helpers.http_return_request.port:
     print "Starting HTTP return request helper on %s" % config.helpers.http_return_request.port
     http_return_request_helper = internet.TCPServer(
             int(config.helpers.http_return_request.port),
-            http_helpers.HTTPReturnJSONHeadersHelper)
+            http_helpers.HTTPReturnJSONHeadersHelper())
     http_return_request_helper.setServiceParent(serviceCollection)
 
 reactor.addSystemEventTrigger('after', 'shutdown', db_threadpool.stop)
diff --git a/oonib/testhelpers/http_helpers.py b/oonib/testhelpers/http_helpers.py
index 7001fa6..cbd6caa 100644
--- a/oonib/testhelpers/http_helpers.py
+++ b/oonib/testhelpers/http_helpers.py
@@ -10,11 +10,86 @@ from twisted.web.microdom import escape
 
 from cyclone.web import RequestHandler, Application
 
-class HTTPTrapAll(RequestHandler):
+from twisted.protocols import policies, basic
+from twisted.web.http import Request
+
+class SimpleHTTPChannel(basic.LineReceiver, policies.TimeoutMixin):
     """
-    Master class to be used to trap all the HTTP methods and make capitalized
-    requests pass.
+    This is a simplified version of twisted.web.http.HTTPChannel to overcome
+    header lowercase normalization. It does not actually implement the HTTP
+    protocol, but only the subset of it that we need for testing.
+
+    What this HTTP channel currently does is process the HTTP Request Line and
+    the Request Headers and returns them in a JSON datastructure in the order
+    we received them.
+
+    The returned JSON dict looks like so:
+
+    {
+        'request_headers': 
+            [['User-Agent', 'IE6'], ['Content-Length', 200]]
+        'request_line':
+            'GET / HTTP/1.1'
+    }
     """
+    requestFactory = Request
+    __first_line = 1
+    __header = ''
+    __content = None
+
+    length = 0
+    maxHeaders = 500
+    requestLine = ''
+    headers = []
+
+    timeOut = 60 * 60 * 12
+
+    def __init__(self):
+        self.requests = []
+
+    def connectionMade(self):
+        self.setTimeout(self.timeOut)
+
+    def lineReceived(self, line):
+        if self.__first_line:
+            self.requestLine = line
+            self.__first_line = 0
+        elif line == '':
+            # We have reached the end of the headers.
+            if self.__header:
+                self.headerReceived(self.__header)
+            self.__header = ''
+            self.allHeadersReceived()
+            self.setRawMode()
+        elif line[0] in ' \t':
+            # This is to support header field value folding over multiple lines
+            # as specified by rfc2616.
+            self.__header = self.__header+'\n'+line
+        else:
+            if self.__header:
+                self.headerReceived(self.__header)
+            self.__header = line
+
+    def headerReceived(self, line):
+        header, data = line.split(':', 1)
+        self.headers.append((header, data))
+
+    def allHeadersReceived(self):
+        response = {'request_headers': self.headers,
+            'request_line': self.requestLine
+        }
+        self.transport.write(json.dumps(response))
+        self.transport.loseConnection()
+
+
+class HTTPReturnJSONHeadersHelper(protocol.ServerFactory):
+    protocol = SimpleHTTPChannel
+    def buildProtocol(self, addr):
+        p = self.protocol()
+        p.headers = []
+        return p
+
+class HTTPTrapAll(RequestHandler):
     def _execute(self, transforms, *args, **kwargs):
         self._transforms = transforms
         defer.maybeDeferred(self.prepare).addCallbacks(
@@ -33,20 +108,6 @@ class HTTPTrapAll(RequestHandler):
             d.addCallbacks(self._execute_success, self._execute_failure)
             self.notifyFinish().addCallback(self.on_connection_close)
 
-class HTTPReturnJSONHeaders(HTTPTrapAll):
-    def all(self):
-        # XXX make sure that the request headers are in the correct order
-        submitted_data = {'request_body': self.request.body,
-                'request_headers': self.request.headers,
-                'request_uri': self.request.uri,
-                'request_method': self.request.method}
-        response = json.dumps(submitted_data)
-        self.write(response)
-
-HTTPReturnJSONHeadersHelper = Application([
-    (r"/*", HTTPReturnJSONHeaders)
-])
-
 
 class HTTPRandomPage(HTTPTrapAll):
     """



More information about the tor-commits mailing list