From f7ed34ee0babe65b152f5672d2c4b56dbb14d180 Mon Sep 17 00:00:00 2001 From: Joe Gregorio Date: Mon, 25 Feb 2013 11:08:24 -0500 Subject: Make indents consistent with PEP8. Reviewed in https://codereview.appspot.com/7314118/. --- Makefile | 2 +- python2/httplib2/__init__.py | 322 ++++++++++++++++++++++--------------------- python2/httplib2/iri2uri.py | 40 +++--- python3/httplib2/__init__.py | 294 +++++++++++++++++++-------------------- python3/httplib2/iri2uri.py | 40 +++--- 5 files changed, 351 insertions(+), 347 deletions(-) diff --git a/Makefile b/Makefile index fac0480..45f8851 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ tests: cd python2 && python2.6 httplib2test_appengine.py cd python2 && python2.7 httplib2test.py cd python2 && python2.7 httplib2test_appengine.py - cd python3 && ~/bin/python3.2 httplib2test.py + cd python3 && python3.2 httplib2test.py VERSION = $(shell python setup.py --version) INLINE_VERSION = $(shell cd python2; python -c "import httplib2;print httplib2.__version__") diff --git a/python2/httplib2/__init__.py b/python2/httplib2/__init__.py index 129a980..acca5f2 100644 --- a/python2/httplib2/__init__.py +++ b/python2/httplib2/__init__.py @@ -15,12 +15,12 @@ Changelog: __author__ = "Joe Gregorio (joe@bitworking.org)" __copyright__ = "Copyright 2006, Joe Gregorio" __contributors__ = ["Thomas Broyer (t.broyer@ltgt.net)", - "James Antill", - "Xavier Verges Farrero", - "Jonathan Feinberg", - "Blair Zajac", - "Sam Ruby", - "Louis Nyffenegger"] + "James Antill", + "Xavier Verges Farrero", + "Jonathan Feinberg", + "Blair Zajac", + "Sam Ruby", + "Louis Nyffenegger"] __license__ = "MIT" __version__ = "0.7.7" @@ -102,10 +102,12 @@ def has_timeout(timeout): # python 2.6 return (timeout is not None and timeout is not socket._GLOBAL_DEFAULT_TIMEOUT) return (timeout is not None) -__all__ = ['Http', 'Response', 'ProxyInfo', 'HttpLib2Error', - 'RedirectMissingLocation', 'RedirectLimit', 'FailedToDecompressContent', - 'UnimplementedDigestAuthOptionError', 'UnimplementedHmacDigestAuthOptionError', - 'debuglevel', 'ProxiesUnavailableError'] +__all__ = [ + 'Http', 'Response', 'ProxyInfo', 'HttpLib2Error', 'RedirectMissingLocation', + 'RedirectLimit', 'FailedToDecompressContent', + 'UnimplementedDigestAuthOptionError', + 'UnimplementedHmacDigestAuthOptionError', + 'debuglevel', 'ProxiesUnavailableError'] # The httplib debug level, set to a non-zero value to get debug output @@ -155,10 +157,10 @@ class CertificateValidationUnsupported(HttpLib2Error): pass class SSLHandshakeError(HttpLib2Error): pass class NotSupportedOnThisPlatform(HttpLib2Error): pass class CertificateHostnameMismatch(SSLHandshakeError): - def __init__(self, desc, host, cert): - HttpLib2Error.__init__(self, desc) - self.host = host - self.cert = cert + def __init__(self, desc, host, cert): + HttpLib2Error.__init__(self, desc) + self.host = host + self.cert = cert # Open Items: # ----------- @@ -284,27 +286,29 @@ def _parse_www_authenticate(headers, headername='www-authenticate'): retval = {} if headers.has_key(headername): try: - authenticate = headers[headername].strip() - www_auth = USE_WWW_AUTH_STRICT_PARSING and WWW_AUTH_STRICT or WWW_AUTH_RELAXED - while authenticate: - # Break off the scheme at the beginning of the line - if headername == 'authentication-info': - (auth_scheme, the_rest) = ('digest', authenticate) - else: - (auth_scheme, the_rest) = authenticate.split(" ", 1) - # Now loop over all the key value pairs that come after the scheme, - # being careful not to roll into the next scheme - match = www_auth.search(the_rest) - auth_params = {} - while match: - if match and len(match.groups()) == 3: - (key, value, the_rest) = match.groups() - auth_params[key.lower()] = UNQUOTE_PAIRS.sub(r'\1', value) # '\\'.join([x.replace('\\', '') for x in value.split('\\\\')]) - match = www_auth.search(the_rest) - retval[auth_scheme.lower()] = auth_params - authenticate = the_rest.strip() + + authenticate = headers[headername].strip() + www_auth = USE_WWW_AUTH_STRICT_PARSING and WWW_AUTH_STRICT or WWW_AUTH_RELAXED + while authenticate: + # Break off the scheme at the beginning of the line + if headername == 'authentication-info': + (auth_scheme, the_rest) = ('digest', authenticate) + else: + (auth_scheme, the_rest) = authenticate.split(" ", 1) + # Now loop over all the key value pairs that come after the scheme, + # being careful not to roll into the next scheme + match = www_auth.search(the_rest) + auth_params = {} + while match: + if match and len(match.groups()) == 3: + (key, value, the_rest) = match.groups() + auth_params[key.lower()] = UNQUOTE_PAIRS.sub(r'\1', value) # '\\'.join([x.replace('\\', '') for x in value.split('\\\\')]) + match = www_auth.search(the_rest) + retval[auth_scheme.lower()] = auth_params + authenticate = the_rest.strip() + except ValueError: - raise MalformedHeader("WWW-Authenticate") + raise MalformedHeader("WWW-Authenticate") return retval @@ -520,11 +524,11 @@ class DigestAuthentication(Authentication): KD = lambda s, d: H("%s:%s" % (s, d)) A2 = "".join([method, ":", request_uri]) self.challenge['cnonce'] = cnonce or _cnonce() - request_digest = '"%s"' % KD(H(self.A1), "%s:%s:%s:%s:%s" % (self.challenge['nonce'], - '%08x' % self.challenge['nc'], - self.challenge['cnonce'], - self.challenge['qop'], H(A2) - )) + request_digest = '"%s"' % KD(H(self.A1), "%s:%s:%s:%s:%s" % ( + self.challenge['nonce'], + '%08x' % self.challenge['nc'], + self.challenge['cnonce'], + self.challenge['qop'], H(A2))) headers['authorization'] = 'Digest username="%s", realm="%s", nonce="%s", uri="%s", algorithm=%s, response=%s, qop=%s, nc=%08x, cnonce="%s"' % ( self.credentials[0], self.challenge['realm'], @@ -534,8 +538,7 @@ class DigestAuthentication(Authentication): request_digest, self.challenge['qop'], self.challenge['nc'], - self.challenge['cnonce'], - ) + self.challenge['cnonce']) if self.challenge.get('opaque'): headers['authorization'] += ', opaque="%s"' % self.challenge['opaque'] self.challenge['nc'] += 1 @@ -586,9 +589,8 @@ class HmacDigestAuthentication(Authentication): else: self.pwhashmod = _sha self.key = "".join([self.credentials[0], ":", - self.pwhashmod.new("".join([self.credentials[1], self.challenge['salt']])).hexdigest().lower(), - ":", self.challenge['realm'] - ]) + self.pwhashmod.new("".join([self.credentials[1], self.challenge['salt']])).hexdigest().lower(), + ":", self.challenge['realm']]) self.key = self.pwhashmod.new(self.key).hexdigest().lower() def request(self, method, request_uri, headers, content): @@ -608,8 +610,7 @@ class HmacDigestAuthentication(Authentication): request_uri, created, request_digest, - keylist, - ) + keylist) def response(self, response, content): challenge = _parse_www_authenticate(response, 'www-authenticate').get('hmacdigest', {}) @@ -735,14 +736,14 @@ class KeyCerts(Credentials): pass class AllHosts(object): - pass + pass class ProxyInfo(object): """Collect information required to use a proxy.""" bypass_hosts = () def __init__(self, proxy_type, proxy_host, proxy_port, - proxy_rdns=None, proxy_user=None, proxy_pass=None): + proxy_rdns=None, proxy_user=None, proxy_pass=None): """The parameter proxy_type must be set to one of socks.PROXY_TYPE_XXX constants. For example: @@ -758,7 +759,7 @@ class ProxyInfo(object): def astuple(self): return (self.proxy_type, self.proxy_host, self.proxy_port, - self.proxy_rdns, self.proxy_user, self.proxy_pass) + self.proxy_rdns, self.proxy_user, self.proxy_pass) def isgood(self): return (self.proxy_host != None) and (self.proxy_port != None) @@ -769,12 +770,12 @@ class ProxyInfo(object): def bypass_host(self, hostname): """Has this host been excluded from the proxy config""" if self.bypass_hosts is AllHosts: - return True + return True bypass = False for domain in self.bypass_hosts: - if hostname.endswith(domain): - bypass = True + if hostname.endswith(domain): + bypass = True return bypass @@ -784,21 +785,21 @@ def proxy_info_from_environment(method='http'): Read proxy info from the environment variables. """ if method not in ['http', 'https']: - return + return env_var = method + '_proxy' url = os.environ.get(env_var, os.environ.get(env_var.upper())) if not url: - return + return pi = proxy_info_from_url(url, method) no_proxy = os.environ.get('no_proxy', os.environ.get('NO_PROXY', '')) bypass_hosts = [] if no_proxy: - bypass_hosts = no_proxy.split(',') + bypass_hosts = no_proxy.split(',') # special case, no_proxy=* means all hosts bypassed if no_proxy == '*': - bypass_hosts = AllHosts + bypass_hosts = AllHosts pi.bypass_hosts = bypass_hosts return pi @@ -812,17 +813,17 @@ def proxy_info_from_url(url, method='http'): password = None port = None if '@' in url[1]: - ident, host_port = url[1].split('@', 1) - if ':' in ident: - username, password = ident.split(':', 1) - else: - password = ident + ident, host_port = url[1].split('@', 1) + if ':' in ident: + username, password = ident.split(':', 1) + else: + password = ident else: - host_port = url[1] + host_port = url[1] if ':' in host_port: - host, port = host_port.split(':', 1) + host, port = host_port.split(':', 1) else: - host = host_port + host = host_port if port: port = int(port) @@ -917,12 +918,13 @@ class HTTPSConnectionWithTimeout(httplib.HTTPSConnection): def __init__(self, host, port=None, key_file=None, cert_file=None, strict=None, timeout=None, proxy_info=None, ca_certs=None, disable_ssl_certificate_validation=False): - httplib.HTTPSConnection.__init__(self, host, port=port, key_file=key_file, - cert_file=cert_file, strict=strict) + httplib.HTTPSConnection.__init__(self, host, port=port, + key_file=key_file, + cert_file=cert_file, strict=strict) self.timeout = timeout self.proxy_info = proxy_info if ca_certs is None: - ca_certs = CA_CERTS + ca_certs = CA_CERTS self.ca_certs = ca_certs self.disable_ssl_certificate_validation = \ disable_ssl_certificate_validation @@ -994,8 +996,8 @@ class HTTPSConnectionWithTimeout(httplib.HTTPSConnection): host = self.host port = self.port - for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo( - host, port, 0, socket.SOCK_STREAM): + address_info = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) + for family, socktype, proto, canonname, sockaddr in address_info: try: if use_proxy: sock = socks.socksocket(family, socktype, proto) @@ -1037,83 +1039,84 @@ class HTTPSConnectionWithTimeout(httplib.HTTPSConnection): else: raise except (socket.timeout, socket.gaierror): - raise + raise except socket.error, msg: - if self.debuglevel > 0: - print "connect fail: (%s, %s)" % (self.host, self.port) - if use_proxy: - print "proxy: %s" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass)) - if self.sock: - self.sock.close() - self.sock = None - continue + if self.debuglevel > 0: + print "connect fail: (%s, %s)" % (self.host, self.port) + if use_proxy: + print "proxy: %s" % str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass)) + if self.sock: + self.sock.close() + self.sock = None + continue break if not self.sock: - raise socket.error, msg + raise socket.error, msg SCHEME_TO_CONNECTION = { 'http': HTTPConnectionWithTimeout, 'https': HTTPSConnectionWithTimeout - } +} # Use a different connection object for Google App Engine try: - from google.appengine.api import apiproxy_stub_map - if apiproxy_stub_map.apiproxy.GetStub('urlfetch') is None: - raise ImportError # Bail out; we're not actually running on App Engine. - from google.appengine.api.urlfetch import fetch - from google.appengine.api.urlfetch import InvalidURLError - - def _new_fixed_fetch(validate_certificate): - def fixed_fetch(url, payload=None, method="GET", headers={}, allow_truncated=False, follow_redirects=True, deadline=5): - return fetch(url, payload=payload, method=method, headers=header, allow_truncated=allow_truncated, follow_redirects=follow_redirects, deadline=deadline, validate_certificate=validate_certificate) - return fixed_fetch - - class AppEngineHttpConnection(httplib.HTTPConnection): - """Use httplib on App Engine, but compensate for its weirdness. - - The parameters key_file, cert_file, proxy_info, ca_certs, and - disable_ssl_certificate_validation are all dropped on the ground. - """ - def __init__(self, host, port=None, key_file=None, cert_file=None, - strict=None, timeout=None, proxy_info=None, ca_certs=None, - disable_ssl_certificate_validation=False): - httplib.HTTPConnection.__init__(self, host, port=port, strict=strict, - timeout=timeout) - - class AppEngineHttpsConnection(httplib.HTTPSConnection): - """Same as AppEngineHttpConnection, but for HTTPS URIs.""" - def __init__(self, host, port=None, key_file=None, cert_file=None, - strict=None, timeout=None, proxy_info=None, ca_certs=None, - disable_ssl_certificate_validation=False): - httplib.HTTPSConnection.__init__(self, host, port=port, - key_file=key_file, - cert_file=cert_file, strict=strict, - timeout=timeout) - self._fetch = _new_fixed_fetch(not disable_ssl_certificate_validation) - - # Update the connection classes to use the Googel App Engine specific ones. - SCHEME_TO_CONNECTION = { - 'http': AppEngineHttpConnection, - 'https': AppEngineHttpsConnection - } - + from google.appengine.api import apiproxy_stub_map + if apiproxy_stub_map.apiproxy.GetStub('urlfetch') is None: + raise ImportError # Bail out; we're not actually running on App Engine. + from google.appengine.api.urlfetch import fetch + from google.appengine.api.urlfetch import InvalidURLError + + def _new_fixed_fetch(validate_certificate): + def fixed_fetch(url, payload=None, method="GET", headers={}, allow_truncated=False, follow_redirects=True, deadline=5): + return fetch(url, payload=payload, method=method, headers=header, allow_truncated=allow_truncated, follow_redirects=follow_redirects, deadline=deadline, validate_certificate=validate_certificate) + return fixed_fetch + + class AppEngineHttpConnection(httplib.HTTPConnection): + """Use httplib on App Engine, but compensate for its weirdness. + + The parameters key_file, cert_file, proxy_info, ca_certs, and + disable_ssl_certificate_validation are all dropped on the ground. + """ + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=None, proxy_info=None, ca_certs=None, + disable_ssl_certificate_validation=False): + httplib.HTTPConnection.__init__(self, host, port=port, + strict=strict, timeout=timeout) + + class AppEngineHttpsConnection(httplib.HTTPSConnection): + """Same as AppEngineHttpConnection, but for HTTPS URIs.""" + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=None, proxy_info=None, ca_certs=None, + disable_ssl_certificate_validation=False): + httplib.HTTPSConnection.__init__(self, host, port=port, + key_file=key_file, + cert_file=cert_file, strict=strict, + timeout=timeout) + self._fetch = _new_fixed_fetch( + not disable_ssl_certificate_validation) + + # Update the connection classes to use the Googel App Engine specific ones. + SCHEME_TO_CONNECTION = { + 'http': AppEngineHttpConnection, + 'https': AppEngineHttpsConnection + } except ImportError: - pass + pass class Http(object): """An HTTP client that handles: -- all methods -- caching -- ETags -- compression, -- HTTPS -- Basic -- Digest -- WSSE - -and more. + + - all methods + - caching + - ETags + - compression, + - HTTPS + - Basic + - Digest + - WSSE + + and more. """ def __init__(self, cache=None, timeout=None, proxy_info=proxy_info_from_environment, @@ -1228,7 +1231,7 @@ and more. for i in range(RETRIES): try: if hasattr(conn, 'sock') and conn.sock is None: - conn.connect() + conn.connect() conn.request(method, request_uri, body, headers) except socket.timeout: raise @@ -1365,24 +1368,25 @@ and more. def request(self, uri, method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None): """ Performs a single HTTP request. -The 'uri' is the URI of the HTTP resource and can begin -with either 'http' or 'https'. The value of 'uri' must be an absolute URI. -The 'method' is the HTTP method to perform, such as GET, POST, DELETE, etc. -There is no restriction on the methods allowed. + The 'uri' is the URI of the HTTP resource and can begin with either + 'http' or 'https'. The value of 'uri' must be an absolute URI. -The 'body' is the entity body to be sent with the request. It is a string -object. + The 'method' is the HTTP method to perform, such as GET, POST, DELETE, + etc. There is no restriction on the methods allowed. -Any extra headers that are to be sent with the request should be provided in the -'headers' dictionary. + The 'body' is the entity body to be sent with the request. It is a + string object. -The maximum number of redirect to follow before raising an -exception is 'redirections. The default is 5. + Any extra headers that are to be sent with the request should be + provided in the 'headers' dictionary. -The return value is a tuple of (response, content), the first -being and instance of the 'Response' class, the second being -a string that contains the response entity body. + The maximum number of redirect to follow before raising an + exception is 'redirections. The default is 5. + + The return value is a tuple of (response, content), the first + being and instance of the 'Response' class, the second being + a string that contains the response entity body. """ try: if headers is None: @@ -1408,7 +1412,7 @@ a string that contains the response entity body. conn = self.connections[conn_key] else: if not connection_type: - connection_type = SCHEME_TO_CONNECTION[scheme] + connection_type = SCHEME_TO_CONNECTION[scheme] certs = list(self.certificates.iter(authority)) if scheme == 'https': if certs: @@ -1476,14 +1480,14 @@ a string that contains the response entity body. key = '-varied-%s' % header value = info[key] if headers.get(header, None) != value: - cached_value = None - break + cached_value = None + break if cached_value and method in ["GET", "HEAD"] and self.cache and 'range' not in headers: if info.has_key('-x-permanent-redirect-url'): # Should cached permanent redirects be counted in our redirection count? For now, yes. if redirections <= 0: - raise RedirectLimit("Redirected more times than rediection_limit allows.", {}, "") + raise RedirectLimit("Redirected more times than rediection_limit allows.", {}, "") (response, new_content) = self.request(info['-x-permanent-redirect-url'], "GET", headers = headers, redirections = redirections - 1) response.previous = Response(info) response.previous.fromcache = True @@ -1555,19 +1559,19 @@ a string that contains the response entity body. response.reason = str(e) elif isinstance(e, socket.timeout): content = "Request Timeout" - response = Response( { - "content-type": "text/plain", - "status": "408", - "content-length": len(content) - }) + response = Response({ + "content-type": "text/plain", + "status": "408", + "content-length": len(content) + }) response.reason = "Request Timeout" else: content = str(e) - response = Response( { - "content-type": "text/plain", - "status": "400", - "content-length": len(content) - }) + response = Response({ + "content-type": "text/plain", + "status": "400", + "content-length": len(content) + }) response.reason = "Bad Request" else: raise diff --git a/python2/httplib2/iri2uri.py b/python2/httplib2/iri2uri.py index e4cda1d..d88c91f 100644 --- a/python2/httplib2/iri2uri.py +++ b/python2/httplib2/iri2uri.py @@ -28,26 +28,26 @@ import urlparse # / %xD0000-DFFFD / %xE1000-EFFFD escape_range = [ - (0xA0, 0xD7FF ), - (0xE000, 0xF8FF ), - (0xF900, 0xFDCF ), - (0xFDF0, 0xFFEF), - (0x10000, 0x1FFFD ), - (0x20000, 0x2FFFD ), - (0x30000, 0x3FFFD), - (0x40000, 0x4FFFD ), - (0x50000, 0x5FFFD ), - (0x60000, 0x6FFFD), - (0x70000, 0x7FFFD ), - (0x80000, 0x8FFFD ), - (0x90000, 0x9FFFD), - (0xA0000, 0xAFFFD ), - (0xB0000, 0xBFFFD ), - (0xC0000, 0xCFFFD), - (0xD0000, 0xDFFFD ), - (0xE1000, 0xEFFFD), - (0xF0000, 0xFFFFD ), - (0x100000, 0x10FFFD) + (0xA0, 0xD7FF), + (0xE000, 0xF8FF), + (0xF900, 0xFDCF), + (0xFDF0, 0xFFEF), + (0x10000, 0x1FFFD), + (0x20000, 0x2FFFD), + (0x30000, 0x3FFFD), + (0x40000, 0x4FFFD), + (0x50000, 0x5FFFD), + (0x60000, 0x6FFFD), + (0x70000, 0x7FFFD), + (0x80000, 0x8FFFD), + (0x90000, 0x9FFFD), + (0xA0000, 0xAFFFD), + (0xB0000, 0xBFFFD), + (0xC0000, 0xCFFFD), + (0xD0000, 0xDFFFD), + (0xE1000, 0xEFFFD), + (0xF0000, 0xFFFFD), + (0x100000, 0x10FFFD), ] def encode(c): diff --git a/python3/httplib2/__init__.py b/python3/httplib2/__init__.py index fb63594..bf6c2e9 100644 --- a/python3/httplib2/__init__.py +++ b/python3/httplib2/__init__.py @@ -3,7 +3,7 @@ httplib2 A caching http interface that supports ETags and gzip -to conserve bandwidth. +to conserve bandwidth. Requires Python 3.0 or later @@ -26,8 +26,8 @@ __contributors__ = ["Thomas Broyer (t.broyer@ltgt.net)", __license__ = "MIT" __version__ = "0.7.7" -import re -import sys +import re +import sys import email import email.utils import email.message @@ -64,9 +64,10 @@ def has_timeout(timeout): return (timeout is not None) __all__ = ['Http', 'Response', 'ProxyInfo', 'HttpLib2Error', - 'RedirectMissingLocation', 'RedirectLimit', 'FailedToDecompressContent', - 'UnimplementedDigestAuthOptionError', 'UnimplementedHmacDigestAuthOptionError', - 'debuglevel', 'RETRIES'] + 'RedirectMissingLocation', 'RedirectLimit', + 'FailedToDecompressContent', 'UnimplementedDigestAuthOptionError', + 'UnimplementedHmacDigestAuthOptionError', + 'debuglevel', 'RETRIES'] # The httplib debug level, set to a non-zero value to get debug output @@ -78,8 +79,8 @@ RETRIES = 2 # All exceptions raised here derive from HttpLib2Error class HttpLib2Error(Exception): pass -# Some exceptions can be caught and optionally -# be turned back into responses. +# Some exceptions can be caught and optionally +# be turned back into responses. class HttpLib2ErrorWithResponse(HttpLib2Error): def __init__(self, desc, response, content): self.response = response @@ -147,7 +148,7 @@ def urlnorm(uri): raise RelativeURIError("Only absolute URIs are allowed. uri = %s" % uri) authority = authority.lower() scheme = scheme.lower() - if not path: + if not path: path = "/" # Could do syntax based normalization of the URI before # computing the digest. See Section 6.2.2 of Std 66. @@ -200,7 +201,7 @@ def _parse_cache_control(headers): parts_with_args = [tuple([x.strip().lower() for x in part.split("=", 1)]) for part in parts if -1 != part.find("=")] parts_wo_args = [(name.strip().lower(), 1) for name in parts if -1 == name.find("=")] retval = dict(parts_with_args + parts_wo_args) - return retval + return retval # Whether to use a strict mode to parse WWW-Authenticate headers # Might lead to bad results in case of ill-formed header value, @@ -222,27 +223,27 @@ def _parse_www_authenticate(headers, headername='www-authenticate'): retval = {} if headername in headers: try: - authenticate = headers[headername].strip() - www_auth = USE_WWW_AUTH_STRICT_PARSING and WWW_AUTH_STRICT or WWW_AUTH_RELAXED - while authenticate: - # Break off the scheme at the beginning of the line - if headername == 'authentication-info': - (auth_scheme, the_rest) = ('digest', authenticate) - else: - (auth_scheme, the_rest) = authenticate.split(" ", 1) - # Now loop over all the key value pairs that come after the scheme, - # being careful not to roll into the next scheme - match = www_auth.search(the_rest) - auth_params = {} - while match: - if match and len(match.groups()) == 3: - (key, value, the_rest) = match.groups() - auth_params[key.lower()] = UNQUOTE_PAIRS.sub(r'\1', value) # '\\'.join([x.replace('\\', '') for x in value.split('\\\\')]) - match = www_auth.search(the_rest) - retval[auth_scheme.lower()] = auth_params - authenticate = the_rest.strip() + authenticate = headers[headername].strip() + www_auth = USE_WWW_AUTH_STRICT_PARSING and WWW_AUTH_STRICT or WWW_AUTH_RELAXED + while authenticate: + # Break off the scheme at the beginning of the line + if headername == 'authentication-info': + (auth_scheme, the_rest) = ('digest', authenticate) + else: + (auth_scheme, the_rest) = authenticate.split(" ", 1) + # Now loop over all the key value pairs that come after the scheme, + # being careful not to roll into the next scheme + match = www_auth.search(the_rest) + auth_params = {} + while match: + if match and len(match.groups()) == 3: + (key, value, the_rest) = match.groups() + auth_params[key.lower()] = UNQUOTE_PAIRS.sub(r'\1', value) # '\\'.join([x.replace('\\', '') for x in value.split('\\\\')]) + match = www_auth.search(the_rest) + retval[auth_scheme.lower()] = auth_params + authenticate = the_rest.strip() except ValueError: - raise MalformedHeader("WWW-Authenticate") + raise MalformedHeader("WWW-Authenticate") return retval @@ -254,17 +255,17 @@ def _entry_disposition(response_headers, request_headers): 1. Cache-Control: max-stale 2. Age: headers are not used in the calculations. - Not that this algorithm is simpler than you might think + Not that this algorithm is simpler than you might think because we are operating as a private (non-shared) cache. This lets us ignore 's-maxage'. We can also ignore 'proxy-invalidate' since we aren't a proxy. - We will never return a stale document as - fresh as a design decision, and thus the non-implementation - of 'max-stale'. This also lets us safely ignore 'must-revalidate' + We will never return a stale document as + fresh as a design decision, and thus the non-implementation + of 'max-stale'. This also lets us safely ignore 'must-revalidate' since we operate as if every server has sent 'must-revalidate'. Since we are private we get to ignore both 'public' and 'private' parameters. We also ignore 'no-transform' since - we don't do any transformations. + we don't do any transformations. The 'no-store' parameter is handled at a higher level. So the only Cache-Control parameters we look at are: @@ -273,7 +274,7 @@ def _entry_disposition(response_headers, request_headers): max-age min-fresh """ - + retval = "STALE" cc = _parse_cache_control(request_headers) cc_response = _parse_cache_control(response_headers) @@ -315,10 +316,10 @@ def _entry_disposition(response_headers, request_headers): min_fresh = int(cc['min-fresh']) except ValueError: min_fresh = 0 - current_age += min_fresh + current_age += min_fresh if freshness_lifetime > current_age: retval = "FRESH" - return retval + return retval def _decompressContent(response, new_content): content = new_content @@ -386,10 +387,10 @@ def _updateCache(request_headers, response_headers, content, cache, cachekey): status_header = 'status: %d\r\n' % status try: - header_str = info.as_string() + header_str = info.as_string() except UnicodeEncodeError: - setattr(info, '_write_headers', _bind_write_headers(info)) - header_str = info.as_string() + setattr(info, '_write_headers', _bind_write_headers(info)) + header_str = info.as_string() header_str = re.sub("\r(?!\n)|(?