Create http package. #2883.
diff --git a/Lib/BaseHTTPServer.py b/Lib/BaseHTTPServer.py
deleted file mode 100644
index 7fbbcf2..0000000
--- a/Lib/BaseHTTPServer.py
+++ /dev/null
@@ -1,601 +0,0 @@
-"""HTTP server base class.
-
-Note: the class in this module doesn't implement any HTTP request; see
-SimpleHTTPServer 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!)
-
-__version__ = "0.3"
-
-__all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
-
-import io
-import sys
-import time
-import socket # For gethostbyaddr()
-import mimetools
-import socketserver
-
-# Default error message template
-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>
-"""
-
-DEFAULT_ERROR_CONTENT_TYPE = "text/html;charset=utf-8"
-
-def _quote_html(html):
-    return html.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
-
-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)
-        host, port = self.socket.getsockname()[:2]
-        self.server_name = socket.getfqdn(host)
-        self.server_port = port
-
-
-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__
-
-    error_message_format = DEFAULT_ERROR_MESSAGE
-    error_content_type = DEFAULT_ERROR_CONTENT_TYPE
-
-    # The default request version.  This only affects responses up until
-    # the point where the request line is parsed, so it mainly decides what
-    # the client gets back when sending a malformed request line.
-    # Most web servers default to HTTP 0.9, i.e. don't send a status line.
-    default_request_version = "HTTP/0.9"
-
-    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 = self.default_request_version
-        self.close_connection = 1
-        requestline = str(self.raw_requestline, 'iso-8859-1')
-        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 (%r)" % 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 (%r)" % 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 (%r)" % command)
-                return False
-        elif not words:
-            return False
-        else:
-            self.send_error(400, "Bad request syntax (%r)" % requestline)
-            return False
-        self.command, self.path, self.request_version = command, path, version
-
-        # Examine the headers and look for a Connection directive.
-
-        # MessageClass (rfc822) wants to see strings rather than bytes.
-        # But a TextIOWrapper around self.rfile would buffer too many bytes
-        # from the stream, bytes which we later need to read as bytes.
-        # So we read the correct bytes here, as bytes, then use StringIO
-        # to make them look like strings for MessageClass to parse.
-        headers = []
-        while True:
-            line = self.rfile.readline()
-            headers.append(line)
-            if line in (b'\r\n', b'\n', b''):
-                break
-        hfile = io.StringIO(b''.join(headers).decode('iso-8859-1'))
-        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 (%r)" % 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:
-            shortmsg, longmsg = self.responses[code]
-        except KeyError:
-            shortmsg, longmsg = '???', '???'
-        if message is None:
-            message = shortmsg
-        explain = longmsg
-        self.log_error("code %d, message %s", code, message)
-        # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201)
-        content = (self.error_message_format %
-                   {'code': code, 'message': _quote_html(message), 'explain': explain})
-        self.send_response(code, message)
-        self.send_header("Content-Type", self.error_content_type)
-        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.encode('UTF-8', 'replace'))
-
-    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)).encode('ASCII', 'strict'))
-            # 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)).encode('ASCII', 'strict'))
-
-        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(b"\r\n")
-
-    def log_request(self, code='-', size='-'):
-        """Log an accepted request.
-
-        This is called by send_response().
-
-        """
-
-        self.log_message('"%s" %s %s',
-                         self.requestline, str(code), str(size))
-
-    def log_error(self, format, *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(format, *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, timestamp=None):
-        """Return the current date and time formatted for a message header."""
-        if timestamp is None:
-            timestamp = time.time()
-        year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
-        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)
-
-    # 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 RFC 2616.
-    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 Content', '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 Timeout', '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 Server 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 Unavailable',
-              '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:]:
-        port = int(sys.argv[1])
-    else:
-        port = 8000
-    server_address = ('', port)
-
-    HandlerClass.protocol_version = protocol
-    httpd = ServerClass(server_address, HandlerClass)
-
-    sa = httpd.socket.getsockname()
-    print("Serving HTTP on", sa[0], "port", sa[1], "...")
-    httpd.serve_forever()
-
-
-if __name__ == '__main__':
-    test()
diff --git a/Lib/CGIHTTPServer.py b/Lib/CGIHTTPServer.py
deleted file mode 100644
index 29d701a..0000000
--- a/Lib/CGIHTTPServer.py
+++ /dev/null
@@ -1,367 +0,0 @@
-"""CGI-savvy HTTP Server.
-
-This module builds on SimpleHTTPServer 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.
-
-Note that status code 200 is sent prior to execution of a CGI script, so
-scripts cannot send other status codes such as 302 (redirect).
-"""
-
-
-__version__ = "0.4"
-
-__all__ = ["CGIHTTPRequestHandler"]
-
-import os
-import sys
-import urllib
-import BaseHTTPServer
-import SimpleHTTPServer
-import select
-
-
-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."""
-        path = self.path
-        dir, rest = self.cgi_info
-
-        i = path.find('/', len(dir) + 1)
-        while i >= 0:
-            nextdir = path[:i]
-            nextrest = path[i+1:]
-
-            scriptdir = self.translate_path(nextdir)
-            if os.path.isdir(scriptdir):
-                dir, rest = nextdir, nextrest
-                i = path.find('/', len(dir) + 1)
-            else:
-                break
-
-        # find an explicit query string, if present.
-        i = rest.rfind('?')
-        if i >= 0:
-            rest, query = rest[:i], rest[i+1:]
-        else:
-            query = ''
-
-        # dissect the part after the directory name into a script name &
-        # a possible additional path, to be stored in PATH_INFO.
-        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 (%r)" % scriptname)
-            return
-        if not os.path.isfile(scriptfile):
-            self.send_error(403, "CGI script is not a plain file (%r)" %
-                            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 (%r)" %
-                                scriptname)
-                return
-            if not self.is_executable(scriptfile):
-                self.send_error(403, "CGI script is not executable (%r)" %
-                                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]
-        authorization = self.headers.getheader("authorization")
-        if authorization:
-            authorization = authorization.split()
-            if len(authorization) == 2:
-                import base64, binascii
-                env['AUTH_TYPE'] = authorization[0]
-                if authorization[0].lower() == "basic":
-                    try:
-                        authorization = authorization[1].encode('ascii')
-                        authorization = base64.decodestring(authorization).\
-                                        decode('ascii')
-                    except (binascii.Error, UnicodeError):
-                        pass
-                    else:
-                        authorization = authorization.split(':')
-                        if len(authorization) == 2:
-                            env['REMOTE_USER'] = authorization[0]
-        # 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
-        referer = self.headers.getheader('referer')
-        if referer:
-            env['HTTP_REFERER'] = referer
-        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', 'HTTP_REFERER'):
-            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:
-                save_cwd = os.getcwd()
-                try:
-                    sys.argv = [scriptfile]
-                    if '=' not in decoded_query:
-                        sys.argv.append(decoded_query)
-                    sys.stdout = self.wfile
-                    sys.stdin = self.rfile
-                    exec(open(scriptfile).read(), {"__name__": "__main__"})
-                finally:
-                    sys.argv = save_argv
-                    sys.stdin = save_stdin
-                    sys.stdout = save_stdout
-                    sys.stderr = save_stderr
-                    os.chdir(save_cwd)
-            except SystemExit as 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 & 0o111 != 0
-
-
-def test(HandlerClass = CGIHTTPRequestHandler,
-         ServerClass = BaseHTTPServer.HTTPServer):
-    SimpleHTTPServer.test(HandlerClass, ServerClass)
-
-
-if __name__ == '__main__':
-    test()
diff --git a/Lib/SimpleHTTPServer.py b/Lib/SimpleHTTPServer.py
deleted file mode 100644
index 36a249c..0000000
--- a/Lib/SimpleHTTPServer.py
+++ /dev/null
@@ -1,216 +0,0 @@
-"""Simple HTTP Server.
-
-This module builds on BaseHTTPServer by implementing the standard GET
-and HEAD requests in a fairly straightforward manner.
-
-"""
-
-
-__version__ = "0.6"
-
-__all__ = ["SimpleHTTPRequestHandler"]
-
-import os
-import sys
-import posixpath
-import BaseHTTPServer
-import urllib
-import cgi
-import shutil
-import mimetypes
-from io import BytesIO
-
-
-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.  The MIME type for files is determined by
-    calling the .guess_type() method.
-
-    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):
-            if not self.path.endswith('/'):
-                # redirect browser - doing basically what apache does
-                self.send_response(301)
-                self.send_header("Location", self.path + "/")
-                self.end_headers()
-                return None
-            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)
-        try:
-            f = open(path, 'rb')
-        except IOError:
-            self.send_error(404, "File not found")
-            return None
-        self.send_response(200)
-        self.send_header("Content-type", ctype)
-        fs = os.fstat(f.fileno())
-        self.send_header("Content-Length", str(fs[6]))
-        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
-        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(key=lambda a: a.lower())
-        r = []
-        displaypath = cgi.escape(urllib.unquote(self.path))
-        r.append('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
-        r.append("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
-        r.append("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
-        r.append("<hr>\n<ul>\n")
-        for name in list:
-            fullname = os.path.join(path, name)
-            displayname = linkname = 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 /
-            r.append('<li><a href="%s">%s</a>\n'
-                    % (urllib.quote(linkname), cgi.escape(displayname)))
-        r.append("</ul>\n<hr>\n</body>\n</html>\n")
-        enc = sys.getfilesystemencoding()
-        encoded = ''.join(r).encode(enc)
-        f = BytesIO()
-        f.write(encoded)
-        f.seek(0)
-        self.send_response(200)
-        self.send_header("Content-type", "text/html; charset=%s" % enc)
-        self.send_header("Content-Length", str(len(encoded)))
-        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.)
-
-        """
-        # abandon query parameters
-        path = path.split('?',1)[0]
-        path = path.split('#',1)[0]
-        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 application/octet-stream
-        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['']
-
-    if not mimetypes.inited:
-        mimetypes.init() # try to read system mime.types
-    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/Lib/_LWPCookieJar.py b/Lib/_LWPCookieJar.py
index 6720958..641744b 100644
--- a/Lib/_LWPCookieJar.py
+++ b/Lib/_LWPCookieJar.py
@@ -12,10 +12,10 @@
 """
 
 import time, re
-from cookielib import (_warn_unhandled_exception, FileCookieJar, LoadError,
-                       Cookie, MISSING_FILENAME_TEXT,
-                       join_header_words, split_header_words,
-                       iso2time, time2isoz)
+from http.cookiejar import (_warn_unhandled_exception, FileCookieJar, LoadError,
+                            Cookie, MISSING_FILENAME_TEXT,
+                            join_header_words, split_header_words,
+                            iso2time, time2isoz)
 
 def lwp_cookie_str(cookie):
     """Return string representation of Cookie in an the LWP cookie file format.
