[tor-commits] [flashproxy/rtmfp] Make the facilitator use real HTTP in its responses.

dcf at torproject.org dcf at torproject.org
Fri Jun 10 13:59:54 UTC 2011


commit a3c045f340661c9256d08de86dc70e055feae25a
Author: David Fifield <david at bamsoftware.com>
Date:   Fri May 20 05:07:48 2011 -0700

    Make the facilitator use real HTTP in its responses.
---
 README         |   12 +++++++-----
 design.txt     |   24 ++++++++++++------------
 facilitator.py |   29 ++++++++++++++++++++++++++++-
 3 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/README b/README
index 067f92e..4e58907 100644
--- a/README
+++ b/README
@@ -87,16 +87,18 @@ with the caveat that the server also has to serve a crossdomain policy.
 The Tor client needs to be able to listen for an incoming connection,
 which generally means not being behind NAT.
 
-Clients register with the facilitator by sending an HTTP-like message:
+Clients register with the facilitator by sending an HTTP message:
 	POST / HTTP/1.0\r\n
 	\r\n
 	client=:9000
-
-The Flash proxy also gets a client address using something like HTTP:
+The Flash proxy also gets a client address over HTTP:
 	GET / HTTP/1.0\r\n
 	\r\n
-The server sends back an address specification (no HTTP header):
-	192.168.0.102:8888
+The server sends back an address specification in an HTTP respose.
+	HTTP/1.0 200 OK\r\n
+	Server: BaseHTTP/0.3 Python/2.5.2\r\n
+	\r\n
+	client=1.2.3.4%3A9000
 
 == ActionScript programming
 
diff --git a/design.txt b/design.txt
index 4776b73..abc53a4 100644
--- a/design.txt
+++ b/design.txt
@@ -108,10 +108,11 @@ Design of Flash proxies
 
     client=[<address>]:<port>
 
-  (The facilitator sends back no data in response.) If the connector
-  omits the [<address>] part, the facilitator will automatically fill it
-  in based on the HTTP client address, which means the connector doesn't
-  have to know its external address.
+  The facilitator sends a 200 reply if the registration was successful
+  and an error status otherwise. If the connector omits the [<address>]
+  part, the facilitator will automatically fill it in based on the HTTP
+  client address, which means the connector doesn't have to know its
+  external address.
 
   The connector solves the impedance mismatch between the Tor client and
   the Flash proxy, both of which want to make outgoing connections to
@@ -136,22 +137,21 @@ Design of Flash proxies
     GET / HTTP/1.0
 
 
-  The response is not really HTTP: the data follows immediately with no
-  HTTP header. An empty document means that there are no clients
-  registered. Otherwise, the response looks like this:
+  The response code is 200 and the body looks like this:
 
-    <address>:<port>
+    client=[<address>:<port>]
 
-  Both <address> and <port> are required.
+  If <address>:<port> is missing, it means that there are no client
+  registrations for this proxy.
 
   The Flash proxy may serve more than one relay–client pair at once. It
   limits its own bandwidth to 10 KB/s (combined upload/download).
 
 8. Behavior of the facilitator
 
-  The faciliator is a pseudo-HTTP server that handles client POST
-  registrations and proxy GET requests according to the formats given
-  above. The facilitator listens on port 9002.
+  The faciliator is a HTTP server that handles client POST registrations
+  and proxy GET requests according to the formats given above. The
+  facilitator listens on port 9002.
 
   In the current implementation, the facilitator forgets a client
   registration after giving it to a Flash proxy. The client must
diff --git a/facilitator.py b/facilitator.py
index d5bac75..56a9774 100755
--- a/facilitator.py
+++ b/facilitator.py
@@ -10,6 +10,7 @@ import socket
 import sys
 import threading
 import time
+import urllib
 
 DEFAULT_ADDRESS = "0.0.0.0"
 DEFAULT_PORT = 9002
@@ -193,20 +194,23 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
         reg = REGS.fetch()
         if reg:
             log(u"proxy %s gets %s (now %d)" % (format_addr(self.client_address), unicode(reg), len(REGS)))
-            self.request.send(str(reg))
+            self.send_client(reg)
         else:
             log(u"proxy %s gets none" % format_addr(self.client_address))
+            self.send_client(None)
 
     def do_POST(self):
         data = self.rfile.readline(1024).strip()
         try:
             vals = cgi.parse_qs(data, False, True)
         except ValueError, e:
+            self.send_error(400)
             log(u"client %s POST syntax error: %s" % (format_addr(self.client_address), repr(str(e))))
             return
 
         client_specs = vals.get("client")
         if client_specs is None or len(client_specs) != 1:
+            self.send_error(400)
             log(u"client %s missing \"client\" param" % format_addr(self.client_address))
             return
         val = client_specs[0]
@@ -214,6 +218,7 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
         try:
             reg = Reg.parse(val, self.client_address[0])
         except ValueError, e:
+            self.send_error(400)
             log(u"client %s syntax error in %s: %s" % (format_addr(self.client_address), repr(val), repr(str(e))))
             return
 
@@ -223,10 +228,32 @@ class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
         else:
             log(u"client %s %s (already present, now %d)" % (format_addr(self.client_address), unicode(reg), len(REGS)))
 
+        self.send_response(200)
+        self.end_headers()
+
+    def send_error(self, code, message = None):
+        self.send_response(code)
+        self.end_headers()
+        if message:
+            self.wfile.write(message)
+
     def log_message(self, format, *args):
         msg = format % args
         log(u"message from HTTP handler for %s: %s" % (format_addr(self.client_address), repr(msg)))
 
+    def send_client(self, reg):
+        if reg:
+            client_str = str(reg)
+        else:
+            # Send an empty string rather than a 404 or similar because Flash
+            # Player's URLLoader can't always distinguish a 404 from, say,
+            # "server not found."
+            client_str = ""
+        self.send_response(200)
+        self.send_header("Content-Type", "x-www-form-urlencoded")
+        self.end_headers()
+        self.request.send(urllib.urlencode({"client": client_str}))
+
 REGS = RegSet()
 
 opts, args = getopt.gnu_getopt(sys.argv[1:], "dhl:", ["debug", "help", "log="])





More information about the tor-commits mailing list