# Set default logging handler to avoid "No handler found" warnings.
import logging
-try:
+try: # Python 2.7+
from logging import NullHandler
except ImportError:
class NullHandler(logging.Handler):
logging.getLogger(__name__).addHandler(NullHandler())
+def add_stderr_logger(level=logging.DEBUG):
+ """
+ Helper for quickly adding a StreamHandler to the logger. Useful for
+ debugging.
+
+ Returns the handler after adding it.
+ """
+ # This method needs to be in this __init__.py to get the __name__ correct
+ # even if urllib3 is vendored within another package.
+ logger = logging.getLogger(__name__)
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
+ logger.addHandler(handler)
+ logger.setLevel(level)
+ logger.debug('Added an stderr logging handler to logger: %s' % __name__)
+ return handler
+
# ... Clean up.
-del logging
del NullHandler
httplib_response = conn.getresponse()
# AppEngine doesn't have a version attr.
- http_version = getattr(conn, '_http_vsn_str', 'HTTP/?'),
+ http_version = getattr(conn, '_http_vsn_str', 'HTTP/?')
log.debug("\"%s %s %s\" %s %s" % (method, url, http_version,
httplib_response.status,
httplib_response.length))
Number of retries to allow before raising a MaxRetryError exception.
:param redirect:
- Automatically handle redirects (status codes 301, 302, 303, 307),
- each redirect counts as a retry.
+ If True, automatically handle redirects (status codes 301, 302,
+ 303, 307). Each redirect counts as a retry.
:param assert_same_host:
If ``True``, will make sure that the host of the pool requests is
('http', 'google.com', 80)
"""
- # This code is actually similar to urlparse.urlsplit, but much
- # simplified for our needs.
- port = None
+ # While this code has overlap with stdlib's urlparse, it is much
+ # simplified for our needs and less annoying.
+ # Additionally, this imeplementations does silly things to be optimal
+ # on CPython.
+
scheme = 'http'
+ host = None
+ port = None
+ # Scheme
if '://' in url:
scheme, url = url.split('://', 1)
# Find the earliest Authority Terminator
- # http://tools.ietf.org/html/rfc3986#section-3.2
+ # (http://tools.ietf.org/html/rfc3986#section-3.2)
url, _path = split_first(url, ['/', '?', '#'])
+ # Auth
if '@' in url:
_auth, url = url.split('@', 1)
+
+ # IPv6
+ if url and url[0] == '[':
+ host, url = url[1:].split(']', 1)
+
+ # Port
if ':' in url:
- url, port = url.split(':', 1)
+ _host, port = url.split(':', 1)
+
+ if not host:
+ host = _host
if not port.isdigit():
raise LocationParseError("Failed to parse: %s" % url)
port = int(port)
- return scheme, url, port
+ elif not host:
+ host = url
+ return scheme, host, port
def is_connection_dropped(conn):