diff --git a/Lib/_MozillaCookieJar.py b/Lib/_MozillaCookieJar.py
index 4fd6de3..a376ce0 100644
--- a/Lib/_MozillaCookieJar.py
+++ b/Lib/_MozillaCookieJar.py
@@ -2,8 +2,8 @@
 
 import re, time
 
-from cookielib import (_warn_unhandled_exception, FileCookieJar, LoadError,
-                       Cookie, MISSING_FILENAME_TEXT)
+from http.cookiejar import (_warn_unhandled_exception, FileCookieJar, LoadError,
+                            Cookie, MISSING_FILENAME_TEXT)
 
 class MozillaCookieJar(FileCookieJar):
     """
@@ -73,7 +73,7 @@
                 domain_specified = (domain_specified == "TRUE")
                 if name == "":
                     # cookies.txt regards 'Set-Cookie: foo' as a cookie
-                    # with no name, whereas cookielib regards it as a
+                    # with no name, whereas http.cookiejar regards it as a
                     # cookie with no value.
                     name = value
                     value = None
@@ -134,7 +134,7 @@
                     expires = ""
                 if cookie.value is None:
                     # cookies.txt regards 'Set-Cookie: foo' as a cookie
-                    # with no name, whereas cookielib regards it as a
+                    # with no name, whereas http.cookiejar regards it as a
                     # cookie with no value.
                     name = ""
                     value = cookie.name
diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py
index 603336c..2cad2c7 100644
--- a/Lib/distutils/command/upload.py
+++ b/Lib/distutils/command/upload.py
@@ -11,7 +11,7 @@
 import socket
 import platform
 import configparser
-import httplib
+import http.client
 import base64
 import urlparse
 
@@ -151,9 +151,9 @@
             urlparse.urlparse(self.repository)
         assert not params and not query and not fragments
         if schema == 'http':
-            http = httplib.HTTPConnection(netloc)
+            http = http.client.HTTPConnection(netloc)
         elif schema == 'https':
-            http = httplib.HTTPSConnection(netloc)
+            http = http.client.HTTPSConnection(netloc)
         else:
             raise AssertionError("unsupported schema "+schema)
 
diff --git a/Lib/http/__init__.py b/Lib/http/__init__.py
new file mode 100644
index 0000000..196d378
--- /dev/null
+++ b/Lib/http/__init__.py
@@ -0,0 +1 @@
+# This directory is a Python package.
diff --git a/Lib/httplib.py b/Lib/http/client.py
similarity index 100%
rename from Lib/httplib.py
rename to Lib/http/client.py
diff --git a/Lib/cookielib.py b/Lib/http/cookiejar.py
similarity index 98%
rename from Lib/cookielib.py
rename to Lib/http/cookiejar.py
index 6c59390..795953b 100644
--- a/Lib/cookielib.py
+++ b/Lib/http/cookiejar.py
@@ -33,7 +33,7 @@
     import threading as _threading
 except ImportError:
     import dummy_threading as _threading
-import httplib  # only for the default HTTP port
+import http.client  # only for the default HTTP port
 from calendar import timegm
 
 debug = False   # set to True to enable debugging via the logging module
@@ -45,11 +45,11 @@
     global logger
     if not logger:
         import logging
-        logger = logging.getLogger("cookielib")
+        logger = logging.getLogger("http.cookiejar")
     return logger.debug(*args)
 
 
-DEFAULT_HTTP_PORT = str(httplib.HTTP_PORT)
+DEFAULT_HTTP_PORT = str(http.client.HTTP_PORT)
 MISSING_FILENAME_TEXT = ("a filename was not supplied (nor was the CookieJar "
                          "instance initialised with one)")
 
@@ -61,7 +61,7 @@
     f = io.StringIO()
     traceback.print_exc(None, f)
     msg = f.getvalue()
-    warnings.warn("cookielib bug!\n%s" % msg, stacklevel=2)
+    warnings.warn("http.cookiejar bug!\n%s" % msg, stacklevel=2)
 
 
 # Date/time conversion
diff --git a/Lib/Cookie.py b/Lib/http/cookies.py
similarity index 96%
rename from Lib/Cookie.py
rename to Lib/http/cookies.py
index 83f30d5..5078d33 100644
--- a/Lib/Cookie.py
+++ b/Lib/http/cookies.py
@@ -48,25 +48,25 @@
 
 Importing is easy..
 
-   >>> import Cookie
+   >>> from http import cookies
 
 Most of the time you start by creating a cookie.  Cookies come in
 three flavors, each with slightly different encoding semantics, but
 more on that later.
 
-   >>> C = Cookie.SimpleCookie()
-   >>> C = Cookie.SerialCookie()
-   >>> C = Cookie.SmartCookie()
+   >>> C = cookies.SimpleCookie()
+   >>> C = cookies.SerialCookie()
+   >>> C = cookies.SmartCookie()
 
-[Note: Long-time users of Cookie.py will remember using
-Cookie.Cookie() to create an Cookie object.  Although deprecated, it
+[Note: Long-time users of cookies.py will remember using
+cookies.Cookie() to create an Cookie object.  Although deprecated, it
 is still supported by the code.  See the Backward Compatibility notes
 for more information.]
 
 Once you've created your Cookie, you can add values just as if it were
 a dictionary.
 
-   >>> C = Cookie.SmartCookie()
+   >>> C = cookies.SmartCookie()
    >>> C["fig"] = "newton"
    >>> C["sugar"] = "wafer"
    >>> C.output()
@@ -77,7 +77,7 @@
 default behavior.  You can change the header and printed
 attributes by using the .output() function
 
-   >>> C = Cookie.SmartCookie()
+   >>> C = cookies.SmartCookie()
    >>> C["rocky"] = "road"
    >>> C["rocky"]["path"] = "/cookie"
    >>> print(C.output(header="Cookie:"))
@@ -89,7 +89,7 @@
 CGI script, you would use this method to extract the cookies from the
 HTTP_COOKIE environment variable.
 
-   >>> C = Cookie.SmartCookie()
+   >>> C = cookies.SmartCookie()
    >>> C.load("chips=ahoy; vienna=finger")
    >>> C.output()
    'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
@@ -98,7 +98,7 @@
 within a string.  Escaped quotation marks, nested semicolons, and other
 such trickeries do not confuse it.
 
-   >>> C = Cookie.SmartCookie()
+   >>> C = cookies.SmartCookie()
    >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
    >>> print(C)
    Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
@@ -107,7 +107,7 @@
 Cookie attributes.  Here's an example which sets the Path
 attribute.
 
-   >>> C = Cookie.SmartCookie()
+   >>> C = cookies.SmartCookie()
    >>> C["oreo"] = "doublestuff"
    >>> C["oreo"]["path"] = "/"
    >>> print(C)
@@ -116,7 +116,7 @@
 Each dictionary element has a 'value' attribute, which gives you
 back the value associated with the key.
 
-   >>> C = Cookie.SmartCookie()
+   >>> C = cookies.SmartCookie()
    >>> C["twix"] = "none for you"
    >>> C["twix"].value
    'none for you'
@@ -135,7 +135,7 @@
 Just to be sure, SimpleCookie invokes the str() builtin to convert
 the value to a string, when the values are set dictionary-style.
 
-   >>> C = Cookie.SimpleCookie()
+   >>> C = cookies.SimpleCookie()
    >>> C["number"] = 7
    >>> C["string"] = "seven"
    >>> C["number"].value
@@ -154,7 +154,7 @@
 cookie has been returned.  (SerialCookie can yield some
 strange-looking cookie values, however.)
 
-   >>> C = Cookie.SerialCookie()
+   >>> C = cookies.SerialCookie()
    >>> C["number"] = 7
    >>> C["string"] = "seven"
    >>> C["number"].value
@@ -178,7 +178,7 @@
 the value.  If it fails, then it fallsback to treating the value
 as a string.
 
-   >>> C = Cookie.SmartCookie()
+   >>> C = cookies.SmartCookie()
    >>> C["number"] = 7
    >>> C["string"] = "seven"
    >>> C["number"].value
@@ -193,10 +193,10 @@
 -----------------------
 
 In order to keep compatibilty with earlier versions of Cookie.py,
-it is still possible to use Cookie.Cookie() to create a Cookie.  In
+it is still possible to use cookies.Cookie() to create a Cookie.  In
 fact, this simply returns a SmartCookie.
 
-   >>> C = Cookie.Cookie()
+   >>> C = cookies.Cookie()
    >>> print(C.__class__.__name__)
    SmartCookie
 
@@ -721,8 +721,8 @@
 ###########################################################
 
 def _test():
-    import doctest, Cookie
-    return doctest.testmod(Cookie)
+    import doctest, http.cookies
+    return doctest.testmod(http.cookies)
 
 if __name__ == "__main__":
     _test()
diff --git a/Lib/http/server.py b/Lib/http/server.py
new file mode 100644
index 0000000..4f41a19
--- /dev/null
+++ b/Lib/http/server.py
@@ -0,0 +1,1141 @@
+"""HTTP server classes.
+
+Note: BaseHTTPRequestHandler doesn't implement any HTTP request; see
+SimpleHTTPRequestHandler for simple implementations of GET, HEAD and POST,
+and CGIHTTPRequestHandler for CGI scripts.
+
+It does, however, optionally implement HTTP/1.1 persistent connections,
+as of version 0.3.
+
+Notes on CGIHTTPRequestHandler
+------------------------------
+
+This class implements 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 synchronously.
+
+SECURITY WARNING: DON'T USE THIS CODE UNLESS YOU ARE INSIDE A FIREWALL
+-- it may execute arbitrary Python code or external programs.
+
+Note that status code 200 is sent prior to execution of a CGI script, so
+scripts cannot send other status codes such as 302 (redirect).
+
+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!)
+
+__version__ = "0.6"
+
+__all__ = ["HTTPServer", "BaseHTTPRequestHandler"]
+
+import io
+import os
+import sys
+import cgi
+import time
+import socket # For gethostbyaddr()
+import shutil
+import urllib
+import select
+import mimetools
+import mimetypes
+import posixpath
+import socketserver
+
+# Default error message template
+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>
+"""
+
+DEFAULT_ERROR_CONTENT_TYPE = "text/html;charset=utf-8"
+
+def _quote_html(html):
+    return html.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
+
+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)
+        host, port = self.socket.getsockname()[:2]
+        self.server_name = socket.getfqdn(host)
+        self.server_port = port
+
+
+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__
+
+    error_message_format = DEFAULT_ERROR_MESSAGE
+    error_content_type = DEFAULT_ERROR_CONTENT_TYPE
+
+    # The default request version.  This only affects responses up until
+    # the point where the request line is parsed, so it mainly decides what
+    # the client gets back when sending a malformed request line.
+    # Most web servers default to HTTP 0.9, i.e. don't send a status line.
+    default_request_version = "HTTP/0.9"
+
+    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 = self.default_request_version
+        self.close_connection = 1
+        requestline = str(self.raw_requestline, 'iso-8859-1')
+        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 (%r)" % 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 (%r)" % 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 (%r)" % command)
+                return False
+        elif not words:
+            return False
+        else:
+            self.send_error(400, "Bad request syntax (%r)" % requestline)
+            return False
+        self.command, self.path, self.request_version = command, path, version
+
+        # Examine the headers and look for a Connection directive.
+
+        # MessageClass (rfc822) wants to see strings rather than bytes.
+        # But a TextIOWrapper around self.rfile would buffer too many bytes
+        # from the stream, bytes which we later need to read as bytes.
+        # So we read the correct bytes here, as bytes, then use StringIO
+        # to make them look like strings for MessageClass to parse.
+        headers = []
+        while True:
+            line = self.rfile.readline()
+            headers.append(line)
+            if line in (b'\r\n', b'\n', b''):
+                break
+        hfile = io.StringIO(b''.join(headers).decode('iso-8859-1'))
+        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 (%r)" % 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:
+            shortmsg, longmsg = self.responses[code]
+        except KeyError:
+            shortmsg, longmsg = '???', '???'
+        if message is None:
+            message = shortmsg
+        explain = longmsg
+        self.log_error("code %d, message %s", code, message)
+        # using _quote_html to prevent Cross Site Scripting attacks (see bug #1100201)
+        content = (self.error_message_format %
+                   {'code': code, 'message': _quote_html(message), 'explain': explain})
+        self.send_response(code, message)
+        self.send_header("Content-Type", self.error_content_type)
+        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.encode('UTF-8', 'replace'))
+
+    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)).encode('ASCII', 'strict'))
+            # 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)).encode('ASCII', 'strict'))
+
+        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(b"\r\n")
+
+    def log_request(self, code='-', size='-'):
+        """Log an accepted request.
+
+        This is called by send_response().
+
+        """
+
+        self.log_message('"%s" %s %s',
+                         self.requestline, str(code), str(size))
+
+    def log_error(self, format, *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(format, *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, timestamp=None):
+        """Return the current date and time formatted for a message header."""
+        if timestamp is None:
+            timestamp = time.time()
+        year, month, day, hh, mm, ss, wd, y, z = time.gmtime(timestamp)
+        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)
+
+    # 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 RFC 2616.
+    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 Content', '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 Timeout', '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 Server 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 Unavailable',
+              '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.'),
+        }
+
+
+class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
+
+    """Simple HTTP request handler with GET and HEAD commands.
+
+    This serves files from the current directory and any of its
+    subdirectories.  The MIME type for files is determined by
+    calling the .guess_type() method.
+
+    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):
+            if not self.path.endswith('/'):
+                # redirect browser - doing basically what apache does
+                self.send_response(301)
+                self.send_header("Location", self.path + "/")
+                self.end_headers()
+                return None
+            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)
+        try:
+            f = open(path, 'rb')
+        except IOError:
+            self.send_error(404, "File not found")
+            return None
+        self.send_response(200)
+        self.send_header("Content-type", ctype)
+        fs = os.fstat(f.fileno())
+        self.send_header("Content-Length", str(fs[6]))
+        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
+        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(key=lambda a: a.lower())
+        r = []
+        displaypath = cgi.escape(urllib.unquote(self.path))
+        r.append('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">')
+        r.append("<html>\n<title>Directory listing for %s</title>\n" % displaypath)
+        r.append("<body>\n<h2>Directory listing for %s</h2>\n" % displaypath)
+        r.append("<hr>\n<ul>\n")
+        for name in list:
+            fullname = os.path.join(path, name)
+            displayname = linkname = 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 /
+            r.append('<li><a href="%s">%s</a>\n'
+                    % (urllib.quote(linkname), cgi.escape(displayname)))
+        r.append("</ul>\n<hr>\n</body>\n</html>\n")
+        enc = sys.getfilesystemencoding()
+        encoded = ''.join(r).encode(enc)
+        f = io.BytesIO()
+        f.write(encoded)
+        f.seek(0)
+        self.send_response(200)
+        self.send_header("Content-type", "text/html; charset=%s" % enc)
+        self.send_header("Content-Length", str(len(encoded)))
+        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.)
+
+        """
+        # abandon query parameters
+        path = path.split('?',1)[0]
+        path = path.split('#',1)[0]
+        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 application/octet-stream
+        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['']
+
+    if not mimetypes.inited:
+        mimetypes.init() # try to read system mime.types
+    extensions_map = mimetypes.types_map.copy()
+    extensions_map.update({
+        '': 'application/octet-stream', # Default
+        '.py': 'text/plain',
+        '.c': 'text/plain',
+        '.h': 'text/plain',
+        })
+
+
+# Utilities for CGIHTTPRequestHandler
+
+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 & 0o111 != 0
+
+
+class CGIHTTPRequestHandler(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 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."""
+        path = self.path
+        dir, rest = self.cgi_info
+
+        i = path.find('/', len(dir) + 1)
+        while i >= 0:
+            nextdir = path[:i]
+            nextrest = path[i+1:]
+
+            scriptdir = self.translate_path(nextdir)
+            if os.path.isdir(scriptdir):
+                dir, rest = nextdir, nextrest
+                i = path.find('/', len(dir) + 1)
+            else:
+                break
+
+        # find an explicit query string, if present.
+        i = rest.rfind('?')
+        if i >= 0:
+            rest, query = rest[:i], rest[i+1:]
+        else:
+            query = ''
+
+        # dissect the part after the directory name into a script name &
+        # a possible additional path, to be stored in PATH_INFO.
+        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 (%r)" % scriptname)
+            return
+        if not os.path.isfile(scriptfile):
+            self.send_error(403, "CGI script is not a plain file (%r)" %
+                            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 (%r)" %
+                                scriptname)
+                return
+            if not self.is_executable(scriptfile):
+                self.send_error(403, "CGI script is not executable (%r)" %
+                                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]
+        authorization = self.headers.getheader("authorization")
+        if authorization:
+            authorization = authorization.split()
+            if len(authorization) == 2:
+                import base64, binascii
+                env['AUTH_TYPE'] = authorization[0]
+                if authorization[0].lower() == "basic":
+                    try:
+                        authorization = authorization[1].encode('ascii')
+                        authorization = base64.decodestring(authorization).\
+                                        decode('ascii')
+                    except (binascii.Error, UnicodeError):
+                        pass
+                    else:
+                        authorization = authorization.split(':')
+                        if len(authorization) == 2:
+                            env['REMOTE_USER'] = authorization[0]
+        # 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
+        referer = self.headers.getheader('referer')
+        if referer:
+            env['HTTP_REFERER'] = referer
+        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', 'HTTP_REFERER'):
+            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:
+                save_cwd = os.getcwd()
+                try:
+                    sys.argv = [scriptfile]
+                    if '=' not in decoded_query:
+                        sys.argv.append(decoded_query)
+                    sys.stdout = self.wfile
+                    sys.stdin = self.rfile
+                    exec(open(scriptfile).read(), {"__name__": "__main__"})
+                finally:
+                    sys.argv = save_argv
+                    sys.stdin = save_stdin
+                    sys.stdout = save_stdout
+                    sys.stderr = save_stderr
+                    os.chdir(save_cwd)
+            except SystemExit as sts:
+                self.log_error("CGI script exit status %s", str(sts))
+            else:
+                self.log_message("CGI script exited OK")
+
+
+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:]:
+        port = int(sys.argv[1])
+    else:
+        port = 8000
+    server_address = ('', port)
+
+    HandlerClass.protocol_version = protocol
+    httpd = ServerClass(server_address, HandlerClass)
+
+    sa = httpd.socket.getsockname()
+    print("Serving HTTP on", sa[0], "port", sa[1], "...")
+    httpd.serve_forever()
+
+
+if __name__ == '__main__':
+    test(HandlerClass=BaseHTTPRequestHandler)
+    test(HandlerClass=SimpleHTTPRequestHandler)
+    test(HandlerClass=CGIHTTPRequestHandler)
diff --git a/Lib/logging/handlers.py b/Lib/logging/handlers.py
index c871ed0..29c398d 100644
--- a/Lib/logging/handlers.py
+++ b/Lib/logging/handlers.py
@@ -1002,9 +1002,9 @@
         Send the record to the Web server as an URL-encoded dictionary
         """
         try:
-            import httplib, urllib
+            import http.client, urllib
             host = self.host
-            h = httplib.HTTP(host)
+            h = http.client.HTTP(host)
             url = self.url
             data = urllib.urlencode(self.mapLogRecord(record))
             if self.method == "GET":
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index 140e1d8..42ba266 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -1921,7 +1921,7 @@
 # --------------------------------------------------- web browser interface
 
 def serve(port, callback=None, completer=None):
-    import BaseHTTPServer, mimetools, select
+    import http.server, mimetools, select
 
     # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
     class Message(mimetools.Message):
@@ -1933,7 +1933,7 @@
             self.parsetype()
             self.parseplist()
 
-    class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+    class DocHandler(http.server.BaseHTTPRequestHandler):
         def send_document(self, title, contents):
             try:
                 self.send_response(200)
@@ -1978,7 +1978,7 @@
 
         def log_message(self, *args): pass
 
-    class DocServer(BaseHTTPServer.HTTPServer):
+    class DocServer(http.server.HTTPServer):
         def __init__(self, port, callback):
             host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
             self.address = ('', port)
@@ -1997,7 +1997,7 @@
             self.base.server_activate(self)
             if self.callback: self.callback(self)
 
-    DocServer.base = BaseHTTPServer.HTTPServer
+    DocServer.base = http.server.HTTPServer
     DocServer.handler = DocHandler
     DocHandler.MessageClass = Message
     try:
diff --git a/Lib/test/test_SimpleHTTPServer.py b/Lib/test/test_SimpleHTTPServer.py
index d285f27..36c2b89 100644
--- a/Lib/test/test_SimpleHTTPServer.py
+++ b/Lib/test/test_SimpleHTTPServer.py
@@ -4,11 +4,11 @@
 """
 
 import os, unittest
