[tor-commits] [flashproxy/master] Move some common code to fac.py.

dcf at torproject.org dcf at torproject.org
Fri Aug 31 11:39:36 UTC 2012


commit af7de115115516435388503fe21c22a03d3b7445
Author: David Fifield <david at bamsoftware.com>
Date:   Sat Aug 11 08:53:49 2012 -0700

    Move some common code to fac.py.
---
 fac.py      |  133 +++++++++++++++++++++++++++++++++++++++++++++++++++
 facilitator |  154 +++++------------------------------------------------------
 2 files changed, 145 insertions(+), 142 deletions(-)

diff --git a/fac.py b/fac.py
new file mode 100644
index 0000000..ab8157c
--- /dev/null
+++ b/fac.py
@@ -0,0 +1,133 @@
+import re
+import socket
+
+def parse_addr_spec(spec, defhost = None, defport = None):
+    host = None
+    port = None
+    m = None
+    # IPv6 syntax.
+    if not m:
+        m = re.match(ur'^\[(.+)\]:(\d+)$', spec)
+        if m:
+            host, port = m.groups()
+            af = socket.AF_INET6
+    if not m:
+        m = re.match(ur'^\[(.+)\]:?$', spec)
+        if m:
+            host, = m.groups()
+            af = socket.AF_INET6
+    # IPv4 syntax.
+    if not m:
+        m = re.match(ur'^(.+):(\d+)$', spec)
+        if m:
+            host, port = m.groups()
+            af = socket.AF_INET
+    if not m:
+        m = re.match(ur'^:?(\d+)$', spec)
+        if m:
+            port, = m.groups()
+            af = 0
+    if not m:
+        host = spec
+        af = 0
+    host = host or defhost
+    port = port or defport
+    if not (host and port):
+        raise ValueError("Bad address specification \"%s\"" % spec)
+    return af, host, int(port)
+
+def format_addr(addr):
+    host, port = addr
+    if not host:
+        return u":%d" % port
+    # Numeric IPv6 address?
+    try:
+        addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
+        af = addrs[0][0]
+    except socket.gaierror, e:
+        af = 0
+    if af == socket.AF_INET6:
+        return u"[%s]:%d" % (host, port)
+    else:
+        return u"%s:%d" % (host, port)
+
+def skip_space(pos, line):
+    """Skip a (possibly empty) sequence of space characters (the ASCII character
+    '\x20' exactly). Returns a pair (pos, num_skipped)."""
+    begin = pos
+    while pos < len(line) and line[pos] == "\x20":
+        pos += 1
+    return pos, pos - begin
+
+TOKEN_CHARS = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-")
+def get_token(pos, line):
+    begin = pos
+    while pos < len(line) and line[pos] in TOKEN_CHARS:
+        pos += 1
+    if begin == pos:
+        raise ValueError("No token found at position %d" % pos)
+    return pos, line[begin:pos]
+
+def get_quoted_string(pos, line):
+    chars = []
+    if not (pos < len(line) and line[pos] == '"'):
+        raise ValueError("Expected '\"' at beginning of quoted string.")
+    pos += 1
+    while pos < len(line) and line[pos] != '"':
+        if line[pos] == '\\':
+            pos += 1
+            if not (pos < len(line)):
+                raise ValueError("End of line after backslash in quoted string")
+        chars.append(line[pos])
+        pos += 1
+    if not (pos < len(line) and line[pos] == '"'):
+        raise ValueError("Expected '\"' at end of quoted string.")
+    pos += 1
+    return pos, "".join(chars)
+
+def parse_transaction(line):
+    """A transaction is a command followed by zero or more key-value pairs. Like so:
+      COMMAND KEY="VALUE" KEY="\"ESCAPED\" VALUE"
+    Values must be quoted. Any byte value may be escaped with a backslash.
+    Returns a pair: (COMMAND, ((KEY1, VALUE1), (KEY2, VALUE2), ...)).
+    """
+    pos = 0
+    pos, skipped = skip_space(pos, line)
+    pos, command = get_token(pos, line)
+
+    pairs = []
+    while True:
+        pos, skipped = skip_space(pos, line)
+        if not (pos < len(line)):
+            break
+        if skipped == 0:
+            raise ValueError("Expected space before key-value pair")
+        pos, key = get_token(pos, line)
+        if not (pos < len(line) and line[pos] == '='):
+            raise ValueError("No '=' found after key")
+        pos += 1
+        pos, value = get_quoted_string(pos, line)
+        pairs.append((key, value))
+    return command, tuple(pairs)
+
+def param_first(key, params):
+    for k, v in params:
+        if key == k:
+            return v
+    return None
+
+def quote_string(s):
+    chars = []
+    for c in s:
+        if c == "\\":
+            c = "\\\\"
+        elif c == "\"":
+            c = "\\\""
+        chars.append(c)
+    return "\"" + "".join(chars) + "\""
+
+def render_transaction(command, *params):
+    parts = [command]
+    for key, value in params:
+        parts.append("%s=%s" % (key, quote_string(value)))
+    return " ".join(parts)
diff --git a/facilitator b/facilitator
index 2ab6491..d1e25a4 100755
--- a/facilitator
+++ b/facilitator
@@ -3,12 +3,13 @@
 import SocketServer
 import getopt
 import os
