mirror of
https://github.com/kennethreitz/requests3.git
synced 2026-06-05 23:10:16 +00:00
148 lines
4.5 KiB
Python
148 lines
4.5 KiB
Python
#-*- coding: utf-8 -*-
|
|
|
|
"""
|
|
requests.monkeys
|
|
~~~~~~~~~~~~~~~~
|
|
|
|
Urllib2 Monkey patches.
|
|
|
|
"""
|
|
|
|
import urllib2
|
|
import re
|
|
|
|
class Request(urllib2.Request):
|
|
"""Hidden wrapper around the urllib2.Request object. Allows for manual
|
|
setting of HTTP methods.
|
|
"""
|
|
|
|
def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None):
|
|
urllib2.Request.__init__(self, url, data, headers, origin_req_host, unverifiable)
|
|
self.method = method
|
|
|
|
def get_method(self):
|
|
if self.method:
|
|
return self.method
|
|
|
|
return urllib2.Request.get_method(self)
|
|
|
|
|
|
class HTTPRedirectHandler(urllib2.HTTPRedirectHandler):
|
|
"""HTTP Redirect handler."""
|
|
def http_error_301(self, req, fp, code, msg, headers):
|
|
pass
|
|
|
|
http_error_302 = http_error_303 = http_error_307 = http_error_301
|
|
|
|
|
|
|
|
class HTTPBasicAuthHandler(urllib2.HTTPBasicAuthHandler):
|
|
"""HTTP Basic Auth Handler with authentication loop fixes."""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
urllib2.HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
|
|
self.retried_req = None
|
|
self.retried = 0
|
|
|
|
|
|
def reset_retry_count(self):
|
|
# Python 2.6.5 will call this on 401 or 407 errors and thus loop
|
|
# forever. We disable reset_retry_count completely and reset in
|
|
# http_error_auth_reqed instead.
|
|
pass
|
|
|
|
|
|
def http_error_auth_reqed(self, auth_header, host, req, headers):
|
|
# Reset the retry counter once for each request.
|
|
if req is not self.retried_req:
|
|
self.retried_req = req
|
|
self.retried = 0
|
|
|
|
return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(
|
|
self, auth_header, host, req, headers
|
|
)
|
|
|
|
|
|
|
|
class HTTPForcedBasicAuthHandler(HTTPBasicAuthHandler):
|
|
"""HTTP Basic Auth Handler with forced Authentication."""
|
|
|
|
auth_header = 'Authorization'
|
|
rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+'
|
|
'realm=(["\'])(.*?)\\2', re.I)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
|
|
|
|
|
|
def http_error_401(self, req, fp, code, msg, headers):
|
|
url = req.get_full_url()
|
|
response = self._http_error_auth_reqed('www-authenticate', url, req, headers)
|
|
self.reset_retry_count()
|
|
return response
|
|
|
|
http_error_404 = http_error_401
|
|
|
|
|
|
def _http_error_auth_reqed(self, authreq, host, req, headers):
|
|
|
|
authreq = headers.get(authreq, None)
|
|
|
|
if self.retried > 5:
|
|
# retry sending the username:password 5 times before failing.
|
|
raise urllib2.HTTPError(req.get_full_url(), 401, "basic auth failed",
|
|
headers, None)
|
|
else:
|
|
self.retried += 1
|
|
|
|
if authreq:
|
|
|
|
mo = self.rx.search(authreq)
|
|
|
|
if mo:
|
|
scheme, quote, realm = mo.groups()
|
|
|
|
if scheme.lower() == 'basic':
|
|
response = self.retry_http_basic_auth(host, req, realm)
|
|
|
|
if response and response.code not in (401, 404):
|
|
self.retried = 0
|
|
return response
|
|
else:
|
|
response = self.retry_http_basic_auth(host, req, 'Realm')
|
|
|
|
if response and response.code not in (401, 404):
|
|
self.retried = 0
|
|
return response
|
|
|
|
|
|
|
|
class HTTPDigestAuthHandler(urllib2.HTTPDigestAuthHandler):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
urllib2.HTTPDigestAuthHandler.__init__(self, *args, **kwargs)
|
|
self.retried_req = None
|
|
|
|
def reset_retry_count(self):
|
|
# Python 2.6.5 will call this on 401 or 407 errors and thus loop
|
|
# forever. We disable reset_retry_count completely and reset in
|
|
# http_error_auth_reqed instead.
|
|
pass
|
|
|
|
def http_error_auth_reqed(self, auth_header, host, req, headers):
|
|
# Reset the retry counter once for each request.
|
|
if req is not self.retried_req:
|
|
self.retried_req = req
|
|
self.retried = 0
|
|
# In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
|
|
# it doesn't know about the auth type requested. This can happen if
|
|
# somebody is using BasicAuth and types a bad password.
|
|
|
|
try:
|
|
return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
|
|
self, auth_header, host, req, headers)
|
|
except ValueError, inst:
|
|
arg = inst.args[0]
|
|
if arg.startswith("AbstractDigestAuthHandler doesn't know "):
|
|
return
|
|
raise |