diff options
Diffstat (limited to 'Lib')
35 files changed, 721 insertions, 869 deletions
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 @@ libwww-perl, I hope. """ 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 @@ class MozillaCookieJar(FileCookieJar): 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 @@ class MozillaCookieJar(FileCookieJar): 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 os import socket import platform import configparser -import httplib +import http.client import base64 import urlparse @@ -151,9 +151,9 @@ class upload(PyPIRCCommand): 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 index de27c17..de27c17 100644 --- a/Lib/httplib.py +++ b/Lib/http/client.py diff --git a/Lib/cookielib.py b/Lib/http/cookiejar.py index 6c59390..795953b 100644 --- a/Lib/cookielib.py +++ b/Lib/http/cookiejar.py @@ -33,7 +33,7 @@ try: 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 @@ def _debug(*args): 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 @@ def _warn_unhandled_exception(): 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 index 83f30d5..5078d33 100644 --- a/Lib/Cookie.py +++ b/Lib/http/cookies.py @@ -48,25 +48,25 @@ The Basics 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 @@ appropriate format for a Set-Cookie: header. This is the 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 @@ The load() method of a Cookie extracts cookies from a string. In a 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 @@ The load() method is darn-tootin smart about identifying cookies 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 @@ Each element of the Cookie also supports all of the RFC 2109 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 @@ attribute. 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 @@ The SimpleCookie expects that all values should be standard strings. 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 @@ Python object to a value, and recover the exact same object when the 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 @@ when the load() method parses out values, it attempts to de-serialize 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 @@ Backwards Compatibility ----------------------- 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 @@ Cookie = SmartCookie ########################################################### 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/BaseHTTPServer.py b/Lib/http/server.py index 7fbbcf2..4f41a19 100644 --- a/Lib/BaseHTTPServer.py +++ b/Lib/http/server.py @@ -1,14 +1,30 @@ -"""HTTP server base class. +"""HTTP server classes. -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. +Note: BaseHTTPRequestHandler doesn't implement any HTTP request; see +SimpleHTTPRequestHandler for simple implementations of GET, HEAD and POST, +and CGIHTTPRequestHandler for CGI scripts. -Contents: +It does, however, optionally implement HTTP/1.1 persistent connections, +as of version 0.3. -- BaseHTTPRequestHandler: HTTP request handler base class -- test: test function +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: @@ -66,15 +82,22 @@ XXX To do: # (Actually, the latter is only true if you know the server configuration # at the time the request was made!) -__version__ = "0.3" +__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 @@ -574,6 +597,521 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler): } +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. @@ -598,4 +1136,6 @@ def test(HandlerClass = BaseHTTPRequestHandler, if __name__ == '__main__': - test() + 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 @@ class HTTPHandler(logging.Handler): 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 @@ def apropos(key): # --------------------------------------------------- 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 @@ def serve(port, callback=None, completer=None): 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 @@ pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>''' 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 @@ pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>''' 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 @@ We don't want to require the 'network' resource. """ 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 @@ class AllTest(unittest.TestCase): # 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 @@ class AllTest(unittest.TestCase): 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 @@ class DocXMLRPCHTTPGETServer(unittest.TestCase): 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 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 @@ class DateTimeTests(TestCase): "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 @@ class DateTimeTests(TestCase): 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 @@ class DateTimeTests(TestCase): "'%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 DateTimeTests(TestCase): 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 @@ class HeaderTests(TestCase): 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 @@ Got: '%s' """ % (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_netscape(cookiejar, url, *set_cookie_hdrs): 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 @@ def _interact(cookiejar, url, set_cookie_hdrs, hdr_name): 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 @@ class FileCookieJarTests(TestCase): 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 @@ class CookieTests(TestCase): # 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): # 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): # 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): # 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): "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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): "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 @@ class CookieTests(TestCase): "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 @@ class CookieTests(TestCase): 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 @@ class CookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): # 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): "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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): # 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 @@ class LWPCookieTests(TestCase): 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 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 @@ class CookieTests(unittest.TestCase): ] 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 @@ class CookieTests(unittest.TestCase): 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 @@ class CookieTests(unittest.TestCase): 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 @@ class CookieTests(unittest.TestCase): 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 @@ class HeaderTests(TestCase): # 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 @@ Written by Cody A.W. Somerville <cody-somerville@ubuntu.com>, 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 @@ class BaseTestCase(unittest.TestCase): 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 @@ class BaseHTTPServerTestCase(BaseTestCase): 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 @@ class CGIHTTPServerTestCase(BaseTestCase): 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 @@ class PyclbrTest(TestCase): '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 shelve 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 @@ class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase): 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 shutil 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 @@ import warnings 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 @@ class urlopen_HttpTests(unittest.TestCase): 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 @@ def test_request_headers_methods(): 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 @@ class MockHTTPHandler(urllib2.BaseHandler): 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 @@ class HandlerTests(unittest.TestCase): 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 mimetools 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 @@ class DigestAuthHandler: # 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 @@ class ProxyAuthTests(unittest.TestCase): 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 @@ class AuthTests(unittest.TestCase): ## 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 @@ class AuthTests(unittest.TestCase): # # 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 @@ class CloseSocketTest(unittest.TestCase): 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.client as xmlrpclib import xmlrpc.server import threading import mimetools -import httplib +import http.client import socket import os from test import support @@ -340,9 +340,9 @@ class SimpleServerTestCase(unittest.TestCase): # [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 sys 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 @@ used to query various info about the object, if available. (mimetools.Message objects are queried with the getheader() method.) """ -import httplib +import http.client import os import socket import sys @@ -352,7 +352,7 @@ class URLopener: 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 @@ class URLopener: 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 @@ class URLopener: 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 @@ f = urllib2.urlopen('http://www.python.org/') import base64 import hashlib -import httplib +import http.client import io import mimetools import os @@ -441,7 +441,7 @@ def build_opener(*handlers): 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 @@ class AbstractHTTPHandler(BaseHandler): 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 @@ class AbstractHTTPHandler(BaseHandler): # 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 AbstractHTTPHandler(BaseHandler): 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 @@ For example usage, see the 'if __name__=="__main__"' block at the end of the 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 @@ Exported functions: """ import re, time, operator -import httplib +import http.client # -------------------------------------------------------------------- # Internal stuff @@ -1196,7 +1196,7 @@ class Transport: 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 @@ class SafeTransport(Transport): 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 @@ server.handle_request() # 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 @@ class SimpleXMLRPCDispatcher: 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 @@ class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """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 @@ class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher): """ 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, |