-import re
 import socket
 import sys
 import threading
 import time
 
+import fac
+
 LISTEN_ADDRESS = "127.0.0.1"
 DEFAULT_LISTEN_PORT = 9002
 DEFAULT_RELAY_PORT = 9001
@@ -32,10 +33,10 @@ class options(object):
 
     @staticmethod
     def set_relay_spec(spec):
-        af, host, port = parse_addr_spec(spec, defport = DEFAULT_RELAY_PORT)
+        af, host, port = fac.parse_addr_spec(spec, defport = DEFAULT_RELAY_PORT)
         # Resolve to get an IP address.
         addrs = socket.getaddrinfo(host, port, af)
-        options.relay_spec = format_addr(addrs[0][4])
+        options.relay_spec = fac.format_addr(addrs[0][4])
 
 def usage(f = sys.stdout):
     print >> f, """\
@@ -71,144 +72,13 @@ def log(msg):
     finally:
         log_lock.release()
 
-def parse_addr_spec(spec, defhost = None, defport = None):
-    host = None
-    port = None
-    m = None
-    # IPv6 syntax.
-    if not m:
-        m = re.match(ur'^\[(.+)\]:(\d+)$', spec)
-        if m:
-            host, port = m.groups()
-            af = socket.AF_INET6
-    if not m:
-        m = re.match(ur'^\[(.+)\]:?$', spec)
-        if m:
-            host, = m.groups()
-            af = socket.AF_INET6
-    # IPv4 syntax.
-    if not m:
-        m = re.match(ur'^(.+):(\d+)$', spec)
-        if m:
-            host, port = m.groups()
-            af = socket.AF_INET
-    if not m:
-        m = re.match(ur'^:?(\d+)$', spec)
-        if m:
-            port, = m.groups()
-            af = 0
-    if not m:
-        host = spec
-        af = 0
-    host = host or defhost
-    port = port or defport
-    if not (host and port):
-        raise ValueError("Bad address specification \"%s\"" % spec)
-    return af, host, int(port)
-
-def format_addr(addr):
-    host, port = addr
-    if not host:
-        return u":%d" % port
-    # Numeric IPv6 address?
-    try:
-        addrs = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.IPPROTO_TCP, socket.AI_NUMERICHOST)
-        af = addrs[0][0]
-    except socket.gaierror, e:
-        af = 0
-    if af == socket.AF_INET6:
-        return u"[%s]:%d" % (host, port)
-    else:
-        return u"%s:%d" % (host, port)
-
-def skip_space(pos, line):
-    """Skip a (possibly empty) sequence of space characters (the ASCII character
-    '\x20' exactly). Returns a pair (pos, num_skipped)."""
-    begin = pos
-    while pos < len(line) and line[pos] == "\x20":
-        pos += 1
-    return pos, pos - begin
-
-TOKEN_CHARS = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-")
-def get_token(pos, line):
-    begin = pos
-    while pos < len(line) and line[pos] in TOKEN_CHARS:
-        pos += 1
-    if begin == pos:
-        raise ValueError("No token found at position %d" % pos)
-    return pos, line[begin:pos]
-
-def get_quoted_string(pos, line):
-    chars = []
-    if not (pos < len(line) and line[pos] == '"'):
-        raise ValueError("Expected '\"' at beginning of quoted string.")
-    pos += 1
-    while pos < len(line) and line[pos] != '"':
-        if line[pos] == '\\':
-            pos += 1
-            if not (pos < len(line)):
-                raise ValueError("End of line after backslash in quoted string")
-        chars.append(line[pos])
-        pos += 1
-    if not (pos < len(line) and line[pos] == '"'):
-        raise ValueError("Expected '\"' at end of quoted string.")
-    pos += 1
-    return pos, "".join(chars)
-
-def parse_command(line):
-    """A line is a command followed by zero or more key-value pairs. Like so:
-      COMMAND KEY="VALUE" KEY="\"ESCAPED\" VALUE"
-    Values must be quoted. Any byte value may be escaped with a backslash.
-    Returns a pair: (COMMAND, ((KEY1, VALUE1), (KEY2, VALUE2), ...)).
-    """
-    pos = 0
-    pos, skipped = skip_space(pos, line)
-    pos, command = get_token(pos, line)
-
-    pairs = []
-    while True:
-        pos, skipped = skip_space(pos, line)
-        if not (pos < len(line)):
-            break
-        if skipped == 0:
-            raise ValueError("Expected space before key-value pair")
-        pos, key = get_token(pos, line)
-        if not (pos < len(line) and line[pos] == '='):
-            raise ValueError("No '=' found after key")
-        pos += 1
-        pos, value = get_quoted_string(pos, line)
-        pairs.append((key, value))
-    return command, tuple(pairs)
-
-def param_first(key, params):
-    for k, v in params:
-        if key == k:
-            return v
-    return None
-
-def quote_string(s):
-    chars = []
-    for c in s:
-        if c == "\\":
-            c = "\\\\"
-        elif c == "\"":
-            c = "\\\""
-        chars.append(c)
-    return "\"" + "".join(chars) + "\""
-
-def render_params(params):
-    parts = []
-    for key, value in params:
-        parts.append("%s=%s" % (key, quote_string(value)))
-    return " ".join(parts)
-
 class TCPReg(object):
     def __init__(self, host, port):
         self.host = host
         self.port = port
 
     def __unicode__(self):
-        return format_addr((self.host, self.port))
+        return fac.format_addr((self.host, self.port))
 
     def __str__(self):
         return unicode(self).encode("UTF-8")
@@ -223,7 +93,7 @@ class Reg(object):
     @staticmethod
     def parse(spec, defhost = None, defport = None):
         try:
-            af, host, port = parse_addr_spec(spec, defhost, defport)
+            af, host, port = fac.parse_addr_spec(spec, defhost, defport)
         except ValueError:
             pass
         else:
@@ -330,9 +200,9 @@ class Handler(SocketServer.StreamRequestHandler):
         if not (len(line) > 0 and line[-1] == '\n'):
             raise ValueError("No newline at end of string returned by readline")
         try:
-            command, params = parse_command(line[:-1])
+            command, params = fac.parse_transaction(line[:-1])
         except ValueError, e:
-            log("parse_command: %s" % e)
+            log("fac.parse_transaction: %s" % e)
             self.send_error()
             return False
 
@@ -355,14 +225,14 @@ class Handler(SocketServer.StreamRequestHandler):
         if reg:
             log(u"proxy gets %s, relay %s (now %d)" %
                 (safe_str(unicode(reg)), options.relay_spec, len(REGS)))
-            print >> self.wfile, "OK", render_params((("CLIENT", str(reg)), ("RELAY", options.relay_spec)))
+            print >> self.wfile, fac.render_transaction("OK", ("CLIENT", str(reg)), ("RELAY", options.relay_spec))
         else:
             log(u"proxy gets none")
-            print >> self.wfile, "NONE"
+            print >> self.wfile, fac.render_transaction("NONE")
         return True
 
     def do_PUT(self, params):
-        client_spec = param_first("CLIENT", params)
+        client_spec = fac.param_first("CLIENT", params)
         if client_spec is None:
             log(u"PUT missing CLIENT param")
             self.send_error()
@@ -433,7 +303,7 @@ The -r option is required. Give it the relay that will be sent to proxies.
 
     server = Server(addrinfo[4], Handler)
 
-    log(u"start on %s" % format_addr(addrinfo[4]))
+    log(u"start on %s" % fac.format_addr(addrinfo[4]))
     log(u"using relay address %s" % options.relay_spec)
 
     if options.daemonize:





More information about the tor-commits mailing list