aboutsummaryrefslogtreecommitdiff
path: root/requests/monkeys.py
blob: c83807112db4d24a2cd35046904def18e0832aa8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#-*- 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