[tor-commits] [flashproxy/master] Make the facilitator use real HTTP in its responses.
dcf at torproject.org
dcf at torproject.org
Fri Jun 10 13:59:53 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