-from SimpleHTTPServer import SimpleHTTPRequestHandler
+from http.server import SimpleHTTPRequestHandler
 from test import support
 
 
-class SocketlessRequestHandler (SimpleHTTPRequestHandler):
+class SocketlessRequestHandler(SimpleHTTPRequestHandler):
     def __init__(self):
         pass
 
diff --git a/Lib/test/test___all__.py b/Lib/test/test___all__.py
index f3f7ba3..89395be 100644
--- a/Lib/test/test___all__.py
+++ b/Lib/test/test___all__.py
@@ -33,12 +33,10 @@
             # than an AttributeError somewhere deep in CGIHTTPServer.
             import _socket
 
-        self.check_all("BaseHTTPServer")
-        self.check_all("CGIHTTPServer")
+        self.check_all("http.server")
         self.check_all("configparser")
-        self.check_all("Cookie")
-        self.check_all("Queue")
-        self.check_all("SimpleHTTPServer")
+        self.check_all("http.cookies")
+        self.check_all("queue")
         self.check_all("socketserver")
         self.check_all("aifc")
         self.check_all("base64")
@@ -77,7 +75,7 @@
         self.check_all("gzip")
         self.check_all("heapq")
         self.check_all("htmllib")
-        self.check_all("httplib")
+        self.check_all("http.client")
         self.check_all("ihooks")
         self.check_all("imaplib")
         self.check_all("imghdr")
