From c04885449dc91205322d8cae9ccc9ebed8f75a68 Mon Sep 17 00:00:00 2001
From: aum <aum>
Date: Sat, 31 Jul 2004 18:51:45 +0000
Subject: [PATCH] Replaced these files with:  - I2PSocketServer.py  -
 I2PBaseHTTPServer.py  - I2PSimpleHTTPServer.py  - I2PCGIHTTPServer.py
 difference being that these new modules are not hacks of the original python
 server modules, rather, they subclass the python server modules; this
 overcomes the Fear and Loathing expressed by some regarding multiplicity of
 licenses, and apart from that, is a better idea anyway. Only danger being if
 the modules in later Python releases change substantially, these modules
 could get broken.

---
 apps/sam/python/src/i2p/BaseHTTPServer.py   | 575 --------------------
 apps/sam/python/src/i2p/CGIHTTPServer.py    | 316 -----------
 apps/sam/python/src/i2p/SimpleHTTPServer.py | 201 -------
 apps/sam/python/src/i2p/SocketServer.py     | 542 ------------------
 apps/sam/python/src/i2p/__init__.py         |   3 +-
 5 files changed, 2 insertions(+), 1635 deletions(-)
 delete mode 100644 apps/sam/python/src/i2p/BaseHTTPServer.py
 delete mode 100644 apps/sam/python/src/i2p/CGIHTTPServer.py
 delete mode 100644 apps/sam/python/src/i2p/SimpleHTTPServer.py
 delete mode 100644 apps/sam/python/src/i2p/SocketServer.py

