diff --git a/AUTHORS.rst b/AUTHORS.rst index e1835d24..023deb52 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -64,4 +64,5 @@ Patches and Suggestions - Robert Gieseke - Idan Gazit - Ed Summers -- Chris Van Horne \ No newline at end of file +- Chris Van Horne +- Christopher Davis \ No newline at end of file diff --git a/HISTORY.rst b/HISTORY.rst index 4fb77402..d17355ec 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,13 @@ History ------- +0.8.6 (2011-12-18) +++++++++++++++++++ + +* Socket timeout fixes. +* Proxy Authorization support. + + 0.8.5 (2011-12-14) ++++++++++++++++++ diff --git a/Makefile b/Makefile index bb385555..01c10638 100644 --- a/Makefile +++ b/Makefile @@ -13,4 +13,13 @@ stats: site: cd docs; make dirhtml +pyc: + find . -name "*.pyc" -exec rm '{}' ';' + +deps: + rm -fr requests/packages/urllib3 + git clone https://github.com/shazow/urllib3.git + mv urllib3/urllib3 requests/packages/ + rm -fr urllib3 + docs: site diff --git a/requests/__init__.py b/requests/__init__.py index 55f63706..ee3173e1 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -15,8 +15,8 @@ requests """ __title__ = 'requests' -__version__ = '0.8.5' -__build__ = 0x000805 +__version__ = '0.8.6' +__build__ = 0x000806 __author__ = 'Kenneth Reitz' __license__ = 'ISC' __copyright__ = 'Copyright 2011 Kenneth Reitz' diff --git a/requests/auth.py b/requests/auth.py index fad6eb79..4af3d6d3 100644 --- a/requests/auth.py +++ b/requests/auth.py @@ -16,6 +16,12 @@ from urlparse import urlparse from .utils import randombytes, parse_dict_header + +def _basic_auth_str(username, password): + """Returns a Basic Auth string.""" + return 'Basic %s' % b64encode('%s:%s' % (username, password)) + + class AuthBase(object): """Base class that all auth implementations derive from""" @@ -30,8 +36,14 @@ class HTTPBasicAuth(AuthBase): self.password = str(password) def __call__(self, r): - auth_s = b64encode('%s:%s' % (self.username, self.password)) - r.headers['Authorization'] = ('Basic %s' % auth_s) + r.headers['Authorization'] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPProxyAuth(HTTPBasicAuth): + """Attaches HTTP Proxy Authenetication to a given Request object.""" + def __call__(self, r): + r.headers['Proxy-Authorization'] = _basic_auth_str(self.username, self.password) return r @@ -76,8 +88,8 @@ class HTTPDigestAuth(AuthBase): p_parsed = urlparse(r.request.url) path = p_parsed.path + p_parsed.query - A1 = "%s:%s:%s" % (self.username, realm, self.password) - A2 = "%s:%s" % (r.request.method, path) + A1 = '%s:%s:%s' % (self.username, realm, self.password) + A2 = '%s:%s' % (r.request.method, path) if qop == 'auth': if nonce == last_nonce: diff --git a/requests/models.py b/requests/models.py index 78af22c6..e84c8f1a 100644 --- a/requests/models.py +++ b/requests/models.py @@ -17,7 +17,7 @@ from .hooks import dispatch_hook from .structures import CaseInsensitiveDict from .status_codes import codes from .packages import oreos -from .auth import HTTPBasicAuth +from .auth import HTTPBasicAuth, HTTPProxyAuth from .packages.urllib3.exceptions import MaxRetryError from .packages.urllib3.exceptions import SSLError as _SSLError from .packages.urllib3.exceptions import HTTPError as _HTTPError @@ -407,6 +407,12 @@ class Request(object): if proxy: conn = poolmanager.proxy_from_url(proxy) + _proxy = urlparse(proxy) + if '@' in _proxy.netloc: + auth, url = _proxy.netloc.split('@', 1) + self.proxy_auth = HTTPProxyAuth(*auth.split(':', 1)) + r = self.proxy_auth(self) + self.__dict__.update(r.__dict__) else: # Check to see if keep_alive is allowed. if self.config.get('keep_alive'): diff --git a/requests/packages/urllib3/connectionpool.py b/requests/packages/urllib3/connectionpool.py index 8b10dc70..be9b7feb 100644 --- a/requests/packages/urllib3/connectionpool.py +++ b/requests/packages/urllib3/connectionpool.py @@ -210,6 +210,8 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): if timeout is _Default: timeout = self.timeout + conn.timeout = timeout # This only does anything in Py26+ + conn.request(method, url, **httplib_request_kw) conn.sock.settimeout(timeout) httplib_response = conn.getresponse() @@ -244,6 +246,13 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): More commonly, it's appropriate to use a convenience method provided by :class:`.RequestMethods`, such as :meth:`.request`. + .. note:: + + `release_conn` will only behave as expected if + `preload_content=False` because we want to make + `preload_content=False` the default behaviour someday soon without + breaking backwards compatibility. + :param method: HTTP request method (such as GET, POST, PUT, etc.) @@ -279,10 +288,12 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): :param release_conn: If False, then the urlopen call will not release the connection - back into the pool once a response is received. This is useful if - you're not preloading the response's content immediately. You will - need to call ``r.release_conn()`` on the response ``r`` to return - the connection back into the pool. If None, it takes the value of + back into the pool once a response is received (but will release if + you read the entire contents of the response such as when + `preload_content=True`). This is useful if you're not preloading + the response's content immediately. You will need to call + ``r.release_conn()`` on the response ``r`` to return the connection + back into the pool. If None, it takes the value of ``response_kw.get('preload_content', True)``. :param \**response_kw: @@ -295,6 +306,9 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): if retries < 0: raise MaxRetryError("Max retries exceeded for url: %s" % url) + if timeout is _Default: + timeout = self.timeout + if release_conn is None: release_conn = response_kw.get('preload_content', True) @@ -336,10 +350,15 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods): # ``response.release_conn()`` is called (implicitly by # ``response.read()``) - except (SocketTimeout, Empty), e: - # Timed out either by socket or queue - raise TimeoutError("Request timed out after %s seconds" % - self.timeout) + except (Empty), e: + # Timed out by queue + raise TimeoutError("Request timed out. (pool_timeout=%s)" % + pool_timeout) + + except (SocketTimeout), e: + # Timed out by socket + raise TimeoutError("Request timed out. (timeout=%s)" % + timeout) except (BaseSSLError), e: # SSL certificate error @@ -488,10 +507,12 @@ def get_host(url): # simplified for our needs. port = None scheme = 'http' - if '//' in url: + if '://' in url: scheme, url = url.split('://', 1) if '/' in url: url, _path = url.split('/', 1) + if '@' in url: + _auth, url = url.split('@', 1) if ':' in url: url, port = url.split(':', 1) port = int(port)