diff --git a/Lib/test/test_docxmlrpc.py b/Lib/test/test_docxmlrpc.py
index 9cb9ffb..d1799a2 100644
--- a/Lib/test/test_docxmlrpc.py
+++ b/Lib/test/test_docxmlrpc.py
@@ -1,5 +1,5 @@
 from xmlrpc.server import DocXMLRPCServer
-import httplib
+import http.client
 from test import support
 import threading
 import time
@@ -65,7 +65,7 @@
             time.sleep(0.001)
             n -= 1
 
-        self.client = httplib.HTTPConnection("localhost:%d" % PORT)
+        self.client = http.client.HTTPConnection("localhost:%d" % PORT)
 
     def tearDown(self):
         self.client.close()
diff --git a/Lib/test/test_cookielib.py b/Lib/test/test_http_cookiejar.py
similarity index 91%
rename from Lib/test/test_cookielib.py
rename to Lib/test/test_http_cookiejar.py
index e400bfa..09fb0c6 100644
--- a/Lib/test/test_cookielib.py
+++ b/Lib/test/test_http_cookiejar.py
@@ -1,15 +1,20 @@
-"""Tests for cookielib.py."""
+"""Tests for http/cookiejar.py."""
 
-import re, os, time
+import re, os, time, urllib2
 from unittest import TestCase
 
 from test import support
 
+from http.cookiejar import time2isoz, http2time, time2netscape, \
+     parse_ns_headers, join_header_words, split_header_words, Cookie, \
+     CookieJar, DefaultCookiePolicy, LWPCookieJar, MozillaCookieJar, \
+     LoadError, lwp_cookie_str, DEFAULT_HTTP_PORT, escape_path, \
+     reach, is_HDN, domain_match, user_domain_match, request_path, \
+     request_port, request_host
+
 class DateTimeTests(TestCase):
 
     def test_time2isoz(self):
-        from cookielib import time2isoz
-
         base = 1019227000
         day = 24*3600
         self.assertEquals(time2isoz(base), "2002-04-19 14:36:40Z")
@@ -24,8 +29,6 @@
                          "bad time2isoz format: %s %s" % (az, bz))
 
     def test_http2time(self):
-        from cookielib import http2time
-
         def parse_date(text):
             return time.gmtime(http2time(text))[:6]
 
@@ -38,8 +41,6 @@
         self.assertEquals(parse_date("03-Feb-98"), (1998, 2, 3, 0, 0, 0.0))
 
     def test_http2time_formats(self):
-        from cookielib import http2time, time2isoz
-
         # test http2time for supported dates.  Test cases with 2 digit year
         # will probably break in year 2044.
         tests = [
@@ -77,8 +78,6 @@
                          "'%s'  =>  %s, %s, %s (%s)" % (s, t, t2, t3, test_t))
 
     def test_http2time_garbage(self):