diff --git a/apps/sam/python/src/i2p/BaseHTTPServer.py b/apps/sam/python/src/i2p/BaseHTTPServer.py
deleted file mode 100644
index dc7f4fa4ef..0000000000
--- a/apps/sam/python/src/i2p/BaseHTTPServer.py
+++ /dev/null
@@ -1,575 +0,0 @@
-#! /usr/bin/env python
-"""HTTP server base class.
-
-Hacked by aum for I2P SAM Socket compatibility
-
---
-
-Note: the class in this module doesn't implement any HTTP request; see
-SAMSimpleHTTPServer for simple implementations of GET, HEAD and POST
-(including CGI scripts).  It does, however, optionally implement HTTP/1.1
-persistent connections, as of version 0.3.
-
-Contents:
-
-- BaseHTTPRequestHandler: HTTP request handler base class
-- test: test function
-
-XXX To do:
-
-- log requests even later (to capture byte count)
-- log user-agent header and other interesting goodies
-- send error log to separate file
-"""
-
-# See also:
-#
-# HTTP Working Group                                        T. Berners-Lee
-# INTERNET-DRAFT                                            R. T. Fielding
-# <draft-ietf-http-v10-spec-00.txt>                     H. Frystyk Nielsen
-# Expires September 8, 1995                                  March 8, 1995
-#
-# URL: http://www.ics.uci.edu/pub/ietf/http/draft-ietf-http-v10-spec-00.txt
-#
-# and
-#
-# Network Working Group                                      R. Fielding
-# Request for Comments: 2616                                       et al
-# Obsoletes: 2068                                              June 1999
-# Category: Standards Track
-#
-# URL: http://www.faqs.org/rfcs/rfc2616.html
-
-# Log files
-# ---------
-#
-# Here's a quote from the NCSA httpd docs about log file format.
-#
-# | The logfile format is as follows. Each line consists of:
-# |
-# | host rfc931 authuser [DD/Mon/YYYY:hh:mm:ss] "request" ddd bbbb
-# |
-# |        host: Either the DNS name or the IP number of the remote client
-# |        rfc931: Any information returned by identd for this person,
-# |                - otherwise.
-# |        authuser: If user sent a userid for authentication, the user name,
-# |                  - otherwise.
-# |        DD: Day
-# |        Mon: Month (calendar name)
-# |        YYYY: Year
-# |        hh: hour (24-hour format, the machine's timezone)
-# |        mm: minutes
-# |        ss: seconds
-# |        request: The first line of the HTTP request as sent by the client.
-# |        ddd: the status code returned by the server, - if not available.
-# |        bbbb: the total number of bytes sent,
-# |              *not including the HTTP/1.0 header*, - if not available
-# |
-# | You can determine the name of the file accessed through request.
-#
-# (Actually, the latter is only true if you know the server configuration
-# at the time the request was made!)
-
-
-import sys
-import time
-
-# replace official python socket module with sunshine's I2P sam module
-#import socket
-import i2p
-from i2p import sam as socket
-
-import mimetools
-from i2p import SocketServer
-
-import cStringIO
-
-__version__ = "0.3"
-
-__all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
-
-# Default error message
-DEFAULT_ERROR_MESSAGE = """\
-<head>
-<title>Error response</title>
-</head>
-<body>
-<h1>Error response</h1>
-<p>Error code %(code)d.
-<p>Message: %(message)s.
-<p>Error code explanation: %(code)s = %(explain)s.
-</body>
-"""
-class HTTPServer(SocketServer.TCPServer):
-    allow_reuse_address = 1    # Seems to make sense in testing environment
-    
-    def server_bind(self):
-        """Override server_bind to store the server name."""
-        SocketServer.TCPServer.server_bind(self)
-        self.server_name = self.server_address
-    
-class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
-
-    """HTTP request handler base class.
-
-    The following explanation of HTTP serves to guide you through the
-    code as well as to expose any misunderstandings I may have about
-    HTTP (so you don't need to read the code to figure out I'm wrong
-    :-).
-
-    HTTP (HyperText Transfer Protocol) is an extensible protocol on
-    top of a reliable stream transport (e.g. TCP/IP).  The protocol
-    recognizes three parts to a request:
-
-    1. One line identifying the request type and path
-    2. An optional set of RFC-822-style headers
-    3. An optional data part
-
-    The headers and data are separated by a blank line.
-
-    The first line of the request has the form
-
-    <command> <path> <version>
-
-    where <command> is a (case-sensitive) keyword such as GET or POST,
-    <path> is a string containing path information for the request,
-    and <version> should be the string "HTTP/1.0" or "HTTP/1.1".
-    <path> is encoded using the URL encoding scheme (using %xx to signify
-    the ASCII character with hex code xx).
-
-    The specification specifies that lines are separated by CRLF but
-    for compatibility with the widest range of clients recommends
-    servers also handle LF.  Similarly, whitespace in the request line
-    is treated sensibly (allowing multiple spaces between components
-    and allowing trailing whitespace).
-
-    Similarly, for output, lines ought to be separated by CRLF pairs
-    but most clients grok LF characters just fine.
-
-    If the first line of the request has the form
-
-    <command> <path>
-
-    (i.e. <version> is left out) then this is assumed to be an HTTP
-    0.9 request; this form has no optional headers and data part and
-    the reply consists of just the data.
-
-    The reply form of the HTTP 1.x protocol again has three parts:
-
-    1. One line giving the response code
-    2. An optional set of RFC-822-style headers
-    3. The data
-
-    Again, the headers and data are separated by a blank line.
-
-    The response code line has the form
-
-    <version> <responsecode> <responsestring>
-
-    where <version> is the protocol version ("HTTP/1.0" or "HTTP/1.1"),
-    <responsecode> is a 3-digit response code indicating success or
-    failure of the request, and <responsestring> is an optional
-    human-readable string explaining what the response code means.
-
-    This server parses the request and the headers, and then calls a
-    function specific to the request type (<command>).  Specifically,
-    a request SPAM will be handled by a method do_SPAM().  If no
-    such method exists the server sends an error response to the
-    client.  If it exists, it is called with no arguments:
-
-    do_SPAM()
-
-    Note that the request name is case sensitive (i.e. SPAM and spam
-    are different requests).
-
-    The various request details are stored in instance variables:
-
-    - client_address is the client IP address in the form (host,
-    port);
-
-    - command, path and version are the broken-down request line;
-
-    - headers is an instance of mimetools.Message (or a derived
-    class) containing the header information;
-
-    - rfile is a file object open for reading positioned at the
-    start of the optional input data part;
-
-    - wfile is a file object open for writing.
-
-    IT IS IMPORTANT TO ADHERE TO THE PROTOCOL FOR WRITING!
-
-    The first thing to be written must be the response line.  Then
-    follow 0 or more header lines, then a blank line, and then the
-    actual data (if any).  The meaning of the header lines depends on
-    the command executed by the server; in most cases, when data is
-    returned, there should be at least one header line of the form
-
-    Content-type: <type>/<subtype>
-
-    where <type> and <subtype> should be registered MIME types,
-    e.g. "text/html" or "text/plain".
-
-    """
-    # The Python system version, truncated to its first component.
-    sys_version = "Python/" + sys.version.split()[0]
-    
-    # The server software version.  You may want to override this.
-    # The format is multiple whitespace-separated strings,
-    # where each string is of the form name[/version].
-    server_version = "BaseHTTP/" + __version__
-    
-    def parse_request(self):
-        """Parse a request (internal).
-    
-        The request should be stored in self.raw_requestline; the results
-        are in self.command, self.path, self.request_version and
-        self.headers.
-    
-        Return True for success, False for failure; on failure, an
-        error is sent back.
-    
-        """
-        self.command = None  # set in case of error on the first line
-        self.request_version = version = "HTTP/0.9" # Default
-        self.close_connection = 1
-        requestline = self.raw_requestline
-        if requestline[-2:] == '\r\n':
-            requestline = requestline[:-2]
-        elif requestline[-1:] == '\n':
-            requestline = requestline[:-1]
-        self.requestline = requestline
-        words = requestline.split()
-        if len(words) == 3:
-            [command, path, version] = words
-            if version[:5] != 'HTTP/':
-                self.send_error(400, "Bad request version (%s)" % `version`)
-                return False
-            try:
-                base_version_number = version.split('/', 1)[1]
-                version_number = base_version_number.split(".")
-                # RFC 2145 section 3.1 says there can be only one "." and
-                #   - major and minor numbers MUST be treated as
-                #      separate integers;
-                #   - HTTP/2.4 is a lower version than HTTP/2.13, which in
-                #      turn is lower than HTTP/12.3;
-                #   - Leading zeros MUST be ignored by recipients.
-                if len(version_number) != 2:
-                    raise ValueError
-                version_number = int(version_number[0]), int(version_number[1])
-            except (ValueError, IndexError):
-                self.send_error(400, "Bad request version (%s)" % `version`)
-                return False
-            if version_number >= (1, 1) and self.protocol_version >= "HTTP/1.1":
-                self.close_connection = 0
-            if version_number >= (2, 0):
-                self.send_error(505,
-                          "Invalid HTTP Version (%s)" % base_version_number)
-                return False
-        elif len(words) == 2:
-            [command, path] = words
-            self.close_connection = 1
-            if command != 'GET':
-                self.send_error(400,
-                                "Bad HTTP/0.9 request type (%s)" % `command`)
-                return False
-        elif not words:
-            return False
-        else:
-            self.send_error(400, "Bad request syntax (%s)" % `requestline`)
-            return False
-        self.command, self.path, self.request_version = command, path, version
-    
-        # Deal with pipelining
-        bytes = ""
-        while 1:
-            line = self.rfile.readline()
-            bytes = bytes + line
-            if line == '\r\n' or line == '\n' or line == '':
-                break
-    
-        # Examine the headers and look for a Connection directive
-        hfile = cStringIO.StringIO(bytes)
-        self.headers = self.MessageClass(hfile)
-    
-        conntype = self.headers.get('Connection', "")
-        if conntype.lower() == 'close':
-            self.close_connection = 1
-        elif (conntype.lower() == 'keep-alive' and
-              self.protocol_version >= "HTTP/1.1"):
-            self.close_connection = 0
-        return True
-    def handle_one_request(self):
-        """Handle a single HTTP request.
-    
-        You normally don't need to override this method; see the class
-        __doc__ string for information on how to handle specific HTTP
-        commands such as GET and POST.
-    
-        """
-        self.raw_requestline = self.rfile.readline()
-        if not self.raw_requestline:
-            self.close_connection = 1
-            return
-        if not self.parse_request(): # An error code has been sent, just exit
-            return
-        mname = 'do_' + self.command
-        if not hasattr(self, mname):
-            self.send_error(501, "Unsupported method (%s)" % `self.command`)
-            return
-        method = getattr(self, mname)
-        method()
-    def handle(self):
-        """Handle multiple requests if necessary."""
-        self.close_connection = 1
-    
-        self.handle_one_request()
-        while not self.close_connection:
-            self.handle_one_request()
-    def send_error(self, code, message=None):
-        """Send and log an error reply.
-    
-        Arguments are the error code, and a detailed message.
-        The detailed message defaults to the short entry matching the
-        response code.
-    
-        This sends an error response (so it must be called before any
-        output has been generated), logs the error, and finally sends
-        a piece of HTML explaining the error to the user.
-    
-        """
-    
-        try:
-            short, long = self.responses[code]
-        except KeyError:
-            short, long = '???', '???'
-        if message is None:
-            message = short
-        explain = long
-        self.log_error("code %d, message %s", code, message)
-        content = (self.error_message_format %
-                   {'code': code, 'message': message, 'explain': explain})
-        self.send_response(code, message)
-        self.send_header("Content-Type", "text/html")
-        self.send_header('Connection', 'close')
-        self.end_headers()
-        if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
-            self.wfile.write(content)
-    error_message_format = DEFAULT_ERROR_MESSAGE
-    
-    def send_response(self, code, message=None):
-        """Send the response header and log the response code.
-    
-        Also send two standard headers with the server software
-        version and the current date.
-    
-        """
-        self.log_request(code)
-        if message is None:
-            if code in self.responses:
-                message = self.responses[code][0]
-            else:
-                message = ''
-        if self.request_version != 'HTTP/0.9':
-            self.wfile.write("%s %d %s\r\n" %
-                             (self.protocol_version, code, message))
-            # print (self.protocol_version, code, message)
-        self.send_header('Server', self.version_string())
-        self.send_header('Date', self.date_time_string())
-    def send_header(self, keyword, value):
-        """Send a MIME header."""
-        if self.request_version != 'HTTP/0.9':
-            self.wfile.write("%s: %s\r\n" % (keyword, value))
-    
-        if keyword.lower() == 'connection':
-            if value.lower() == 'close':
-                self.close_connection = 1
-            elif value.lower() == 'keep-alive':
-                self.close_connection = 0
-    def end_headers(self):
-        """Send the blank line ending the MIME headers."""
-        if self.request_version != 'HTTP/0.9':
-            self.wfile.write("\r\n")
-    def log_request(self, code='-', size='-'):
-        """Log an accepted request.
-    
-        This is called by send_reponse().
-    
-        """
-    
-        self.log_message('"%s" %s %s',
-                         self.requestline, str(code), str(size))
-    def log_error(self, *args):
-        """Log an error.
-    
-        This is called when a request cannot be fulfilled.  By
-        default it passes the message on to log_message().
-    
-        Arguments are the same as for log_message().
-    
-        XXX This should go to the separate error log.
-    
-        """
-    
-        self.log_message(*args)
-    def log_message(self, format, *args):
-        """Log an arbitrary message.
-    
-        This is used by all other logging functions.  Override
-        it if you have specific logging wishes.
-    
-        The first argument, FORMAT, is a format string for the
-        message to be logged.  If the format string contains
-        any % escapes requiring parameters, they should be
-        specified as subsequent arguments (it's just like
-        printf!).
-    
-        The client host and current date/time are prefixed to
-        every message.
-    
-        """
-    
-        sys.stderr.write("%s - - [%s] %s\n" %
-                         (self.address_string(),
-                          self.log_date_time_string(),
-                          format%args))
-    def version_string(self):
-        """Return the server software version string."""
-        return self.server_version + ' ' + self.sys_version
-    def date_time_string(self):
-        """Return the current date and time formatted for a message header."""
-        now = time.time()
-        year, month, day, hh, mm, ss, wd, y, z = time.gmtime(now)
-        s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
-                self.weekdayname[wd],
-                day, self.monthname[month], year,
-                hh, mm, ss)
-        return s
-    def log_date_time_string(self):
-        """Return the current time formatted for logging."""
-        now = time.time()
-        year, month, day, hh, mm, ss, x, y, z = time.localtime(now)
-        s = "%02d/%3s/%04d %02d:%02d:%02d" % (
-                day, self.monthname[month], year, hh, mm, ss)
-        return s
-    weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
-    
-    monthname = [None,
-                 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
-                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
-    
-    def address_string(self):
-        """Return the client address formatted for logging.
-    
-        This version looks up the full hostname using gethostbyaddr(),
-        and tries to find a name that contains at least one dot.
-    
-        """
-    
-        #host, port = self.client_address[:2]
-        #return socket.getfqdn(host)
-        return self.client_address
-    
-
-    # Essentially static class variables
-
-    # The version of the HTTP protocol we support.
-    # Set this to HTTP/1.1 to enable automatic keepalive
-    protocol_version = "HTTP/1.0"
-
-    # The Message-like class used to parse headers
-    MessageClass = mimetools.Message
-
-    # Table mapping response codes to messages; entries have the
-    # form {code: (shortmessage, longmessage)}.
-    # See http://www.w3.org/hypertext/WWW/Protocols/HTTP/HTRESP.html
-    responses = {
-        100: ('Continue', 'Request received, please continue'),
-        101: ('Switching Protocols',
-              'Switching to new protocol; obey Upgrade header'),
-
-        200: ('OK', 'Request fulfilled, document follows'),
-        201: ('Created', 'Document created, URL follows'),
-        202: ('Accepted',
-              'Request accepted, processing continues off-line'),
-        203: ('Non-Authoritative Information', 'Request fulfilled from cache'),
-        204: ('No response', 'Request fulfilled, nothing follows'),
-        205: ('Reset Content', 'Clear input form for further input.'),
-        206: ('Partial Content', 'Partial content follows.'),
-
-        300: ('Multiple Choices',
-              'Object has several resources -- see URI list'),
-        301: ('Moved Permanently', 'Object moved permanently -- see URI list'),
-        302: ('Found', 'Object moved temporarily -- see URI list'),
-        303: ('See Other', 'Object moved -- see Method and URL list'),
-        304: ('Not modified',
-              'Document has not changed since given time'),
-        305: ('Use Proxy',
-              'You must use proxy specified in Location to access this '
-              'resource.'),
-        307: ('Temporary Redirect',
-              'Object moved temporarily -- see URI list'),
-
-        400: ('Bad request',
-              'Bad request syntax or unsupported method'),
-        401: ('Unauthorized',
-              'No permission -- see authorization schemes'),
-        402: ('Payment required',
-              'No payment -- see charging schemes'),
-        403: ('Forbidden',
-              'Request forbidden -- authorization will not help'),
-        404: ('Not Found', 'Nothing matches the given URI'),
-        405: ('Method Not Allowed',
-              'Specified method is invalid for this server.'),
-        406: ('Not Acceptable', 'URI not available in preferred format.'),
-        407: ('Proxy Authentication Required', 'You must authenticate with '
-              'this proxy before proceeding.'),
-        408: ('Request Time-out', 'Request timed out; try again later.'),
-        409: ('Conflict', 'Request conflict.'),
-        410: ('Gone',
-              'URI no longer exists and has been permanently removed.'),
-        411: ('Length Required', 'Client must specify Content-Length.'),
-        412: ('Precondition Failed', 'Precondition in headers is false.'),
-        413: ('Request Entity Too Large', 'Entity is too large.'),
-        414: ('Request-URI Too Long', 'URI is too long.'),
-        415: ('Unsupported Media Type', 'Entity body in unsupported format.'),
-        416: ('Requested Range Not Satisfiable',
-              'Cannot satisfy request range.'),
-        417: ('Expectation Failed',
-              'Expect condition could not be satisfied.'),
-
-        500: ('Internal error', 'Server got itself in trouble'),
-        501: ('Not Implemented',
-              'Server does not support this operation'),
-        502: ('Bad Gateway', 'Invalid responses from another server/proxy.'),
-        503: ('Service temporarily overloaded',
-              'The server cannot process the request due to a high load'),
-        504: ('Gateway timeout',
-              'The gateway server did not receive a timely response'),
-        505: ('HTTP Version not supported', 'Cannot fulfill request.'),
-        }
-
-def test(HandlerClass = BaseHTTPRequestHandler,
-         ServerClass = HTTPServer, protocol="HTTP/1.0"):
-    """Test the HTTP request handler class.
-
-    This runs an HTTP server on port 8000 (or the first command line
-    argument).
-
-    """
-
-    if sys.argv[1:]:
-        server_address = sys.argv[1]
-    else:
-        server_address = "mytestxxx.i2p"
-
-    HandlerClass.protocol_version = protocol
-    httpd = ServerClass(server_address, HandlerClass)
-
-    print "Serving HTTP on", server_address, "..."
-    print "Destination follows:"
-    print httpd.socket.dest
-    httpd.serve_forever()
-
-if __name__ == '__main__':
-    test()
diff --git a/apps/sam/python/src/i2p/CGIHTTPServer.py b/apps/sam/python/src/i2p/CGIHTTPServer.py
deleted file mode 100644
index 2cb9b173b2..0000000000
--- a/apps/sam/python/src/i2p/CGIHTTPServer.py
+++ /dev/null
@@ -1,316 +0,0 @@
-#! /usr/bin/env python
-"""CGI-savvy HTTP Server.
-
-This module builds on SAMSimpleHTTPServer by implementing GET and POST
-requests to cgi-bin scripts.
-
-If the os.fork() function is not present (e.g. on Windows),
-os.popen2() is used as a fallback, with slightly altered semantics; if
-that function is not present either (e.g. on Macintosh), only Python
-scripts are supported, and they are executed by the current process.
-
-In all cases, the implementation is intentionally naive -- all
-requests are executed sychronously.
-
-SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL
--- it may execute arbitrary Python code or external programs.
-
-"""
-
-
-__version__ = "0.4"
-
-__all__ = ["CGIHTTPRequestHandler"]
-
-import os
-import sys
-import urllib
-from i2p import BaseHTTPServer, SimpleHTTPServer
-import select
-
-# conveniences
-HTTPServer = BaseHTTPServer.HTTPServer
-class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
-
-    """Complete HTTP server with GET, HEAD and POST commands.
-
-    GET and HEAD also support running CGI scripts.
-
-    The POST command is *only* implemented for CGI scripts.
-
-    """
-    # Determine platform specifics
-    have_fork = hasattr(os, 'fork')
-    have_popen2 = hasattr(os, 'popen2')
-    have_popen3 = hasattr(os, 'popen3')
-    
-    # Make rfile unbuffered -- we need to read one line and then pass
-    # the rest to a subprocess, so we can't use buffered input.
-    rbufsize = 0
-    
-    def do_POST(self):
-        """Serve a POST request.
-    
-        This is only implemented for CGI scripts.
-    
-        """
-    
-        if self.is_cgi():
-            self.run_cgi()
-        else:
-            self.send_error(501, "Can only POST to CGI scripts")
-    def send_head(self):
-        """Version of send_head that support CGI scripts"""
-        if self.is_cgi():
-            return self.run_cgi()
-        else:
-            return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
-    def is_cgi(self):
-        """Test whether self.path corresponds to a CGI script.
-    
-        Return a tuple (dir, rest) if self.path requires running a
-        CGI script, None if not.  Note that rest begins with a
-        slash if it is not empty.
-    
-        The default implementation tests whether the path
-        begins with one of the strings in the list
-        self.cgi_directories (and the next character is a '/'
-        or the end of the string).
-    
-        """
-    
-        path = self.path
-    
-        for x in self.cgi_directories:
-            i = len(x)
-            if path[:i] == x and (not path[i:] or path[i] == '/'):
-                self.cgi_info = path[:i], path[i+1:]
-                return True
-        return False
-    cgi_directories = ['/cgi-bin', '/htbin']
-    
-    def is_executable(self, path):
-        """Test whether argument path is an executable file."""
-        return executable(path)
-    def is_python(self, path):
-        """Test whether argument path is a Python script."""
-        head, tail = os.path.splitext(path)
-        return tail.lower() in (".py", ".pyw")
-    def run_cgi(self):
-        """Execute a CGI script."""
-        dir, rest = self.cgi_info
-        i = rest.rfind('?')
-        if i >= 0:
-            rest, query = rest[:i], rest[i+1:]
-        else:
-            query = ''
-        i = rest.find('/')
-        if i >= 0:
-            script, rest = rest[:i], rest[i:]
-        else:
-            script, rest = rest, ''
-        scriptname = dir + '/' + script
-        scriptfile = self.translate_path(scriptname)
-        if not os.path.exists(scriptfile):
-            self.send_error(404, "No such CGI script (%s)" % `scriptname`)
-            return
-        if not os.path.isfile(scriptfile):
-            self.send_error(403, "CGI script is not a plain file (%s)" %
-                            `scriptname`)
-            return
-        ispy = self.is_python(scriptname)
-        if not ispy:
-            if not (self.have_fork or self.have_popen2 or self.have_popen3):
-                self.send_error(403, "CGI script is not a Python script (%s)" %
-                                `scriptname`)
-                return
-            if not self.is_executable(scriptfile):
-                self.send_error(403, "CGI script is not executable (%s)" %
-                                `scriptname`)
-                return
-    
-        # Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
-        # XXX Much of the following could be prepared ahead of time!
-        env = {}
-        env['SERVER_SOFTWARE'] = self.version_string()
-        env['SERVER_NAME'] = self.server.server_name
-        env['GATEWAY_INTERFACE'] = 'CGI/1.1'
-        env['SERVER_PROTOCOL'] = self.protocol_version
-        env['SERVER_PORT'] = str(self.server.server_port)
-        env['REQUEST_METHOD'] = self.command
-        uqrest = urllib.unquote(rest)
-        env['PATH_INFO'] = uqrest
-        env['PATH_TRANSLATED'] = self.translate_path(uqrest)
-        env['SCRIPT_NAME'] = scriptname
-        if query:
-            env['QUERY_STRING'] = query
-        host = self.address_string()
-        if host != self.client_address[0]:
-            env['REMOTE_HOST'] = host
-        env['REMOTE_ADDR'] = self.client_address[0]
-        # XXX AUTH_TYPE
-        # XXX REMOTE_USER
-        # XXX REMOTE_IDENT
-        if self.headers.typeheader is None:
-            env['CONTENT_TYPE'] = self.headers.type
-        else:
-            env['CONTENT_TYPE'] = self.headers.typeheader
-        length = self.headers.getheader('content-length')
-        if length:
-            env['CONTENT_LENGTH'] = length
-        accept = []
-        for line in self.headers.getallmatchingheaders('accept'):
-            if line[:1] in "\t\n\r ":
-                accept.append(line.strip())
-            else:
-                accept = accept + line[7:].split(',')
-        env['HTTP_ACCEPT'] = ','.join(accept)
-        ua = self.headers.getheader('user-agent')
-        if ua:
-            env['HTTP_USER_AGENT'] = ua
-        co = filter(None, self.headers.getheaders('cookie'))
-        if co:
-            env['HTTP_COOKIE'] = ', '.join(co)
-        # XXX Other HTTP_* headers
-        # Since we're setting the env in the parent, provide empty
-        # values to override previously set values
-        for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH',
-                  'HTTP_USER_AGENT', 'HTTP_COOKIE'):
-            env.setdefault(k, "")
-        os.environ.update(env)
-    
-        self.send_response(200, "Script output follows")
-    
-        decoded_query = query.replace('+', ' ')
-    
-        if self.have_fork:
-            # Unix -- fork as we should
-            args = [script]
-            if '=' not in decoded_query:
-                args.append(decoded_query)
-            nobody = nobody_uid()
-            self.wfile.flush() # Always flush before forking
-            pid = os.fork()
-            if pid != 0:
-                # Parent
-                pid, sts = os.waitpid(pid, 0)
-                # throw away additional data [see bug #427345]
-                while select.select([self.rfile], [], [], 0)[0]:
-                    if not self.rfile.read(1):
-                        break
-                if sts:
-                    self.log_error("CGI script exit status %#x", sts)
-                return
-            # Child
-            try:
-                try:
-                    os.setuid(nobody)
-                except os.error:
-                    pass
-                os.dup2(self.rfile.fileno(), 0)
-                os.dup2(self.wfile.fileno(), 1)
-                os.execve(scriptfile, args, os.environ)
-            except:
-                self.server.handle_error(self.request, self.client_address)
-                os._exit(127)
-    
-        elif self.have_popen2 or self.have_popen3:
-            # Windows -- use popen2 or popen3 to create a subprocess
-            import shutil
-            if self.have_popen3:
-                popenx = os.popen3
-            else:
-                popenx = os.popen2
-            cmdline = scriptfile
-            if self.is_python(scriptfile):
-                interp = sys.executable
-                if interp.lower().endswith("w.exe"):
-                    # On Windows, use python.exe, not pythonw.exe
-                    interp = interp[:-5] + interp[-4:]
-                cmdline = "%s -u %s" % (interp, cmdline)
-            if '=' not in query and '"' not in query:
-                cmdline = '%s "%s"' % (cmdline, query)
-            self.log_message("command: %s", cmdline)
-            try:
-                nbytes = int(length)
-            except (TypeError, ValueError):
-                nbytes = 0
-            files = popenx(cmdline, 'b')
-            fi = files[0]
-            fo = files[1]
-            if self.have_popen3:
-                fe = files[2]
-            if self.command.lower() == "post" and nbytes > 0:
-                data = self.rfile.read(nbytes)
-                fi.write(data)
-            # throw away additional data [see bug #427345]
-            while select.select([self.rfile._sock], [], [], 0)[0]:
-                if not self.rfile._sock.recv(1):
-                    break
-            fi.close()
-            shutil.copyfileobj(fo, self.wfile)
-            if self.have_popen3:
-                errors = fe.read()
-                fe.close()
-                if errors:
-                    self.log_error('%s', errors)
-            sts = fo.close()
-            if sts:
-                self.log_error("CGI script exit status %#x", sts)
-            else:
-                self.log_message("CGI script exited OK")
-    
-        else:
-            # Other O.S. -- execute script in this process
-            save_argv = sys.argv
-            save_stdin = sys.stdin
-            save_stdout = sys.stdout
-            save_stderr = sys.stderr
-            try:
-                try:
-                    sys.argv = [scriptfile]
-                    if '=' not in decoded_query:
-                        sys.argv.append(decoded_query)
-                    sys.stdout = self.wfile
-                    sys.stdin = self.rfile
-                    execfile(scriptfile, {"__name__": "__main__"})
-                finally:
-                    sys.argv = save_argv
-                    sys.stdin = save_stdin
-                    sys.stdout = save_stdout
-                    sys.stderr = save_stderr
-            except SystemExit, sts:
-                self.log_error("CGI script exit status %s", str(sts))
-            else:
-                self.log_message("CGI script exited OK")
-nobody = None
-
-def nobody_uid():
-    """Internal routine to get nobody's uid"""
-    global nobody
-    if nobody:
-        return nobody
-    try:
-        import pwd
-    except ImportError:
-        return -1
-    try:
-        nobody = pwd.getpwnam('nobody')[2]
-    except KeyError:
-        nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
-    return nobody
-def executable(path):
-    """Test for executable file."""
-    try:
-        st = os.stat(path)
-    except os.error:
-        return False
-    return st.st_mode & 0111 != 0
-def test(HandlerClass = CGIHTTPRequestHandler,
-         ServerClass = BaseHTTPServer.HTTPServer):
-    SimpleHTTPServer.test(HandlerClass, ServerClass)
-
-
-
-if __name__ == '__main__':
-    test()
diff --git a/apps/sam/python/src/i2p/SimpleHTTPServer.py b/apps/sam/python/src/i2p/SimpleHTTPServer.py
deleted file mode 100644
index 31af1dcdcc..0000000000
--- a/apps/sam/python/src/i2p/SimpleHTTPServer.py
+++ /dev/null
@@ -1,201 +0,0 @@
-#! /usr/bin/env python
-"""Simple HTTP Server.
-
-Hacked by aum from standard python module of the same name,
-modified for compatibility with sunshine's 'i2p.sam.socket'.
-
---
-
-This module builds on SAMBaseHTTPServer by implementing the standard GET
-and HEAD requests in a fairly straightforward manner.
-
-"""
-
-
-__version__ = "0.6"
-
-__all__ = ["SimpleHTTPRequestHandler"]
-
-import os
-import posixpath
-from i2p import BaseHTTPServer
-import urllib
-import cgi
-import shutil
-import mimetypes
-from StringIO import StringIO
-
-# conveniences
-HTTPServer = BaseHTTPServer.HTTPServer
-
-class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
-
-    """Simple HTTP request handler with GET and HEAD commands.
-
-    This serves files from the current directory and any of its
-    subdirectories.  It assumes that all files are plain text files
-    unless they have the extension ".html" in which case it assumes
-    they are HTML files.
-
-    The GET and HEAD requests are identical except that the HEAD
-    request omits the actual contents of the file.
-
-    """
-    server_version = "SimpleHTTP/" + __version__
-    
-    def do_GET(self):
-        """Serve a GET request."""
-        f = self.send_head()
-        if f:
-            self.copyfile(f, self.wfile)
-            f.close()
-    def do_HEAD(self):
-        """Serve a HEAD request."""
-        f = self.send_head()
-        if f:
-            f.close()
-    def send_head(self):
-        """Common code for GET and HEAD commands.
-    
-        This sends the response code and MIME headers.
-    
-        Return value is either a file object (which has to be copied
-        to the outputfile by the caller unless the command was HEAD,
-        and must be closed by the caller under all circumstances), or
-        None, in which case the caller has nothing further to do.
-    
-        """
-        path = self.translate_path(self.path)
-        f = None
-        if os.path.isdir(path):
-            for index in "index.html", "index.htm":
-                index = os.path.join(path, index)
-                if os.path.exists(index):
-                    path = index
-                    break
-            else:
-                return self.list_directory(path)
-        ctype = self.guess_type(path)
-        if ctype.startswith('text/'):
-            mode = 'r'
-        else:
-            mode = 'rb'
-        try:
-            f = open(path, mode)
-        except IOError:
-            self.send_error(404, "File not found")
-            return None
-        self.send_response(200)
-        self.send_header("Content-type", ctype)
-        self.send_header("Content-Length", str(os.fstat(f.fileno())[6]))
-        self.end_headers()
-        return f
-    def list_directory(self, path):
-        """Helper to produce a directory listing (absent index.html).
-    
-        Return value is either a file object, or None (indicating an
-        error).  In either case, the headers are sent, making the
-        interface the same as for send_head().
-    
-        """
-        try:
-            list = os.listdir(path)
-        except os.error:
-            self.send_error(404, "No permission to list directory")
-            return None
-        list.sort(lambda a, b: cmp(a.lower(), b.lower()))
-        f = StringIO()
-        f.write("<title>Directory listing for %s</title>\n" % self.path)
-        f.write("<h2>Directory listing for %s</h2>\n" % self.path)
-        f.write("<hr>\n<ul>\n")
-        for name in list:
-            fullname = os.path.join(path, name)
-            displayname = linkname = name = cgi.escape(name)
-            # Append / for directories or @ for symbolic links
-            if os.path.isdir(fullname):
-                displayname = name + "/"
-                linkname = name + "/"
-            if os.path.islink(fullname):
-                displayname = name + "@"
-                # Note: a link to a directory displays with @ and links with /
-            f.write('<li><a href="%s">%s</a>\n' % (linkname, displayname))
-        f.write("</ul>\n<hr>\n")
-        length = f.tell()
-        f.seek(0)
-        self.send_response(200)
-        self.send_header("Content-type", "text/html")
-        self.send_header("Content-Length", str(length))
-        self.end_headers()
-        return f
-    def translate_path(self, path):
-        """Translate a /-separated PATH to the local filename syntax.
-    
-        Components that mean special things to the local file system
-        (e.g. drive or directory names) are ignored.  (XXX They should
-        probably be diagnosed.)
-    
-        """
-        path = posixpath.normpath(urllib.unquote(path))
-        words = path.split('/')
-        words = filter(None, words)
-        path = os.getcwd()
-        for word in words:
-            drive, word = os.path.splitdrive(word)
-            head, word = os.path.split(word)
-            if word in (os.curdir, os.pardir): continue
-            path = os.path.join(path, word)
-        return path
-    def copyfile(self, source, outputfile):
-        """Copy all data between two file objects.
-    
-        The SOURCE argument is a file object open for reading
-        (or anything with a read() method) and the DESTINATION
-        argument is a file object open for writing (or
-        anything with a write() method).
-    
-        The only reason for overriding this would be to change
-        the block size or perhaps to replace newlines by CRLF
-        -- note however that this the default server uses this
-        to copy binary data as well.
-    
-        """
-        shutil.copyfileobj(source, outputfile)
-    def guess_type(self, path):
-        """Guess the type of a file.
-    
-        Argument is a PATH (a filename).
-    
-        Return value is a string of the form type/subtype,
-        usable for a MIME Content-type header.
-    
-        The default implementation looks the file's extension
-        up in the table self.extensions_map, using text/plain
-        as a default; however it would be permissible (if
-        slow) to look inside the data to make a better guess.
-    
-        """
-    
-        base, ext = posixpath.splitext(path)
-        if ext in self.extensions_map:
-            return self.extensions_map[ext]
-        ext = ext.lower()
-        if ext in self.extensions_map:
-            return self.extensions_map[ext]
-        else:
-            return self.extensions_map['']
-
-    extensions_map = mimetypes.types_map.copy()
-    extensions_map.update({
-        '': 'application/octet-stream', # Default
-        '.py': 'text/plain',
-        '.c': 'text/plain',
-        '.h': 'text/plain',
-        })
-
-def test(HandlerClass = SimpleHTTPRequestHandler,
-         ServerClass = BaseHTTPServer.HTTPServer):
-    BaseHTTPServer.test(HandlerClass, ServerClass)
-
-
-if __name__ == '__main__':
-    test()
diff --git a/apps/sam/python/src/i2p/SocketServer.py b/apps/sam/python/src/i2p/SocketServer.py
deleted file mode 100644
index 9b19e7eddb..0000000000
--- a/apps/sam/python/src/i2p/SocketServer.py
+++ /dev/null
@@ -1,542 +0,0 @@
-
-"""Generic I2P SAM socket server classes.
-
-This is taken almost verbatim from the official python SocketServer.py
-module, but has been hacked by aum to work with I2P SAM sockets
-(refer I2P - www.i2p.net - CVS: /i2p/apps/sam/python/src)
-
---
-
-Original module docstring...
-
-This module tries to capture the various aspects of defining a server:
-
-For socket-based servers:
-
-- address family:
-        - AF_INET{,6}: IP (Internet Protocol) sockets (default)
-        - AF_UNIX: Unix domain sockets
-        - others, e.g. AF_DECNET are conceivable (see <socket.h>
-- socket type:
-        - SOCK_STREAM (reliable stream, e.g. TCP)
-        - SOCK_DGRAM (datagrams, e.g. UDP)
-
-For request-based servers (including socket-based):
-
-- client address verification before further looking at the request
-        (This is actually a hook for any processing that needs to look
-         at the request before anything else, e.g. logging)
-- how to handle multiple requests:
-        - synchronous (one request is handled at a time)
-        - forking (each request is handled by a new process)
-        - threading (each request is handled by a new thread)
-
-The classes in this module favor the server type that is simplest to
-write: a synchronous TCP/IP server.  This is bad class design, but
-save some typing.  (There's also the issue that a deep class hierarchy
-slows down method lookups.)
-
-There are five classes in an inheritance diagram, four of which represent
-synchronous servers of four types:
-
-        +------------+
-        | BaseServer |
-        +------------+
-              |
-              v
-        +-----------+        +------------------+
-        | TCPServer |------->| UnixStreamServer |
-        +-----------+        +------------------+
-              |
-              v
-        +-----------+        +--------------------+
-        | UDPServer |------->| UnixDatagramServer |
-        +-----------+        +--------------------+
-
-Note that UnixDatagramServer derives from UDPServer, not from
-UnixStreamServer -- the only difference between an IP and a Unix
-stream server is the address family, which is simply repeated in both
-unix server classes.
-
-Forking and threading versions of each type of server can be created
-using the ForkingServer and ThreadingServer mix-in classes.  For
-instance, a threading UDP server class is created as follows:
-
-        class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
-
-The Mix-in class must come first, since it overrides a method defined
-in UDPServer! Setting the various member variables also changes
-the behavior of the underlying server mechanism.
-
-To implement a service, you must derive a class from
-BaseRequestHandler and redefine its handle() method.  You can then run
-various versions of the service by combining one of the server classes
-with your request handler class.
-
-The request handler class must be different for datagram or stream
-services.  This can be hidden by using the mix-in request handler
-classes StreamRequestHandler or DatagramRequestHandler.
-
-Of course, you still have to use your head!
-
-For instance, it makes no sense to use a forking server if the service
-contains state in memory that can be modified by requests (since the
-modifications in the child process would never reach the initial state
-kept in the parent process and passed to each child).  In this case,
-you can use a threading server, but you will probably have to use
-locks to avoid two requests that come in nearly simultaneous to apply
-conflicting changes to the server state.
-
-On the other hand, if you are building e.g. an HTTP server, where all
-data is stored externally (e.g. in the file system), a synchronous
-class will essentially render the service "deaf" while one request is
-being handled -- which may be for a very long time if a client is slow
-to reqd all the data it has requested.  Here a threading or forking
-server is appropriate.
-
-In some cases, it may be appropriate to process part of a request
-synchronously, but to finish processing in a forked child depending on
-the request data.  This can be implemented by using a synchronous
-server and doing an explicit fork in the request handler class
-handle() method.
-
-Another approach to handling multiple simultaneous requests in an
-environment that supports neither threads nor fork (or where these are
-too expensive or inappropriate for the service) is to maintain an
-explicit table of partially finished requests and to use select() to
-decide which request to work on next (or whether to handle a new
-incoming request).  This is particularly important for stream services
-where each client can potentially be connected for a long time (if
-threads or subprocesses cannot be used).
-
-Future work:
-- Standard classes for Sun RPC (which uses either UDP or TCP)
-- Standard mix-in classes to implement various authentication
-  and encryption schemes
-- Standard framework for select-based multiplexing
-
-XXX Open problems:
-- What to do with out-of-band data?
-
-BaseServer:
-- split generic "request" functionality out into BaseServer class.
-  Copyright (C) 2000  Luke Kenneth Casson Leighton <lkcl@samba.org>
-
-  example: read entries from a SQL database (requires overriding
-  get_request() to return a table entry from the database).
-  entry is processed by a RequestHandlerClass.
-
-"""
-
-# replace official python socket module with sunshine's I2P sam module
-#import socket
-import i2p
-from i2p import sam as socket
-
-
-import sys
-import os
-
-__version__ = "0.1"
-
-
-__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
-           "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
-           "StreamRequestHandler","DatagramRequestHandler",
-           "ThreadingMixIn", "ForkingMixIn"]
-class BaseServer:
-
-    """Base class for server classes.
-
-    Methods for the caller:
-
-    - __init__(server_address, RequestHandlerClass)
-    - serve_forever()
-    - handle_request()  # if you do not use serve_forever()
-    - fileno() -> int   # for select()
-
-    Methods that may be overridden:
-
-    - server_bind()
-    - server_activate()
-    - get_request() -> request, client_address
-    - verify_request(request, client_address)
-    - server_close()
-    - process_request(request, client_address)
-    - close_request(request)
-    - handle_error()
-
-    Methods for derived classes:
-
-    - finish_request(request, client_address)
-
-    Class variables that may be overridden by derived classes or
-    instances:
-
-    - address_family
-    - socket_type
-    - allow_reuse_address
-
-    Instance variables:
-
-    - RequestHandlerClass
-    - socket
-
-    """
-    def __init__(self, server_address, RequestHandlerClass):
-        """Constructor.  May be extended, do not override."""
-        self.server_address = server_address
-        self.RequestHandlerClass = RequestHandlerClass
-    def server_activate(self):
-        """Called by constructor to activate the server.
-    
-        May be overridden.
-    
-        """
-        pass
-    def serve_forever(self):
-        """Handle one request at a time until doomsday."""
-        while 1:
-            self.handle_request()
-    # The distinction between handling, getting, processing and
-    # finishing a request is fairly arbitrary.  Remember:
-    #
-    # - handle_request() is the top-level call.  It calls
-    #   get_request(), verify_request() and process_request()
-    # - get_request() is different for stream or datagram sockets
-    # - process_request() is the place that may fork a new process
-    #   or create a new thread to finish the request
-    # - finish_request() instantiates the request handler class;
-    #   this constructor will handle the request all by itself
-    
-    def handle_request(self):
-        """Handle one request, possibly blocking."""
-        try:
-            request, client_address = self.get_request()
-        except socket.error:
-            return
-        if self.verify_request(request, client_address):
-            try:
-                self.process_request(request, client_address)
-            except:
-                self.handle_error(request, client_address)
-                self.close_request(request)
-    def verify_request(self, request, client_address):
-        """Verify the request.  May be overridden.
-    
-        Return True if we should proceed with this request.
-    
-        """
-        return True
-    def process_request(self, request, client_address):
-        """Call finish_request.
-    
-        Overridden by ForkingMixIn and ThreadingMixIn.
-    
-        """
-        self.finish_request(request, client_address)
-        self.close_request(request)
-    def server_close(self):
-        """Called to clean-up the server.
-    
-        May be overridden.
-    
-        """
-        pass
-    def finish_request(self, request, client_address):
-        """Finish one request by instantiating RequestHandlerClass."""
-        self.RequestHandlerClass(request, client_address, self)
-    def close_request(self, request):
-        """Called to clean up an individual request."""
-        pass
-    def handle_error(self, request, client_address):
-        """Handle an error gracefully.  May be overridden.
-    
-        The default is to print a traceback and continue.
-    
-        """
-        print '-'*40
-        print 'Exception happened during processing of request from',
-        print client_address
-        import traceback
-        traceback.print_exc() # XXX But this goes to stderr!
-        print '-'*40
-    
-class TCPServer(BaseServer):
-
-    """Base class for various socket-based server classes.
-
-    Defaults to synchronous IP stream (i.e., TCP).
-
-    Methods for the caller:
-
-    - __init__(server_address, RequestHandlerClass)
-    - serve_forever()
-    - handle_request()  # if you don't use serve_forever()
-    - fileno() -> int   # for select()
-
-    Methods that may be overridden:
-
-    - server_bind()
-    - server_activate()
-    - get_request() -> request, client_address
-    - verify_request(request, client_address)
-    - process_request(request, client_address)
-    - close_request(request)
-    - handle_error()
-
-    Methods for derived classes:
-
-    - finish_request(request, client_address)
-
-    Class variables that may be overridden by derived classes or
-    instances:
-
-    - address_family
-    - socket_type
-    - request_queue_size (only for stream sockets)
-    - allow_reuse_address
-
-    Instance variables:
-
-    - server_address
-    - RequestHandlerClass
-    - socket
-
-    """
-    socket_type = socket.SOCK_STREAM
-    
-    request_queue_size = 5
-    
-    allow_reuse_address = False
-    
-    def __init__(self, server_address, RequestHandlerClass):
-        """Constructor.  May be extended, do not override."""
-        BaseServer.__init__(self, server_address, RequestHandlerClass)
-    
-        #self.socket = socket.socket(self.address_family,
-        #                            self.socket_type)
-        self.server_address = server_address
-        self.socket = socket.socket(server_address,
-                                    self.socket_type)
-    
-        self.server_bind()
-        self.server_activate()
-    def server_bind(self):
-        """Called by constructor to bind the socket.
-    
-        May be overridden.
-    
-        """
-        #if self.allow_reuse_address:
-        #    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        self.socket.bind(self.server_address)
-    def server_activate(self):
-        """Called by constructor to activate the server.
-    
-        May be overridden.
-    
-        """
-        self.socket.listen(self.request_queue_size)
-    def server_close(self):
-        """Called to clean-up the server.
-    
-        May be overridden.
-    
-        """
-        self.socket.close()
-    def fileno(self):
-        """Return socket file number.
-    
-        Interface required by select().
-    
-        """
-        return self.socket.fileno()
-    def get_request(self):
-        """Get the request and client address from the socket.
-    
-        May be overridden.
-    
-        """
-        return self.socket.accept()
-    def close_request(self, request):
-        """Called to clean up an individual request."""
-        request.close()
-
-
-class UDPServer(TCPServer):
-
-    """UDP server class."""
-    allow_reuse_address = False
-    
-    socket_type = socket.SOCK_DGRAM
-    
-    max_packet_size = 8192
-    
-    def get_request(self):
-        data, client_addr = self.socket.recvfrom(self.max_packet_size)
-        return (data, self.socket), client_addr
-    def server_activate(self):
-        # No need to call listen() for UDP.
-        pass
-    def close_request(self, request):
-        # No need to close anything.
-        pass
-
-class ForkingMixIn:
-
-    """Mix-in class to handle each request in a new process."""
-    active_children = None
-    max_children = 40
-    
-    def collect_children(self):
-        """Internal routine to wait for died children."""
-        while self.active_children:
-            if len(self.active_children) < self.max_children:
-                options = os.WNOHANG
-            else:
-                # If the maximum number of children are already
-                # running, block while waiting for a child to exit
-                options = 0
-            try:
-                pid, status = os.waitpid(0, options)
-            except os.error:
-                pid = None
-            if not pid: break
-            self.active_children.remove(pid)
-    def process_request(self, request, client_address):
-        """Fork a new subprocess to process the request."""
-        self.collect_children()
-        pid = os.fork()
-        if pid:
-            # Parent process
-            if self.active_children is None:
-                self.active_children = []
-            self.active_children.append(pid)
-            self.close_request(request)
-            return
-        else:
-            # Child process.
-            # This must never return, hence os._exit()!
-            try:
-                self.finish_request(request, client_address)
-                os._exit(0)
-            except:
-                try:
-                    self.handle_error(request, client_address)
-                finally:
-                    os._exit(1)
-    
-class ThreadingMixIn:
-    """Mix-in class to handle each request in a new thread."""
-    # Decides how threads will act upon termination of the
-    # main process
-    daemon_threads = False
-    
-    def process_request_thread(self, request, client_address):
-        """Same as in BaseServer but as a thread.
-    
-        In addition, exception handling is done here.
-        """
-        try:
-            self.finish_request(request, client_address)
-            self.close_request(request)
-        except:
-            self.handle_error(request, client_address)
-            self.close_request(request)
-    def process_request(self, request, client_address):
-        """Start a new thread to process the request."""
-        import threading
-        t = threading.Thread(target = self.process_request_thread,
-                             args = (request, client_address))
-        if self.daemon_threads:
-            t.setDaemon (1)
-        t.start()
-class ForkingUDPServer(ForkingMixIn, UDPServer): pass
-
-class ForkingTCPServer(ForkingMixIn, TCPServer): pass
-
-class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
-
-class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
-
-class BaseRequestHandler:
-
-    """Base class for request handler classes.
-
-    This class is instantiated for each request to be handled.  The
-    constructor sets the instance variables request, client_address
-    and server, and then calls the handle() method.  To implement a
-    specific service, all you need to do is to derive a class which
-    defines a handle() method.
-
-    The handle() method can find the request as self.request, the
-    client address as self.client_address, and the server (in case it
-    needs access to per-server information) as self.server.  Since a
-    separate instance is created for each request, the handle() method
-    can define arbitrary other instance variariables.
-
-    """
-    def __init__(self, request, client_address, server):
-        self.request = request
-        self.client_address = client_address
-        self.server = server
-        try:
-            self.setup()
-            self.handle()
-            self.finish()
-        finally:
-            sys.exc_traceback = None    # Help garbage collection
-    def setup(self):
-        pass
-    
-    def handle(self):
-        pass
-    
-    def finish(self):
-        pass
-    
-
-# The following two classes make it possible to use the same service
-# class for stream or datagram servers.
-# Each class sets up these instance variables:
-# - rfile: a file object from which receives the request is read
-# - wfile: a file object to which the reply is written
-# When the handle() method returns, wfile is flushed properly
-
-class StreamRequestHandler(BaseRequestHandler):
-    """Define self.rfile and self.wfile for stream sockets."""
-    # Default buffer sizes for rfile, wfile.
-    # We default rfile to buffered because otherwise it could be
-    # really slow for large data (a getc() call per byte); we make
-    # wfile unbuffered because (a) often after a write() we want to
-    # read and we need to flush the line; (b) big writes to unbuffered
-    # files are typically optimized by stdio even when big reads
-    # aren't.
-    rbufsize = -1
-    wbufsize = 0
-    
-    def setup(self):
-        self.connection = self.request
-        self.rfile = self.connection.makefile('rb', self.rbufsize)
-        self.wfile = self.connection.makefile('wb', self.wbufsize)
-    def finish(self):
-        if not self.wfile.closed:
-            self.wfile.flush()
-        self.wfile.close()
-        self.rfile.close()
-
-
-class DatagramRequestHandler(BaseRequestHandler):
-    # XXX Regrettably, I cannot get this working on Linux;
-    # s.recvfrom() doesn't return a meaningful client address.
-    
-    """Define self.rfile and self.wfile for datagram sockets."""
-    
-    def setup(self):
-        import StringIO
-        self.packet, self.socket = self.request
-        self.rfile = StringIO.StringIO(self.packet)
-        self.wfile = StringIO.StringIO()
-    def finish(self):
-        self.socket.sendto(self.wfile.getvalue(), self.client_address)
diff --git a/apps/sam/python/src/i2p/__init__.py b/apps/sam/python/src/i2p/__init__.py
index 1fc2f5f65b..7d043ee70e 100644
--- a/apps/sam/python/src/i2p/__init__.py
+++ b/apps/sam/python/src/i2p/__init__.py
@@ -3,7 +3,8 @@ i2p -- I2P Python interface
 """
 
 __all__ = ['Error', 'RouterError', 'sam', 'eep', 'router',
-    'SocketServer', 'BaseHTTPServer', 'SimpleHTTPServer', 'CGIHTTPServer',
+    'I2PSocketServer', 'I2PBaseHTTPServer',
+    'I2PSimpleHTTPServer', 'I2PCGIHTTPServer',
     ]
 
 class Error(Exception):
-- 
GitLab