-        from cookielib import http2time
-
         for test in [
             '',
             'Garbage',
@@ -99,8 +98,6 @@
 
 class HeaderTests(TestCase):
     def test_parse_ns_headers(self):
-        from cookielib import parse_ns_headers
-
         # quotes should be stripped
         expected = [[('foo', 'bar'), ('expires', 2209069412), ('version', '0')]]
         for hdr in [
@@ -112,24 +109,18 @@
     def test_parse_ns_headers_special_names(self):
         # names such as 'expires' are not special in first name=value pair
         # of Set-Cookie: header
-        from cookielib import parse_ns_headers
-
         # Cookie with name 'expires'
         hdr = 'expires=01 Jan 2040 22:23:32 GMT'
         expected = [[("expires", "01 Jan 2040 22:23:32 GMT"), ("version", "0")]]
         self.assertEquals(parse_ns_headers([hdr]), expected)
 
     def test_join_header_words(self):
-        from cookielib import join_header_words
-
         joined = join_header_words([[("foo", None), ("bar", "baz")]])
         self.assertEquals(joined, "foo; bar=baz")
 
         self.assertEquals(join_header_words([[]]), "")
 
     def test_split_header_words(self):
-        from cookielib import split_header_words
-
         tests = [
             ("foo", [[("foo", None)]]),
             ("foo=bar", [[("foo", "bar")]]),
@@ -164,8 +155,6 @@
 """ % (arg, expect, result))
 
     def test_roundtrip(self):
-        from cookielib import split_header_words, join_header_words
-
         tests = [
             ("foo", "foo"),
             ("foo=bar", "foo=bar"),
@@ -218,8 +207,7 @@
 
 def _interact(cookiejar, url, set_cookie_hdrs, hdr_name):
     """Perform a single request / response cycle, returning Cookie: header."""
-    from urllib2 import Request
-    req = Request(url)
+    req = urllib2.Request(url)
     cookiejar.add_cookie_header(req)
     cookie_hdr = req.get_header("Cookie", "")
     headers = []
@@ -233,7 +221,6 @@
 class FileCookieJarTests(TestCase):
     def test_lwp_valueless_cookie(self):
         # cookies with no value should be saved and loaded consistently
-        from cookielib import LWPCookieJar
         filename = support.TESTFN
         c = LWPCookieJar()
         interact_netscape(c, "http://www.acme.com/", 'boo')
@@ -248,7 +235,6 @@
         self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None)
 
     def test_bad_magic(self):
-        from cookielib import LWPCookieJar, MozillaCookieJar, LoadError
         # IOErrors (eg. file doesn't exist) are allowed to propagate
         filename = support.TESTFN
         for cookiejar_class in LWPCookieJar, MozillaCookieJar:
@@ -326,8 +312,7 @@
         # may require disk access -- in particular, with MSIECookieJar)
         # This is only a rough check for performance reasons, so it's not too
         # critical as long as it's sufficiently liberal.
-        import cookielib, urllib2
-        pol = cookielib.DefaultCookiePolicy()
+        pol = DefaultCookiePolicy()
         for url, domain, ok in [
             ("http://foo.bar.com/", "blah.com", False),
             ("http://foo.bar.com/", "rhubarb.blah.com", False),
@@ -352,10 +337,8 @@
             else: self.assert_(not r)
 
     def test_missing_value(self):
-        from cookielib import MozillaCookieJar, lwp_cookie_str
-
         # missing = sign in Cookie: header is regarded by Mozilla as a missing
-        # name, and by cookielib as a missing value
+        # name, and by http.cookiejar as a missing value
         filename = support.TESTFN
         c = MozillaCookieJar(filename)
         interact_netscape(c, "http://www.acme.com/", 'eggs')
@@ -388,8 +371,6 @@
     def test_rfc2109_handling(self):
         # RFC 2109 cookies are handled as RFC 2965 or Netscape cookies,
         # dependent on policy settings
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         for rfc2109_as_netscape, rfc2965, version in [
             # default according to rfc2965 if not explicitly specified
             (None, False, 0),
@@ -419,8 +400,6 @@
                     self.assertEqual(cookie2965.version, 1)
 
     def test_ns_parser(self):
-        from cookielib import CookieJar, DEFAULT_HTTP_PORT
-
         c = CookieJar()
         interact_netscape(c, "http://www.acme.com/",
                           'spam=eggs; DoMain=.acme.com; port; blArgh="feep"')
@@ -458,8 +437,6 @@
     def test_ns_parser_special_names(self):
         # names such as 'expires' are not special in first name=value pair
         # of Set-Cookie: header
-        from cookielib import CookieJar
-
         c = CookieJar()
         interact_netscape(c, "http://www.acme.com/", 'expires=eggs')
         interact_netscape(c, "http://www.acme.com/", 'version=eggs; spam=eggs')
@@ -469,8 +446,6 @@
         self.assert_('version' in cookies)
 
     def test_expires(self):
-        from cookielib import time2netscape, CookieJar
-
         # if expires is in future, keep cookie...
         c = CookieJar()
         future = time2netscape(time.time()+3600)
@@ -509,8 +484,6 @@
         # XXX RFC 2965 expiry rules (some apply to V0 too)
 
     def test_default_path(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         # RFC 2965
         pol = DefaultCookiePolicy(rfc2965=True)
 
@@ -551,7 +524,6 @@
         self.assert_("/blah/rhubarb" in c._cookies["www.acme.com"])
 
     def test_escape_path(self):
-        from cookielib import escape_path
         cases = [
             # quoted safe
             ("/foo%2f/bar", "/foo%2F/bar"),
@@ -575,57 +547,50 @@
             self.assertEquals(escape_path(arg), result)
 
     def test_request_path(self):
-        from urllib2 import Request
-        from cookielib import request_path
         # with parameters
-        req = Request("http://www.example.com/rheum/rhaponicum;"
-                      "foo=bar;sing=song?apples=pears&spam=eggs#ni")
+        req = urllib2.Request("http://www.example.com/rheum/rhaponicum;"
+                              "foo=bar;sing=song?apples=pears&spam=eggs#ni")
         self.assertEquals(request_path(req), "/rheum/rhaponicum;"
                      "foo=bar;sing=song?apples=pears&spam=eggs#ni")
         # without parameters
-        req = Request("http://www.example.com/rheum/rhaponicum?"
-                      "apples=pears&spam=eggs#ni")
+        req = urllib2.Request("http://www.example.com/rheum/rhaponicum?"
+                              "apples=pears&spam=eggs#ni")
         self.assertEquals(request_path(req), "/rheum/rhaponicum?"
                      "apples=pears&spam=eggs#ni")
         # missing final slash
-        req = Request("http://www.example.com")
+        req = urllib2.Request("http://www.example.com")
         self.assertEquals(request_path(req), "/")
 
     def test_request_port(self):
-        from urllib2 import Request
-        from cookielib import request_port, DEFAULT_HTTP_PORT
-        req = Request("http://www.acme.com:1234/",
-                      headers={"Host": "www.acme.com:4321"})
+        req = urllib2.Request("http://www.acme.com:1234/",
+                              headers={"Host": "www.acme.com:4321"})
         self.assertEquals(request_port(req), "1234")
-        req = Request("http://www.acme.com/",
-                      headers={"Host": "www.acme.com:4321"})
+        req = urllib2.Request("http://www.acme.com/",
+                              headers={"Host": "www.acme.com:4321"})
         self.assertEquals(request_port(req), DEFAULT_HTTP_PORT)
 
     def test_request_host(self):
-        from urllib2 import Request
-        from cookielib import request_host
         # this request is illegal (RFC2616, 14.2.3)
-        req = Request("http://1.1.1.1/",
-                      headers={"Host": "www.acme.com:80"})
+        req = urllib2.Request("http://1.1.1.1/",
+                              headers={"Host": "www.acme.com:80"})
         # libwww-perl wants this response, but that seems wrong (RFC 2616,
         # section 5.2, point 1., and RFC 2965 section 1, paragraph 3)
         #self.assertEquals(request_host(req), "www.acme.com")
         self.assertEquals(request_host(req), "1.1.1.1")
-        req = Request("http://www.acme.com/",
-                      headers={"Host": "irrelevant.com"})
+        req = urllib2.Request("http://www.acme.com/",
+                              headers={"Host": "irrelevant.com"})
         self.assertEquals(request_host(req), "www.acme.com")
         # not actually sure this one is valid Request object, so maybe should
         # remove test for no host in url in request_host function?
-        req = Request("/resource.html",
-                      headers={"Host": "www.acme.com"})
+        req = urllib2.Request("/resource.html",
+                              headers={"Host": "www.acme.com"})
         self.assertEquals(request_host(req), "www.acme.com")
         # port shouldn't be in request-host
-        req = Request("http://www.acme.com:2345/resource.html",
-                      headers={"Host": "www.acme.com:5432"})
+        req = urllib2.Request("http://www.acme.com:2345/resource.html",
+                              headers={"Host": "www.acme.com:5432"})
         self.assertEquals(request_host(req), "www.acme.com")
 
     def test_is_HDN(self):
-        from cookielib import is_HDN
         self.assert_(is_HDN("foo.bar.com"))
         self.assert_(is_HDN("1foo2.3bar4.5com"))
         self.assert_(not is_HDN("192.168.1.1"))
@@ -636,7 +601,6 @@
         self.assert_(not is_HDN("foo."))
 
     def test_reach(self):
-        from cookielib import reach
         self.assertEquals(reach("www.acme.com"), ".acme.com")
         self.assertEquals(reach("acme.com"), "acme.com")
         self.assertEquals(reach("acme.local"), ".local")
@@ -647,7 +611,6 @@
         self.assertEquals(reach("192.168.0.1"), "192.168.0.1")
 
     def test_domain_match(self):
-        from cookielib import domain_match, user_domain_match
         self.assert_(domain_match("192.168.1.1", "192.168.1.1"))
         self.assert_(not domain_match("192.168.1.1", ".168.1.1"))
         self.assert_(domain_match("x.y.com", "x.Y.com"))
@@ -688,7 +651,6 @@
         # domain are rejected.
 
         # XXX far from complete
-        from cookielib import CookieJar
         c = CookieJar()
         interact_2965(c, "http://www.nasty.com/",
                       'foo=bar; domain=friendly.org; Version="1"')
@@ -697,8 +659,6 @@
     def test_strict_domain(self):
         # Cookies whose domain is a country-code tld like .co.uk should
         # not be set if CookiePolicy.strict_domain is true.
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         cp = DefaultCookiePolicy(strict_domain=True)
         cj = CookieJar(policy=cp)
         interact_netscape(cj, "http://example.co.uk/", 'no=problemo')
@@ -714,8 +674,6 @@
         # Netscape: .www.bar.com, www.bar.com, .bar.com, bar.com, no domain
         # should all get accepted, as should .acme.com, acme.com and no domain
         # for 2-component domains like acme.com.
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         c = CookieJar()
 
         # two-component V0 domain is OK
@@ -761,8 +719,6 @@
         self.assertEquals(len(c), 4)
 
     def test_two_component_domain_rfc2965(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         pol = DefaultCookiePolicy(rfc2965=True)
         c = CookieJar(pol)
 
@@ -807,31 +763,28 @@
         self.assertEquals(len(c), 3)
 
     def test_domain_allow(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-        from urllib2 import Request
-
         c = CookieJar(policy=DefaultCookiePolicy(
             blocked_domains=["acme.com"],
             allowed_domains=["www.acme.com"]))
 
-        req = Request("http://acme.com/")
+        req = urllib2.Request("http://acme.com/")
         headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
         res = FakeResponse(headers, "http://acme.com/")
         c.extract_cookies(res, req)
         self.assertEquals(len(c), 0)
 
-        req = Request("http://www.acme.com/")
+        req = urllib2.Request("http://www.acme.com/")
         res = FakeResponse(headers, "http://www.acme.com/")
         c.extract_cookies(res, req)
         self.assertEquals(len(c), 1)
 
-        req = Request("http://www.coyote.com/")
+        req = urllib2.Request("http://www.coyote.com/")
         res = FakeResponse(headers, "http://www.coyote.com/")
         c.extract_cookies(res, req)
         self.assertEquals(len(c), 1)
 
         # set a cookie with non-allowed domain...
-        req = Request("http://www.coyote.com/")
+        req = urllib2.Request("http://www.coyote.com/")
         res = FakeResponse(headers, "http://www.coyote.com/")
         cookies = c.make_cookies(res, req)
         c.set_cookie(cookies[0])
@@ -841,15 +794,12 @@
         self.assert_(not req.has_header("Cookie"))
 
     def test_domain_block(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-        from urllib2 import Request
-
         pol = DefaultCookiePolicy(
             rfc2965=True, blocked_domains=[".acme.com"])
         c = CookieJar(policy=pol)
         headers = ["Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/"]
 
-        req = Request("http://www.acme.com/")
+        req = urllib2.Request("http://www.acme.com/")
         res = FakeResponse(headers, "http://www.acme.com/")
         c.extract_cookies(res, req)
         self.assertEquals(len(c), 0)
@@ -859,11 +809,11 @@
         self.assertEquals(len(c), 1)
 
         c.clear()
-        req = Request("http://www.roadrunner.net/")
+        req = urllib2.Request("http://www.roadrunner.net/")
         res = FakeResponse(headers, "http://www.roadrunner.net/")
         c.extract_cookies(res, req)
         self.assertEquals(len(c), 1)
-        req = Request("http://www.roadrunner.net/")
+        req = urllib2.Request("http://www.roadrunner.net/")
         c.add_cookie_header(req)
         self.assert_((req.has_header("Cookie") and
                       req.has_header("Cookie2")))
@@ -874,7 +824,7 @@
         self.assertEquals(len(c), 1)
 
         # set a cookie with blocked domain...
-        req = Request("http://www.acme.com/")
+        req = urllib2.Request("http://www.acme.com/")
         res = FakeResponse(headers, "http://www.acme.com/")
         cookies = c.make_cookies(res, req)
         c.set_cookie(cookies[0])
@@ -884,8 +834,6 @@
         self.assert_(not req.has_header("Cookie"))
 
     def test_secure(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         for ns in True, False:
             for whitespace in " ", "":
                 c = CookieJar()
@@ -909,7 +857,6 @@
                     "secure cookie registered non-secure")
 
     def test_quote_cookie_value(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
         c = CookieJar(policy=DefaultCookiePolicy(rfc2965=True))
         interact_2965(c, "http://www.acme.com/", r'foo=\b"a"r; Version=1')
         h = interact_2965(c, "http://www.acme.com/")
@@ -917,19 +864,15 @@
 
     def test_missing_final_slash(self):
         # Missing slash from request URL's abs_path should be assumed present.
-        from cookielib import CookieJar, DefaultCookiePolicy
-        from urllib2 import Request
         url = "http://www.acme.com"
         c = CookieJar(DefaultCookiePolicy(rfc2965=True))
         interact_2965(c, url, "foo=bar; Version=1")
-        req = Request(url)
+        req = urllib2.Request(url)
         self.assertEquals(len(c), 1)
         c.add_cookie_header(req)
         self.assert_(req.has_header("Cookie"))
 
     def test_domain_mirror(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         pol = DefaultCookiePolicy(rfc2965=True)
 
         c = CookieJar(pol)
@@ -953,8 +896,6 @@
         self.assert_('$Domain="bar.com"' in h, "domain not returned")
 
     def test_path_mirror(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         pol = DefaultCookiePolicy(rfc2965=True)
 
         c = CookieJar(pol)
@@ -971,8 +912,6 @@
         self.assert_('$Path="/"' in h, "path not returned")
 
     def test_port_mirror(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         pol = DefaultCookiePolicy(rfc2965=True)
 
         c = CookieJar(pol)
@@ -1005,8 +944,6 @@
                      "values")
 
     def test_no_return_comment(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         c = CookieJar(DefaultCookiePolicy(rfc2965=True))
         url = "http://foo.bar.com/"
         interact_2965(c, url, 'spam=eggs; Version=1; '
@@ -1018,8 +955,6 @@
             "Comment or CommentURL cookie-attributes returned to server")
 
     def test_Cookie_iterator(self):
-        from cookielib import CookieJar, Cookie, DefaultCookiePolicy
-
         cs = CookieJar(DefaultCookiePolicy(rfc2965=True))
         # add some random cookies
         interact_2965(cs, "http://blah.spam.org/", 'foo=eggs; Version=1; '
@@ -1052,8 +987,6 @@
                 i = i + 1
 
     def test_parse_ns_headers(self):
-        from cookielib import parse_ns_headers
-
         # missing domain value (invalid cookie)
         self.assertEquals(
             parse_ns_headers(["foo=bar; path=/; domain"]),
@@ -1076,10 +1009,8 @@
     def test_bad_cookie_header(self):
 
         def cookiejar_from_cookie_headers(headers):
-            from cookielib import CookieJar
-            from urllib2 import Request
             c = CookieJar()
-            req = Request("http://www.example.com/")
+            req = urllib2.Request("http://www.example.com/")
             r = FakeResponse(headers, "http://www.example.com/")
             c.extract_cookies(r, req)
             return c
@@ -1108,9 +1039,6 @@
     # Tests taken from libwww-perl, with a few modifications and additions.
 
     def test_netscape_example_1(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-        from urllib2 import Request
-
         #-------------------------------------------------------------------
         # First we check that it works for the original example at
         # http://www.netscape.com/newsref/std/cookie_spec.html
@@ -1153,9 +1081,9 @@
 
         c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
 
-        #req = Request("http://1.1.1.1/",
+        #req = urllib2.Request("http://1.1.1.1/",
         #              headers={"Host": "www.acme.com:80"})
-        req = Request("http://www.acme.com:80/",
+        req = urllib2.Request("http://www.acme.com:80/",
                       headers={"Host": "www.acme.com:80"})
 
         headers.append(
@@ -1164,7 +1092,7 @@
         res = FakeResponse(headers, "http://www.acme.com/")
         c.extract_cookies(res, req)
 
-        req = Request("http://www.acme.com/")
+        req = urllib2.Request("http://www.acme.com/")
         c.add_cookie_header(req)
 
         self.assertEqual(req.get_header("Cookie"), "CUSTOMER=WILE_E_COYOTE")
@@ -1174,7 +1102,7 @@
         res = FakeResponse(headers, "http://www.acme.com/")
         c.extract_cookies(res, req)
 
-        req = Request("http://www.acme.com/foo/bar")
+        req = urllib2.Request("http://www.acme.com/foo/bar")
         c.add_cookie_header(req)
 
         h = req.get_header("Cookie")
@@ -1185,7 +1113,7 @@
         res = FakeResponse(headers, "http://www.acme.com")
         c.extract_cookies(res, req)
 
-        req = Request("http://www.acme.com/")
+        req = urllib2.Request("http://www.acme.com/")
         c.add_cookie_header(req)
 
         h = req.get_header("Cookie")
@@ -1193,7 +1121,7 @@
                      "CUSTOMER=WILE_E_COYOTE" in h and
                      "SHIPPING=FEDEX" not in h)
 
-        req = Request("http://www.acme.com/foo/")
+        req = urllib2.Request("http://www.acme.com/foo/")
         c.add_cookie_header(req)
 
         h = req.get_header("Cookie")
@@ -1202,9 +1130,6 @@
                       h.startswith("SHIPPING=FEDEX;")))
 
     def test_netscape_example_2(self):
-        from cookielib import CookieJar
-        from urllib2 import Request
-
         # Second Example transaction sequence:
         #
         # Assume all mappings from above have been cleared.
@@ -1231,13 +1156,13 @@
         c = CookieJar()
         headers = []
 
-        req = Request("http://www.acme.com/")
+        req = urllib2.Request("http://www.acme.com/")
         headers.append("Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/")
         res = FakeResponse(headers, "http://www.acme.com/")
 
         c.extract_cookies(res, req)
 
-        req = Request("http://www.acme.com/")
+        req = urllib2.Request("http://www.acme.com/")
         c.add_cookie_header(req)
 
         self.assertEquals(req.get_header("Cookie"),
@@ -1248,7 +1173,7 @@
         res = FakeResponse(headers, "http://www.acme.com/")
         c.extract_cookies(res, req)
 
-        req = Request("http://www.acme.com/ammo")
+        req = urllib2.Request("http://www.acme.com/ammo")
         c.add_cookie_header(req)
 
         self.assert_(re.search(r"PART_NUMBER=RIDING_ROCKET_0023;\s*"
@@ -1256,7 +1181,6 @@
                                req.get_header("Cookie")))
 
     def test_ietf_example_1(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
         #-------------------------------------------------------------------
         # Then we test with the examples from draft-ietf-http-state-man-mec-03.txt
         #
@@ -1371,8 +1295,6 @@
         # contains all the cookies received so far.
 
     def test_ietf_example_2(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         # 5.2  Example 2
         #
         # This example illustrates the effect of the Path attribute.  All detail
@@ -1428,8 +1350,6 @@
 
     def test_rejection(self):
         # Test rejection of Set-Cookie2 responses based on domain, path, port.
-        from cookielib import DefaultCookiePolicy, LWPCookieJar
-
         pol = DefaultCookiePolicy(rfc2965=True)
 
         c = LWPCookieJar(policy=pol)
@@ -1522,8 +1442,6 @@
     def test_url_encoding(self):
         # Try some URL encodings of the PATHs.
         # (the behaviour here has changed from libwww-perl)
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         c = CookieJar(DefaultCookiePolicy(rfc2965=True))
         interact_2965(c, "http://www.acme.com/foo%2f%25/%3c%3c%0Anew%E5/%E5",
                       "foo  =   bar; version    =   1")
@@ -1543,8 +1461,6 @@
 
     def test_mozilla(self):
         # Save / load Mozilla/Netscape cookie file format.
-        from cookielib import MozillaCookieJar, DefaultCookiePolicy
-
         year_plus_one = time.localtime()[0] + 1
 
         filename = support.TESTFN
@@ -1586,12 +1502,9 @@
 
     def test_netscape_misc(self):
         # Some additional Netscape cookies tests.
-        from cookielib import CookieJar
-        from urllib2 import Request
-
         c = CookieJar()
         headers = []
-        req = Request("http://foo.bar.acme.com/foo")
+        req = urllib2.Request("http://foo.bar.acme.com/foo")
 
         # Netscape allows a host part that contains dots
         headers.append("Set-Cookie: Customer=WILE_E_COYOTE; domain=.acme.com")
@@ -1605,7 +1518,7 @@
         res = FakeResponse(headers, "http://www.acme.com/foo")
         c.extract_cookies(res, req)
 
-        req = Request("http://foo.bar.acme.com/foo")
+        req = urllib2.Request("http://foo.bar.acme.com/foo")
         c.add_cookie_header(req)
         self.assert_(
             "PART_NUMBER=3,4" in req.get_header("Cookie") and
@@ -1613,8 +1526,6 @@
 
     def test_intranet_domains_2965(self):
         # Test handling of local intranet hostnames without a dot.
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         c = CookieJar(DefaultCookiePolicy(rfc2965=True))
         interact_2965(c, "http://example/",
                       "foo1=bar; PORT; Discard; Version=1;")
@@ -1627,8 +1538,6 @@
         self.assert_("foo2=bar" in cookie and len(c) == 3)
 
     def test_intranet_domains_ns(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-
         c = CookieJar(DefaultCookiePolicy(rfc2965 = False))
         interact_netscape(c, "http://example/", "foo1=bar")
         cookie = interact_netscape(c, "http://example/",
@@ -1641,9 +1550,6 @@
         self.assertEquals(len(c), 2)
 
     def test_empty_path(self):
-        from cookielib import CookieJar, DefaultCookiePolicy
-        from urllib2 import Request
-
         # Test for empty path
         # Broken web-server ORION/1.3.38 returns to the client response like
         #
@@ -1654,12 +1560,12 @@
         c = CookieJar(DefaultCookiePolicy(rfc2965 = True))
         headers = []
 
-        req = Request("http://www.ants.com/")
+        req = urllib2.Request("http://www.ants.com/")
         headers.append("Set-Cookie: JSESSIONID=ABCDERANDOM123; Path=")
         res = FakeResponse(headers, "http://www.ants.com/")
         c.extract_cookies(res, req)
 
-        req = Request("http://www.ants.com/")
+        req = urllib2.Request("http://www.ants.com/")
         c.add_cookie_header(req)
 
         self.assertEquals(req.get_header("Cookie"),
@@ -1667,7 +1573,7 @@
         self.assertEquals(req.get_header("Cookie2"), '$Version="1"')
 
         # missing path in the request URI
-        req = Request("http://www.ants.com:8080")
+        req = urllib2.Request("http://www.ants.com:8080")
         c.add_cookie_header(req)
 
         self.assertEquals(req.get_header("Cookie"),
@@ -1675,15 +1581,12 @@
         self.assertEquals(req.get_header("Cookie2"), '$Version="1"')
 
     def test_session_cookies(self):
-        from cookielib import CookieJar
-        from urllib2 import Request
-
         year_plus_one = time.localtime()[0] + 1
 
         # Check session cookies are deleted properly by
         # CookieJar.clear_session_cookies method
 
-        req = Request('http://www.perlmeister.com/scripts')
+        req = urllib2.Request('http://www.perlmeister.com/scripts')
         headers = []
         headers.append("Set-Cookie: s1=session;Path=/scripts")
         headers.append("Set-Cookie: p1=perm; Domain=.perlmeister.com;"
diff --git a/Lib/test/test_cookie.py b/Lib/test/test_http_cookies.py
similarity index 92%
rename from Lib/test/test_cookie.py
rename to Lib/test/test_http_cookies.py
index 07d29e1..a336c82 100644
--- a/Lib/test/test_cookie.py
+++ b/Lib/test/test_http_cookies.py
@@ -1,8 +1,8 @@
-# Simple test suite for Cookie.py
+# Simple test suite for http/cookies.py
 
 from test.support import run_unittest, run_doctest
 import unittest
-import Cookie
+from http import cookies
 
 import warnings
 warnings.filterwarnings("ignore",
@@ -34,7 +34,7 @@
         ]
 
         for case in cases:
-            C = Cookie.SimpleCookie()
+            C = cookies.SimpleCookie()
             C.load(case['data'])
             self.assertEqual(repr(C), case['repr'])
             self.assertEqual(C.output(sep='\n'), case['output'])
@@ -42,7 +42,7 @@
                 self.assertEqual(C[k].value, v)
 
     def test_load(self):
-        C = Cookie.SimpleCookie()
+        C = cookies.SimpleCookie()
         C.load('Customer="WILE_E_COYOTE"; Version=1; Path=/acme')
 
         self.assertEqual(C['Customer'].value, 'WILE_E_COYOTE')
@@ -68,7 +68,7 @@
 
     def test_quoted_meta(self):
         # Try cookie with quoted meta-data
-        C = Cookie.SimpleCookie()
+        C = cookies.SimpleCookie()
         C.load('Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"')
         self.assertEqual(C['Customer'].value, 'WILE_E_COYOTE')
         self.assertEqual(C['Customer']['version'], '1')
@@ -76,7 +76,7 @@
 
 def test_main():
     run_unittest(CookieTests)
-    run_doctest(Cookie)
+    run_doctest(cookies)
 
 if __name__ == '__main__':
     test_main()
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 7a77cff..ff4cf9b 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -1,4 +1,4 @@
-import httplib
+import http.client as httplib
 import io
 import socket
 
@@ -48,8 +48,6 @@
         # Some headers are added automatically, but should not be added by
         # .request() if they are explicitly set.
 
-        import httplib
-
         class HeaderCountingBuffer(list):
             def __init__(self):
                 self.count = {}
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
index cc79cb8..02be57a 100644
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -4,16 +4,15 @@
 Josip Dzolonga, and Michael Otteneder for the 2007/08 GHOP contest.
 """
 
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-from SimpleHTTPServer import SimpleHTTPRequestHandler
-from CGIHTTPServer import CGIHTTPRequestHandler
+from http.server import BaseHTTPRequestHandler, HTTPServer, \
+     SimpleHTTPRequestHandler, CGIHTTPRequestHandler
 
 import os
 import sys
 import base64
 import shutil
 import urllib
-import httplib
+import http.client
 import tempfile
 import threading
 
@@ -59,7 +58,7 @@
         self.thread.stop()
 
     def request(self, uri, method='GET', body=None, headers={}):
-        self.connection = httplib.HTTPConnection('localhost', self.PORT)
+        self.connection = http.client.HTTPConnection('localhost', self.PORT)
         self.connection.request(method, uri, body, headers)
         return self.connection.getresponse()
 
@@ -92,7 +91,7 @@
 
     def setUp(self):
         BaseTestCase.setUp(self)
-        self.con = httplib.HTTPConnection('localhost', self.PORT)
+        self.con = http.client.HTTPConnection('localhost', self.PORT)
         self.con.connect()
 
     def test_command(self):
@@ -343,7 +342,7 @@
 def test_main(verbose=None):
     try:
         cwd = os.getcwd()
-        support.run_unittest(#BaseHTTPServerTestCase,
+        support.run_unittest(BaseHTTPServerTestCase,
                              SimpleHTTPServerTestCase,
                              CGIHTTPServerTestCase
                              )
diff --git a/Lib/test/test_pyclbr.py b/Lib/test/test_pyclbr.py
index ca0aefc..e8eb94e 100644
--- a/Lib/test/test_pyclbr.py
+++ b/Lib/test/test_pyclbr.py
@@ -168,7 +168,6 @@
                              'getproxies_internetconfig',)) # not on all platforms
         cm('pickle')
         cm('aifc', ignore=('openfp',))  # set with = in module
-        cm('Cookie', ignore=('Cookie',)) # Cookie is an alias for SmartCookie
         cm('sre_parse', ignore=('dump',)) # from sre_constants import *
         cm('pdb')
         cm('pydoc')
diff --git a/Lib/test/test_shelve.py b/Lib/test/test_shelve.py
index 5fb4641..b2ed87d 100644
--- a/Lib/test/test_shelve.py
+++ b/Lib/test/test_shelve.py
@@ -3,7 +3,7 @@
 import glob
 from test import support
 from collections import MutableMapping
-from test.test_anydbm import dbm_iterator
+from test.test_dbm import dbm_iterator
 
 def L1(s):
     return s.decode("latin-1")
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index d12968c..d664582 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -855,7 +855,7 @@
     In this case (and in this case only), it should be possible to
     create a file object, read a line from it, create another file
     object, read another line from it, without loss of data in the
-    first file object's buffer.  Note that httplib relies on this
+    first file object's buffer.  Note that http.client relies on this
     when reading multiple requests from the same socket."""
 
     bufsize = 0 # Use unbuffered mode
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 4f884f0..ea3efd6 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -15,8 +15,7 @@
 import traceback
 import asyncore
 
-from BaseHTTPServer import HTTPServer
-from SimpleHTTPServer import SimpleHTTPRequestHandler
+from http.server import HTTPServer, SimpleHTTPRequestHandler
 
 # Optionally test SSL support, if we have it in the tested platform
 skip_expected = False
diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py
index 292722d..18101e7 100644
--- a/Lib/test/test_sundry.py
+++ b/Lib/test/test_sundry.py
@@ -8,7 +8,6 @@
 class TestUntestedModules(unittest.TestCase):
     def test_at_least_import_untested_modules(self):
         with support.catch_warning():
-            import CGIHTTPServer
             import aifc
             import bdb
             import cgitb
diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py
index 7db281c..b14510f 100644
--- a/Lib/test/test_urllib.py
+++ b/Lib/test/test_urllib.py
@@ -1,7 +1,7 @@
 """Regresssion tests for urllib"""
 
 import urllib
-import httplib
+import http.client
 import io
 import unittest
 from test import support
@@ -107,14 +107,14 @@
             def readline(self, length=None):
                 if self.closed: return b""
                 return io.BytesIO.readline(self, length)
-        class FakeHTTPConnection(httplib.HTTPConnection):
+        class FakeHTTPConnection(http.client.HTTPConnection):
             def connect(self):
                 self.sock = FakeSocket(fakedata)
-        self._connection_class = httplib.HTTPConnection
-        httplib.HTTPConnection = FakeHTTPConnection
+        self._connection_class = http.client.HTTPConnection
+        http.client.HTTPConnection = FakeHTTPConnection
 
     def unfakehttp(self):
-        httplib.HTTPConnection = self._connection_class
+        http.client.HTTPConnection = self._connection_class
 
     def test_read(self):
         self.fakehttp(b"Hello!")
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
index cb730e2..3386800 100644
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -77,7 +77,7 @@
     Note the case normalization of header names here, to .capitalize()-case.
     This should be preserved for backwards-compatibility.  (In the HTTP case,
     normalization to .title()-case is done by urllib2 before sending headers to
-    httplib).
+    http.client).
 
     >>> url = "http://example.com"
     >>> r = Request(url, headers={"Spam-eggs": "blah"})
@@ -348,12 +348,12 @@
         self._count = 0
         self.requests = []
     def http_open(self, req):
-        import mimetools, httplib, copy
+        import mimetools, http.client, copy
         from io import StringIO
         self.requests.append(copy.deepcopy(req))
         if self._count == 0:
             self._count = self._count + 1
-            name = httplib.responses[self.code]
+            name = http.client.responses[self.code]
             msg = mimetools.Message(StringIO(self.headers))
             return self.parent.error(
                 "http", req, MockFile(), self.code, name, msg)
@@ -875,9 +875,8 @@
 
     def test_cookie_redirect(self):
         # cookies shouldn't leak into redirected requests
-        from cookielib import CookieJar
-
-        from test.test_cookielib import interact_netscape
+        from http.cookiejar import CookieJar
+        from test.test_http_cookiejar import interact_netscape
 
         cj = CookieJar()
         interact_netscape(cj, "http://www.example.com/", "spam=eggs")
diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py
index 6bf1820..6c877d9 100644
--- a/Lib/test/test_urllib2_localnet.py
+++ b/Lib/test/test_urllib2_localnet.py
@@ -4,29 +4,29 @@
 import threading
 import urlparse
 import urllib2
-import BaseHTTPServer
+import http.server
 import unittest
 import hashlib
 from test import support
 
 # Loopback http server infrastructure
 
-class LoopbackHttpServer(BaseHTTPServer.HTTPServer):
+class LoopbackHttpServer(http.server.HTTPServer):
     """HTTP server w/ a few modifications that make it useful for
     loopback testing purposes.
     """
 
     def __init__(self, server_address, RequestHandlerClass):
-        BaseHTTPServer.HTTPServer.__init__(self,
-                                           server_address,
-                                           RequestHandlerClass)
+        http.server.HTTPServer.__init__(self,
+                                        server_address,
+                                        RequestHandlerClass)
 
         # Set the timeout of our listening socket really low so
         # that we can stop the server easily.
         self.socket.settimeout(1.0)
 
     def get_request(self):
-        """BaseHTTPServer method, overridden."""
+        """HTTPServer method, overridden."""
 
         request, client_address = self.socket.accept()
 
@@ -188,7 +188,7 @@
 
 # Proxy test infrastructure
 
-class FakeProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+class FakeProxyHandler(http.server.BaseHTTPRequestHandler):
     """This is a 'fake proxy' that makes it look like the entire
     internet has gone down due to a sudden zombie invasion.  It main
     utility is in providing us with authentication support for
@@ -283,7 +283,7 @@
 
 def GetRequestHandler(responses):
 
-    class FakeHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+    class FakeHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
 
         server_version = "TestHTTP/"
         requests = []
diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py
index 89e48cb..990d3da 100644
--- a/Lib/test/test_urllib2net.py
+++ b/Lib/test/test_urllib2net.py
@@ -33,7 +33,7 @@
 ## could be used to HTTP authentication.
 #
 #    def test_basic_auth(self):
-#        import httplib
+#        import http.client
 #
 #        test_url = "http://www.python.org/test/test_urllib2/basic_auth"
 #        test_hostport = "www.python.org"
@@ -61,14 +61,14 @@
 #        # reasons, let's not implement it!  (it's already implemented for proxy
 #        # specification strings (that is, URLs or authorities specifying a
 #        # proxy), so we must keep that)
-#        self.assertRaises(httplib.InvalidURL,
+#        self.assertRaises(http.client.InvalidURL,
 #                          urllib2.urlopen, "http://evil:thing@example.com")
 
 
 class CloseSocketTest(unittest.TestCase):
 
     def test_close(self):
-        import socket, httplib, gc
+        import socket, http.client, gc
 
         # calling .close() on urllib2's response objects should close the
         # underlying socket
@@ -77,7 +77,7 @@
         response = _urlopen_with_retry("http://www.python.org/")
         abused_fileobject = response.fp
         httpresponse = abused_fileobject.raw
-        self.assert_(httpresponse.__class__ is httplib.HTTPResponse)
+        self.assert_(httpresponse.__class__ is http.client.HTTPResponse)
         fileobject = httpresponse.fp
 
         self.assert_(not fileobject.closed)
diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py
index 25a9c9d..8325496 100644
--- a/Lib/test/test_xmlrpc.py
+++ b/Lib/test/test_xmlrpc.py
@@ -7,7 +7,7 @@
 import xmlrpc.server
 import threading
 import mimetools
-import httplib
+import http.client
 import socket
 import os
 from test import support
@@ -340,9 +340,9 @@
 
     # [ch] The test 404 is causing lots of false alarms.
     def XXXtest_404(self):
-        # send POST with httplib, it should return 404 header and
+        # send POST with http.client, it should return 404 header and
         # 'Not Found' message.
-        conn = httplib.HTTPConnection('localhost', PORT)
+        conn = http.client.HTTPConnection('localhost', PORT)
         conn.request('POST', '/this-is-not-valid')
         response = conn.getresponse()
         conn.close()
diff --git a/Lib/test/test_xmlrpc_net.py b/Lib/test/test_xmlrpc_net.py
index 2525254..f6ebbf0 100644
--- a/Lib/test/test_xmlrpc_net.py
+++ b/Lib/test/test_xmlrpc_net.py
@@ -6,7 +6,7 @@
 import unittest
 from test import support
 
-import xmlrpclib.client as xmlrpclib
+import xmlrpc.client as xmlrpclib
 
 class CurrentTimeTest(unittest.TestCase):
 
diff --git a/Lib/urllib.py b/Lib/urllib.py
index 500bf06..2005baf 100644
--- a/Lib/urllib.py
+++ b/Lib/urllib.py
@@ -22,7 +22,7 @@
 (mimetools.Message objects are queried with the getheader() method.)
 """
 
-import httplib
+import http.client
 import os
 import socket
 import sys
@@ -352,7 +352,7 @@
 
         try:
             response = http_conn.getresponse()
-        except httplib.BadStatusLine:
+        except http.client.BadStatusLine:
             # something went wrong with the HTTP status line
             raise IOError('http protocol error', 0,
                           'got a bad status line', None)
@@ -369,7 +369,7 @@
 
     def open_http(self, url, data=None):
         """Use HTTP protocol."""
-        return self._open_generic_http(httplib.HTTPConnection, url, data)
+        return self._open_generic_http(http.client.HTTPConnection, url, data)
 
     def http_error(self, url, fp, errcode, errmsg, headers, data=None):
         """Handle http errors.
@@ -395,9 +395,9 @@
 
     if _have_ssl:
         def _https_connection(self, host):
-            return httplib.HTTPSConnection(host,
-                                           key_file=self.key_file,
-                                           cert_file=self.cert_file)
+            return http.client.HTTPSConnection(host,
+                                               key_file=self.key_file,
+                                               cert_file=self.cert_file)
 
         def open_https(self, url, data=None):
             """Use HTTPS protocol."""
diff --git a/Lib/urllib2.py b/Lib/urllib2.py
index f87d364..948c6c3 100644
--- a/Lib/urllib2.py
+++ b/Lib/urllib2.py
@@ -89,7 +89,7 @@
 
 import base64
 import hashlib
-import httplib
+import http.client
 import io
 import mimetools
 import os
@@ -441,7 +441,7 @@
     default_classes = [ProxyHandler, UnknownHandler, HTTPHandler,
                        HTTPDefaultErrorHandler, HTTPRedirectHandler,
                        FTPHandler, FileHandler, HTTPErrorProcessor]
-    if hasattr(httplib, 'HTTPS'):
+    if hasattr(http.client, 'HTTPS'):
         default_classes.append(HTTPSHandler)
     skip = set()
     for klass in default_classes:
@@ -1047,7 +1047,7 @@
     def do_open(self, http_class, req):
         """Return an addinfourl object for the request, using http_class.
 
-        http_class must implement the HTTPConnection API from httplib.
+        http_class must implement the HTTPConnection API from http.client.
         The addinfourl return value is a file-like object.  It also
         has methods and attributes including:
             - info(): return a mimetools.Message object for the headers
@@ -1082,7 +1082,7 @@
         # object initialized properly.
 
         # XXX Should an HTTPResponse object really be passed to
-        # BufferedReader?  If so, we should change httplib to support
+        # BufferedReader?  If so, we should change http.client to support
         # this use directly.
 
         # Add some fake methods to the reader to satisfy BufferedReader.
@@ -1101,23 +1101,23 @@
 class HTTPHandler(AbstractHTTPHandler):
 
     def http_open(self, req):
-        return self.do_open(httplib.HTTPConnection, req)
+        return self.do_open(http.client.HTTPConnection, req)
 
     http_request = AbstractHTTPHandler.do_request_
 
-if hasattr(httplib, 'HTTPS'):
+if hasattr(http.client, 'HTTPS'):
     class HTTPSHandler(AbstractHTTPHandler):
 
         def https_open(self, req):
-            return self.do_open(httplib.HTTPSConnection, req)
+            return self.do_open(http.client.HTTPSConnection, req)
 
         https_request = AbstractHTTPHandler.do_request_
 
 class HTTPCookieProcessor(BaseHandler):
     def __init__(self, cookiejar=None):
-        import cookielib
+        import http.cookiejar
         if cookiejar is None:
-            cookiejar = cookielib.CookieJar()
+            cookiejar = http.cookiejar.CookieJar()
         self.cookiejar = cookiejar
 
     def http_request(self, request):
diff --git a/Lib/wsgiref/simple_server.py b/Lib/wsgiref/simple_server.py
index 980f97a..e74f576 100644
--- a/Lib/wsgiref/simple_server.py
+++ b/Lib/wsgiref/simple_server.py
@@ -10,7 +10,7 @@
 module.  See also the BaseHTTPServer module docs for other API information.
 """
 
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+from http.server import BaseHTTPRequestHandler, HTTPServer
 import urllib, sys
 from wsgiref.handlers import SimpleHandler
 
diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py
index 138d86d..43e7a6c 100644
--- a/Lib/xmlrpc/client.py
+++ b/Lib/xmlrpc/client.py
@@ -135,7 +135,7 @@
 """
 
 import re, time, operator
-import httplib
+import http.client
 
 # --------------------------------------------------------------------
 # Internal stuff
@@ -1196,7 +1196,7 @@
 
     def send_request(self, host, handler, request_body, debug):
         host, extra_headers, x509 = self.get_host_info(host)
-        connection = httplib.HTTPConnection(host)
+        connection = http.client.HTTPConnection(host)
         if debug:
             connection.set_debuglevel(1)
         headers = {}
@@ -1261,10 +1261,10 @@
         import socket
         if not hasattr(socket, "ssl"):
             raise NotImplementedError(
-                "your version of httplib doesn't support HTTPS")
+                "your version of http.client doesn't support HTTPS")
 
         host, extra_headers, x509 = self.get_host_info(host)
-        connection = httplib.HTTPSConnection(host, None, **(x509 or {}))
+        connection = http.client.HTTPSConnection(host, None, **(x509 or {}))
         if debug:
             connection.set_debuglevel(1)
         headers = {}
diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py
index 9668c8c..4ddc004 100644
--- a/Lib/xmlrpc/server.py
+++ b/Lib/xmlrpc/server.py
@@ -105,8 +105,9 @@
 # Based on code written by Fredrik Lundh.
 
 from xmlrpc.client import Fault, dumps, loads
+from http.server import BaseHTTPRequestHandler
+import http.server
 import socketserver
-import BaseHTTPServer
 import sys
 import os
 import re
@@ -408,7 +409,7 @@
         else:
             raise Exception('method "%s" is not supported' % method)
 
-class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+class SimpleXMLRPCRequestHandler(BaseHTTPRequestHandler):
     """Simple XML-RPC request handler class.
 
     Handles all HTTP POST requests and attempts to decode them as
@@ -500,7 +501,7 @@
         """Selectively log an accepted request."""
 
         if self.server.logRequests:
-            BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size)
+            BaseHTTPRequestHandler.log_request(self, code, size)
 
 class SimpleXMLRPCServer(socketserver.TCPServer,
                          SimpleXMLRPCDispatcher):
@@ -560,10 +561,9 @@
         """
 
         code = 400
-        message, explain = \
-                 BaseHTTPServer.BaseHTTPRequestHandler.responses[code]
+        message, explain = BaseHTTPRequestHandler.responses[code]
 
-        response = BaseHTTPServer.DEFAULT_ERROR_MESSAGE % \
+        response = http.server.DEFAULT_ERROR_MESSAGE % \
             {
              'code' : code,
              'message' : message,