~bzr-pqm/bzr/bzr.dev

3825.1.2 by Martin Pool
Merge 1.9final and its sftp fixes
1
# Copyright (C) 2006, 2007, 2008 Canonical Ltd
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
16
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
17
"""Implementaion of urllib2 tailored to bzr needs
18
2363.4.7 by Vincent Ladeuil
Deeper tests, prepare the auth setting that will avoid the
19
This file complements the urllib2 class hierarchy with custom classes.
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
20
21
For instance, we create a new HTTPConnection and HTTPSConnection that inherit
22
from the original urllib2.HTTP(s)Connection objects, but also have a new base
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
23
which implements a custom getresponse and cleanup_pipe handlers.
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
24
25
And then we implement custom HTTPHandler and HTTPSHandler classes, that use
26
the custom HTTPConnection classes.
27
28
We have a custom Response class, which lets us maintain a keep-alive
29
connection even for requests that urllib2 doesn't expect to contain body data.
30
2363.4.10 by Vincent Ladeuil
Complete tests.
31
And a custom Request class that lets us track redirections, and
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
32
handle authentication schemes.
3430.1.1 by Vincent Ladeuil
Fix bug #229076 by fixing header names before sending the request.
33
34
For coherency with python libraries, we use capitalized header names throughout
35
the code, even if the header names will be titled just before sending the
36
request (see AbstractHTTPHandler.do_open).
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
37
"""
38
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
39
DEBUG = 0
40
41
# FIXME: Oversimplifying, two kind of exceptions should be
42
# raised, once a request is issued: URLError before we have been
43
# able to process the response, HTTPError after that. Process the
44
# response means we are able to leave the socket clean, so if we
45
# are not able to do that, we should close the connection. The
46
# actual code more or less do that, tests should be written to
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
47
# ensure that.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
48
4628.1.2 by Vincent Ladeuil
More complete fix.
49
import errno
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
50
import httplib
4011.3.5 by Jelmer Vernooij
Move import next to other system libs, fix format.
51
try:
52
    import kerberos
53
except ImportError:
54
    have_kerberos = False
55
else:
56
    have_kerberos = True
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
57
import socket
58
import urllib
59
import urllib2
60
import urlparse
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
61
import re
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
62
import sys
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
63
import time
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
64
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
65
from bzrlib import __version__ as bzrlib_version
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
66
from bzrlib import (
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
67
    config,
3052.3.3 by Vincent Ladeuil
Add -Dhttp support.
68
    debug,
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
69
    errors,
2929.3.1 by Vincent Ladeuil
Fix python2.6 deprecation warnings (still 4 failures 5 errors in test suite).
70
    osutils,
3052.3.3 by Vincent Ladeuil
Add -Dhttp support.
71
    trace,
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
72
    transport,
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
73
    ui,
74
    )
75
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
76
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
77
class _ReportingFileSocket(object):
78
79
    def __init__(self, filesock, report_activity=None):
80
        self.filesock = filesock
81
        self._report_activity = report_activity
82
83
84
    def read(self, size=1):
85
        s = self.filesock.read(size)
86
        self._report_activity(len(s), 'read')
87
        return s
88
3988.2.1 by Vincent Ladeuil
Workaround SSLFile wrong readline prototype and fix bogus tests.
89
    def readline(self):
90
        # This should be readline(self, size=-1), but httplib in python 2.4 and
91
        #  2.5 defines a SSLFile wrapper whose readline method lacks the size
92
        #  parameter.  So until we drop support for 2.4 and 2.5 and since we
93
        #  don't *need* the size parameter we'll stay with readline(self)
94
        #  --  vila 20090209
95
        s = self.filesock.readline()
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
96
        self._report_activity(len(s), 'read')
97
        return s
98
99
    def __getattr__(self, name):
100
        return getattr(self.filesock, name)
101
102
103
class _ReportingSocket(object):
104
105
    def __init__(self, sock, report_activity=None):
3287.3.3 by Andrew Bennetts
A slightly neater hack for forcing buffering, thanks to John.
106
        self.sock = sock
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
107
        self._report_activity = report_activity
108
109
    def sendall(self, s, *args):
4105.1.1 by Andrew Bennetts
Clean-up _ReportingSocket.send/sendall slightly.
110
        self.sock.sendall(s, *args)
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
111
        self._report_activity(len(s), 'write')
112
113
    def recv(self, *args):
114
        s = self.sock.recv(*args)
115
        self._report_activity(len(s), 'read')
116
        return s
3287.3.3 by Andrew Bennetts
A slightly neater hack for forcing buffering, thanks to John.
117
118
    def makefile(self, mode='r', bufsize=-1):
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
119
        # httplib creates a fileobject that doesn't do buffering, which
120
        # makes fp.readline() very expensive because it only reads one byte
121
        # at a time.  So we wrap the socket in an object that forces
122
        # sock.makefile to make a buffered file.
123
        fsock = self.sock.makefile(mode, 65536)
124
        # And wrap that into a reporting kind of fileobject
125
        return _ReportingFileSocket(fsock, self._report_activity)
3287.3.3 by Andrew Bennetts
A slightly neater hack for forcing buffering, thanks to John.
126
127
    def __getattr__(self, name):
128
        return getattr(self.sock, name)
129
130
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
131
# We define our own Response class to keep our httplib pipe clean
132
class Response(httplib.HTTPResponse):
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
133
    """Custom HTTPResponse, to avoid the need to decorate.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
134
135
    httplib prefers to decorate the returned objects, rather
136
    than using a custom object.
137
    """
138
2004.1.7 by vila
Better handling of passwords (user should be queried only once).
139
    # Some responses have bodies in which we have no interest
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
140
    _body_ignored_responses = [301,302, 303, 307, 401, 403, 404]
2004.1.7 by vila
Better handling of passwords (user should be queried only once).
141
3146.3.4 by Vincent Ladeuil
Review feedback, simpler loops.
142
    # in finish() below, we may have to discard several MB in the worst
143
    # case. To avoid buffering that much, we read and discard by chunks
144
    # instead. The underlying file is either a socket or a StringIO, so reading
145
    # 8k chunks should be fine.
146
    _discarded_buf_size = 8192
147
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
148
    def begin(self):
149
        """Begin to read the response from the server.
150
151
        httplib assumes that some responses get no content and do
152
        not even attempt to read the body in that case, leaving
153
        the body in the socket, blocking the next request. Let's
154
        try to workaround that.
155
        """
2004.1.2 by vila
Implements a BasicAuthManager.
156
        httplib.HTTPResponse.begin(self)
2004.1.7 by vila
Better handling of passwords (user should be queried only once).
157
        if self.status in self._body_ignored_responses:
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
158
            if self.debuglevel >= 2:
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
159
                print "For status: [%s]," % self.status,
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
160
                print "will ready body, length: %s" % self.length
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
161
            if not (self.length is None or self.will_close):
162
                # In some cases, we just can't read the body not
163
                # even try or we may encounter a 104, 'Connection
164
                # reset by peer' error if there is indeed no body
165
                # and the server closed the connection just after
166
                # having issued the response headers (even if the
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
167
                # headers indicate a Content-Type...)
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
168
                body = self.read(self.length)
169
                if self.debuglevel >= 9:
3024.2.3 by Vincent Ladeuil
Rewrite http_readv to allow several GET requests. Smoke tested against branch reported in the bug.
170
                    # This one can be huge and is generally not interesting
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
171
                    print "Consumed body: [%s]" % body
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
172
            self.close()
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
173
        elif self.status == 200:
174
            # Whatever the request is, it went ok, so we surely don't want to
175
            # close the connection. Some cases are not correctly detected by
176
            # httplib.HTTPConnection.getresponse (called by
177
            # httplib.HTTPResponse.begin). The CONNECT response for the https
2955.2.1 by Vincent Ladeuil
Fix #160012 by leaving the http pipeline related exceptions raise.
178
            # through proxy case is one.  Note: the 'will_close' below refers
179
            # to the "true" socket between us and the server, whereas the
180
            # 'close()' above refers to the copy of that socket created by
181
            # httplib for the response itself. So, in the if above we close the
182
            # socket to indicate that we are done with the response whereas
183
            # below we keep the socket with the server opened.
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
184
            self.will_close = False
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
185
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
186
    def finish(self):
3059.2.11 by Vincent Ladeuil
Fix typos mentioned by spiv.
187
        """Finish reading the body.
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
188
3059.2.11 by Vincent Ladeuil
Fix typos mentioned by spiv.
189
        In some cases, the client may have left some bytes to read in the
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
190
        body. That will block the next request to succeed if we use a
3059.2.11 by Vincent Ladeuil
Fix typos mentioned by spiv.
191
        persistent connection. If we don't use a persistent connection, well,
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
192
        nothing will block the next request since a new connection will be
193
        issued anyway.
3104.3.3 by Vincent Ladeuil
Jam's and Aaron feedback about bug #175886.
194
195
        :return: the number of bytes left on the socket (may be None)
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
196
        """
3104.3.3 by Vincent Ladeuil
Jam's and Aaron feedback about bug #175886.
197
        pending = None
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
198
        if not self.isclosed():
199
            # Make sure nothing was left to be read on the socket
3104.3.1 by Vincent Ladeuil
Fix #175886 by reading remaining bytes by chunks.
200
            pending = 0
3146.3.2 by Vincent Ladeuil
Fix #179368 by keeping the current range hint on ShortReadvErrors.
201
            data = True
3146.3.4 by Vincent Ladeuil
Review feedback, simpler loops.
202
            while data and self.length:
203
                # read() will update self.length
204
                data = self.read(min(self.length, self._discarded_buf_size))
3104.3.1 by Vincent Ladeuil
Fix #175886 by reading remaining bytes by chunks.
205
                pending += len(data)
206
            if pending:
3146.3.2 by Vincent Ladeuil
Fix #179368 by keeping the current range hint on ShortReadvErrors.
207
                trace.mutter("%s bytes left on the HTTP socket", pending)
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
208
            self.close()
3104.3.3 by Vincent Ladeuil
Jam's and Aaron feedback about bug #175886.
209
        return pending
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
210
2004.1.2 by vila
Implements a BasicAuthManager.
211
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
212
# Not inheriting from 'object' because httplib.HTTPConnection doesn't.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
213
class AbstractHTTPConnection:
214
    """A custom HTTP(S) Connection, which can reset itself on a bad response"""
215
216
    response_class = Response
217
3104.3.3 by Vincent Ladeuil
Jam's and Aaron feedback about bug #175886.
218
    # When we detect a server responding with the whole file to range requests,
219
    # we want to warn. But not below a given thresold.
220
    _range_warning_thresold = 1024 * 1024
221
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
222
    def __init__(self,
223
                 report_activity=None):
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
224
        self._response = None
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
225
        self._report_activity = report_activity
3104.3.3 by Vincent Ladeuil
Jam's and Aaron feedback about bug #175886.
226
        self._ranges_received_whole_file = None
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
227
228
    def _mutter_connect(self):
3104.3.4 by Vincent Ladeuil
Add test.
229
        netloc = '%s:%s' % (self.host, self.port)
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
230
        if self.proxied_host is not None:
231
            netloc += '(proxy for %s)' % self.proxied_host
232
        trace.mutter('* About to connect() to %s' % netloc)
233
234
    def getresponse(self):
235
        """Capture the response to be able to cleanup"""
236
        self._response = httplib.HTTPConnection.getresponse(self)
237
        return self._response
238
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
239
    def cleanup_pipe(self):
3111.1.24 by Vincent Ladeuil
Cleanups.
240
        """Read the remaining bytes of the last response if any."""
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
241
        if self._response is not None:
3104.3.3 by Vincent Ladeuil
Jam's and Aaron feedback about bug #175886.
242
            pending = self._response.finish()
3104.3.5 by Vincent Ladeuil
Fix typo.
243
            # Warn the user (once)
3104.3.3 by Vincent Ladeuil
Jam's and Aaron feedback about bug #175886.
244
            if (self._ranges_received_whole_file is None
245
                and self._response.status == 200
246
                and pending and pending > self._range_warning_thresold
247
                ):
248
                self._ranges_received_whole_file = True
249
                trace.warning(
250
                    'Got a 200 response when asking for multiple ranges,'
251
                    ' does your server at %s:%s support range requests?',
252
                    self.host, self.port)
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
253
            self._response = None
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
254
        # Preserve our preciousss
255
        sock = self.sock
256
        self.sock = None
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
257
        # Let httplib.HTTPConnection do its housekeeping
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
258
        self.close()
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
259
        # Restore our preciousss
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
260
        self.sock = sock
261
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
262
    def _wrap_socket_for_reporting(self, sock):
263
        """Wrap the socket before anybody use it."""
264
        self.sock = _ReportingSocket(sock, self._report_activity)
265
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
266
267
class HTTPConnection(AbstractHTTPConnection, httplib.HTTPConnection):
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
268
269
    # XXX: Needs refactoring at the caller level.
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
270
    def __init__(self, host, port=None, proxied_host=None,
271
                 report_activity=None):
272
        AbstractHTTPConnection.__init__(self, report_activity=report_activity)
2929.3.9 by Vincent Ladeuil
Don't pretend we support HTTP/0.9 since we don't and do that correctly.
273
        # Use strict=True since we don't support HTTP/0.9
274
        httplib.HTTPConnection.__init__(self, host, port, strict=True)
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
275
        self.proxied_host = proxied_host
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
276
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
277
    def connect(self):
278
        if 'http' in debug.debug_flags:
279
            self._mutter_connect()
280
        httplib.HTTPConnection.connect(self)
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
281
        self._wrap_socket_for_reporting(self.sock)
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
282
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
283
3815.2.3 by Martin Pool
merge fix for #293054, ssl on python2.6
284
# Build the appropriate socket wrapper for ssl
285
try:
3823.1.3 by Vincent Ladeuil
Fixed as per John's review.
286
    # python 2.6 introduced a better ssl package
287
    import ssl
3815.2.3 by Martin Pool
merge fix for #293054, ssl on python2.6
288
    _ssl_wrap_socket = ssl.wrap_socket
289
except ImportError:
3823.1.3 by Vincent Ladeuil
Fixed as per John's review.
290
    # python versions prior to 2.6 don't have ssl and ssl.wrap_socket instead
291
    # they use httplib.FakeSocket
3815.2.3 by Martin Pool
merge fix for #293054, ssl on python2.6
292
    def _ssl_wrap_socket(sock, key_file, cert_file):
293
        ssl_sock = socket.ssl(sock, key_file, cert_file)
294
        return httplib.FakeSocket(sock, ssl_sock)
295
296
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
297
class HTTPSConnection(AbstractHTTPConnection, httplib.HTTPSConnection):
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
298
299
    def __init__(self, host, port=None, key_file=None, cert_file=None,
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
300
                 proxied_host=None,
301
                 report_activity=None):
302
        AbstractHTTPConnection.__init__(self, report_activity=report_activity)
2929.3.9 by Vincent Ladeuil
Don't pretend we support HTTP/0.9 since we don't and do that correctly.
303
        # Use strict=True since we don't support HTTP/0.9
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
304
        httplib.HTTPSConnection.__init__(self, host, port,
2929.3.9 by Vincent Ladeuil
Don't pretend we support HTTP/0.9 since we don't and do that correctly.
305
                                         key_file, cert_file, strict=True)
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
306
        self.proxied_host = proxied_host
307
308
    def connect(self):
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
309
        if 'http' in debug.debug_flags:
310
            self._mutter_connect()
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
311
        httplib.HTTPConnection.connect(self)
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
312
        self._wrap_socket_for_reporting(self.sock)
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
313
        if self.proxied_host is None:
314
            self.connect_to_origin()
315
316
    def connect_to_origin(self):
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
317
        ssl_sock = _ssl_wrap_socket(self.sock, self.key_file, self.cert_file)
318
        # Wrap the ssl socket before anybody use it
319
        self._wrap_socket_for_reporting(ssl_sock)
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
320
321
322
class Request(urllib2.Request):
323
    """A custom Request object.
324
325
    urllib2 determines the request method heuristically (based on
326
    the presence or absence of data). We set the method
327
    statically.
328
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
329
    The Request object tracks:
330
    - the connection the request will be made on.
331
    - the authentication parameters needed to preventively set
332
      the authentication header once a first authentication have
333
       been made.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
334
    """
335
336
    def __init__(self, method, url, data=None, headers={},
337
                 origin_req_host=None, unverifiable=False,
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
338
                 connection=None, parent=None,
339
                 accepted_errors=None):
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
340
        urllib2.Request.__init__(self, url, data, headers,
341
                                 origin_req_host, unverifiable)
342
        self.method = method
343
        self.connection = connection
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
344
        self.accepted_errors = accepted_errors
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
345
        # To handle redirections
346
        self.parent = parent
347
        self.redirected_to = None
2164.2.15 by Vincent Ladeuil
Http redirections are not followed by default. Do not use hints
348
        # Unless told otherwise, redirections are not followed
349
        self.follow_redirections = False
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
350
        # auth and proxy_auth are dicts containing, at least
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
351
        # (scheme, host, port, realm, user, password, protocol, path).
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
352
        # The dict entries are mostly handled by the AuthHandler.
353
        # Some authentication schemes may add more entries.
354
        self.auth = {}
355
        self.proxy_auth = {}
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
356
        self.proxied_host = None
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
357
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
358
    def get_method(self):
359
        return self.method
360
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
361
    def set_proxy(self, proxy, type):
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
362
        """Set the proxy and remember the proxied host."""
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
363
        self.proxied_host = self.get_host()
364
        urllib2.Request.set_proxy(self, proxy, type)
365
366
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
367
class _ConnectRequest(Request):
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
368
369
    def __init__(self, request):
370
        """Constructor
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
371
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
372
        :param request: the first request sent to the proxied host, already
373
            processed by the opener (i.e. proxied_host is already set).
374
        """
375
        # We give a fake url and redefine get_selector or urllib2 will be
376
        # confused
377
        Request.__init__(self, 'CONNECT', request.get_full_url(),
378
                         connection=request.connection)
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
379
        if request.proxied_host is None:
380
            raise AssertionError()
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
381
        self.proxied_host = request.proxied_host
382
383
    def get_selector(self):
384
        return self.proxied_host
385
386
    def set_proxy(self, proxy, type):
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
387
        """Set the proxy without remembering the proxied host.
388
389
        We already know the proxied host by definition, the CONNECT request
390
        occurs only when the connection goes through a proxy. The usual
391
        processing (masquerade the request so that the connection is done to
392
        the proxy while the request is targeted at another host) does not apply
393
        here. In fact, the connection is already established with proxy and we
394
        just want to enable the SSL tunneling.
395
        """
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
396
        urllib2.Request.set_proxy(self, proxy, type)
397
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
398
399
class ConnectionHandler(urllib2.BaseHandler):
400
    """Provides connection-sharing by pre-processing requests.
401
402
    urllib2 provides no way to access the HTTPConnection object
403
    internally used. But we need it in order to achieve
404
    connection sharing. So, we add it to the request just before
405
    it is processed, and then we override the do_open method for
2363.4.7 by Vincent Ladeuil
Deeper tests, prepare the auth setting that will avoid the
406
    http[s] requests in AbstractHTTPHandler.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
407
    """
408
409
    handler_order = 1000 # after all pre-processings
410
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
411
    def __init__(self, report_activity=None):
412
        self._report_activity = report_activity
413
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
414
    def create_connection(self, request, http_connection_class):
415
        host = request.get_host()
416
        if not host:
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
417
            # Just a bit of paranoia here, this should have been
418
            # handled in the higher levels
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
419
            raise errors.InvalidURL(request.get_full_url(), 'no host given.')
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
420
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
421
        # We create a connection (but it will not connect until the first
422
        # request is made)
2004.1.42 by v.ladeuil+lp at free
Fix #70803 by catching the httplib exception.
423
        try:
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
424
            connection = http_connection_class(
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
425
                host, proxied_host=request.proxied_host,
426
                report_activity=self._report_activity)
2004.1.42 by v.ladeuil+lp at free
Fix #70803 by catching the httplib exception.
427
        except httplib.InvalidURL, exception:
428
            # There is only one occurrence of InvalidURL in httplib
429
            raise errors.InvalidURL(request.get_full_url(),
430
                                    extra='nonnumeric port')
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
431
432
        return connection
433
434
    def capture_connection(self, request, http_connection_class):
435
        """Capture or inject the request connection.
436
437
        Two cases:
438
        - the request have no connection: create a new one,
439
440
        - the request have a connection: this one have been used
441
          already, let's capture it, so that we can give it to
442
          another transport to be reused. We don't do that
443
          ourselves: the Transport object get the connection from
444
          a first request and then propagate it, from request to
445
          request or to cloned transports.
446
        """
447
        connection = request.connection
448
        if connection is None:
449
            # Create a new one
450
            connection = self.create_connection(request, http_connection_class)
451
            request.connection = connection
452
453
        # All connections will pass here, propagate debug level
454
        connection.set_debuglevel(DEBUG)
455
        return request
456
457
    def http_request(self, request):
458
        return self.capture_connection(request, HTTPConnection)
459
460
    def https_request(self, request):
461
        return self.capture_connection(request, HTTPSConnection)
462
463
464
class AbstractHTTPHandler(urllib2.AbstractHTTPHandler):
465
    """A custom handler for HTTP(S) requests.
466
467
    We overrive urllib2.AbstractHTTPHandler to get a better
468
    control of the connection, the ability to implement new
469
    request types and return a response able to cope with
470
    persistent connections.
471
    """
472
473
    # We change our order to be before urllib2 HTTP[S]Handlers
2004.3.1 by vila
Test ConnectionError exceptions.
474
    # and be chosen instead of them (the first http_open called
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
475
    # wins).
476
    handler_order = 400
477
478
    _default_headers = {'Pragma': 'no-cache',
479
                        'Cache-control': 'max-age=0',
480
                        'Connection': 'Keep-Alive',
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
481
                        'User-agent': 'bzr/%s (urllib)' % bzrlib_version,
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
482
                        'Accept': '*/*',
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
483
                        }
484
485
    def __init__(self):
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
486
        urllib2.AbstractHTTPHandler.__init__(self, debuglevel=DEBUG)
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
487
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
488
    def http_request(self, request):
489
        """Common headers setting"""
490
491
        request.headers.update(self._default_headers.copy())
492
        # FIXME: We may have to add the Content-Length header if
493
        # we have data to send.
494
        return request
495
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
496
    def retry_or_raise(self, http_class, request, first_try):
497
        """Retry the request (once) or raise the exception.
2004.3.1 by vila
Test ConnectionError exceptions.
498
499
        urllib2 raises exception of application level kind, we
500
        just have to translate them.
501
502
        httplib can raise exceptions of transport level (badly
503
        formatted dialog, loss of connexion or socket level
504
        problems). In that case we should issue the request again
505
        (httplib will close and reopen a new connection if
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
506
        needed).
507
        """
508
        # When an exception occurs, we give back the original
509
        # Traceback or the bugs are hard to diagnose.
510
        exc_type, exc_val, exc_tb = sys.exc_info()
511
        if exc_type == socket.gaierror:
512
            # No need to retry, that will not help
513
            raise errors.ConnectionError("Couldn't resolve host '%s'"
514
                                         % request.get_origin_req_host(),
515
                                         orig_error=exc_val)
2955.2.1 by Vincent Ladeuil
Fix #160012 by leaving the http pipeline related exceptions raise.
516
        elif isinstance(exc_val, httplib.ImproperConnectionState):
517
            # The httplib pipeline is in incorrect state, it's a bug in our
518
            # implementation.
519
            raise exc_type, exc_val, exc_tb
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
520
        else:
521
            if first_try:
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
522
                if self._debuglevel >= 2:
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
523
                    print 'Received exception: [%r]' % exc_val
524
                    print '  On connection: [%r]' % request.connection
525
                    method = request.get_method()
526
                    url = request.get_full_url()
527
                    print '  Will retry, %s %r' % (method, url)
528
                request.connection.close()
529
                response = self.do_open(http_class, request, False)
530
            else:
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
531
                if self._debuglevel >= 2:
2004.1.39 by v.ladeuil+lp at free
Fix a race condition that make selftest fail once in a while.
532
                    print 'Received second exception: [%r]' % exc_val
533
                    print '  On connection: [%r]' % request.connection
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
534
                if exc_type in (httplib.BadStatusLine, httplib.UnknownProtocol):
535
                    # httplib.BadStatusLine and
536
                    # httplib.UnknownProtocol indicates that a
537
                    # bogus server was encountered or a bad
538
                    # connection (i.e. transient errors) is
539
                    # experimented, we have already retried once
540
                    # for that request so we raise the exception.
541
                    my_exception = errors.InvalidHttpResponse(
542
                        request.get_full_url(),
543
                        'Bad status line received',
544
                        orig_error=exc_val)
4628.1.2 by Vincent Ladeuil
More complete fix.
545
                elif (isinstance(exc_val, socket.error) and len(exc_val.args)
546
                      and exc_val.args[0] in (errno.ECONNRESET, 10054)):
547
                    raise errors.ConnectionReset(
548
                        "Connection lost while sending request.")
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
549
                else:
550
                    # All other exception are considered connection related.
551
552
                    # socket errors generally occurs for reasons
553
                    # far outside our scope, so closing the
554
                    # connection and retrying is the best we can
555
                    # do.
556
557
                    my_exception = errors.ConnectionError(
558
                        msg= 'while sending %s %s:' % (request.get_method(),
559
                                                       request.get_selector()),
560
                        orig_error=exc_val)
561
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
562
                if self._debuglevel >= 2:
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
563
                    print 'On connection: [%r]' % request.connection
564
                    method = request.get_method()
565
                    url = request.get_full_url()
566
                    print '  Failed again, %s %r' % (method, url)
567
                    print '  Will raise: [%r]' % my_exception
568
                raise my_exception, None, exc_tb
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
569
        return response
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
570
571
    def do_open(self, http_class, request, first_try=True):
572
        """See urllib2.AbstractHTTPHandler.do_open for the general idea.
573
574
        The request will be retried once if it fails.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
575
        """
576
        connection = request.connection
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
577
        if connection is None:
578
            raise AssertionError(
579
                'Cannot process a request without a connection')
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
580
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
581
        # Get all the headers
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
582
        headers = {}
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
583
        headers.update(request.header_items())
584
        headers.update(request.unredirected_hdrs)
3430.1.1 by Vincent Ladeuil
Fix bug #229076 by fixing header names before sending the request.
585
        # Some servers or proxies will choke on headers not properly
586
        # cased. httplib/urllib/urllib2 all use capitalize to get canonical
587
        # header names, but only python2.5 urllib2 use title() to fix them just
588
        # before sending the request. And not all versions of python 2.5 do
589
        # that. Since we replace urllib2.AbstractHTTPHandler.do_open we do it
590
        # ourself below.
3430.1.2 by Vincent Ladeuil
Fixed as per Matt Nordhoff review.
591
        headers = dict((name.title(), val) for name, val in headers.iteritems())
2004.3.1 by vila
Test ConnectionError exceptions.
592
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
593
        try:
3052.3.3 by Vincent Ladeuil
Add -Dhttp support.
594
            method = request.get_method()
595
            url = request.get_selector()
596
            connection._send_request(method, url,
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
597
                                     # FIXME: implements 100-continue
598
                                     #None, # We don't send the body yet
599
                                     request.get_data(),
600
                                     headers)
3052.3.3 by Vincent Ladeuil
Add -Dhttp support.
601
            if 'http' in debug.debug_flags:
602
                trace.mutter('> %s %s' % (method, url))
603
                hdrs = ['%s: %s' % (k, v) for k,v in headers.items()]
604
                trace.mutter('> ' + '\n> '.join(hdrs) + '\n')
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
605
            if self._debuglevel >= 1:
606
                print 'Request sent: [%r] from (%s)' \
607
                    % (request, request.connection.sock.getsockname())
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
608
            response = connection.getresponse()
609
            convert_to_addinfourl = True
2004.1.37 by v.ladeuil+lp at free
Small refactoring.
610
        except (socket.gaierror, httplib.BadStatusLine, httplib.UnknownProtocol,
611
                socket.error, httplib.HTTPException):
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
612
            response = self.retry_or_raise(http_class, request, first_try)
613
            convert_to_addinfourl = False
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
614
615
# FIXME: HTTPConnection does not fully support 100-continue (the
616
# server responses are just ignored)
617
618
#        if code == 100:
619
#            mutter('Will send the body')
620
#            # We can send the body now
621
#            body = request.get_data()
622
#            if body is None:
623
#                raise URLError("No data given")
624
#            connection.send(body)
625
#            response = connection.getresponse()
626
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
627
        if self._debuglevel >= 2:
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
628
            print 'Receives response: %r' % response
629
            print '  For: %r(%r)' % (request.get_method(),
630
                                     request.get_full_url())
631
632
        if convert_to_addinfourl:
633
            # Shamelessly copied from urllib2
634
            req = request
635
            r = response
636
            r.recv = r.read
3287.3.2 by Andrew Bennetts
Buffer 64k, rather than just 8k.
637
            fp = socket._fileobject(r, bufsize=65536)
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
638
            resp = urllib2.addinfourl(fp, r.msg, req.get_full_url())
639
            resp.code = r.status
640
            resp.msg = r.reason
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
641
            resp.version = r.version
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
642
            if self._debuglevel >= 2:
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
643
                print 'Create addinfourl: %r' % resp
644
                print '  For: %r(%r)' % (request.get_method(),
645
                                         request.get_full_url())
3059.2.5 by Vincent Ladeuil
DAMN^64, the http test server is 1.0 not 1.1 :( Better pipe cleaning and less readv caching (since that's the point of the whole fix).
646
            if 'http' in debug.debug_flags:
647
                version = 'HTTP/%d.%d'
648
                try:
649
                    version = version % (resp.version / 10,
650
                                         resp.version % 10)
651
                except:
652
                    version = 'HTTP/%r' % resp.version
653
                trace.mutter('< %s %s %s' % (version, resp.code,
654
                                             resp.msg))
655
                # Use the raw header lines instead of treating resp.info() as a
656
                # dict since we may miss duplicated headers otherwise.
657
                hdrs = [h.rstrip('\r\n') for h in resp.info().headers]
658
                trace.mutter('< ' + '\n< '.join(hdrs) + '\n')
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
659
        else:
660
            resp = response
661
        return resp
662
663
664
class HTTPHandler(AbstractHTTPHandler):
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
665
    """A custom handler that just thunks into HTTPConnection"""
666
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
667
    def http_open(self, request):
668
        return self.do_open(HTTPConnection, request)
669
670
671
class HTTPSHandler(AbstractHTTPHandler):
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
672
    """A custom handler that just thunks into HTTPSConnection"""
673
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
674
    https_request = AbstractHTTPHandler.http_request
675
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
676
    def https_open(self, request):
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
677
        connection = request.connection
678
        if connection.sock is None and \
679
                connection.proxied_host is not None and \
680
                request.get_method() != 'CONNECT' : # Don't loop
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
681
            # FIXME: We need a gazillion connection tests here, but we still
682
            # miss a https server :-( :
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
683
            # - with and without proxy
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
684
            # - with and without certificate
685
            # - with self-signed certificate
686
            # - with and without authentication
2929.3.9 by Vincent Ladeuil
Don't pretend we support HTTP/0.9 since we don't and do that correctly.
687
            # - with good and bad credentials (especially the proxy auth around
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
688
            #   CONNECT)
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
689
            # - with basic and digest schemes
690
            # - reconnection on errors
691
            # - connection persistence behaviour (including reconnection)
692
693
            # We are about to connect for the first time via a proxy, we must
694
            # issue a CONNECT request first to establish the encrypted link
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
695
            connect = _ConnectRequest(request)
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
696
            response = self.parent.open(connect)
697
            if response.code != 200:
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
698
                raise ConnectionError("Can't connect to %s via proxy %s" % (
699
                        connect.proxied_host, self.host))
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
700
            # Housekeeping
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
701
            connection.cleanup_pipe()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
702
            # Establish the connection encryption
2540.2.1 by Vincent Ladeuil
Rough, working, tested against squid+apache in basic auth fix for #120678
703
            connection.connect_to_origin()
704
            # Propagate the connection to the original request
705
            request.connection = connection
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
706
        return self.do_open(HTTPSConnection, request)
707
708
class HTTPRedirectHandler(urllib2.HTTPRedirectHandler):
709
    """Handles redirect requests.
710
711
    We have to implement our own scheme because we use a specific
712
    Request object and because we want to implement a specific
713
    policy.
714
    """
715
    _debuglevel = DEBUG
716
    # RFC2616 says that only read requests should be redirected
717
    # without interacting with the user. But bzr use some
718
    # shortcuts to optimize against roundtrips which can leads to
719
    # write requests being issued before read requests of
720
    # containing dirs can be redirected. So we redirect write
721
    # requests in the same way which seems to respect the spirit
722
    # of the RFC if not its letter.
723
724
    def redirect_request(self, req, fp, code, msg, headers, newurl):
725
        """See urllib2.HTTPRedirectHandler.redirect_request"""
726
        # We would have preferred to update the request instead
727
        # of creating a new one, but the urllib2.Request object
728
        # has a too complicated creation process to provide a
729
        # simple enough equivalent update process. Instead, when
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
730
        # redirecting, we only update the following request in
731
        # the redirect chain with a reference to the parent
732
        # request .
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
733
2164.2.1 by v.ladeuil+lp at free
First rough http branch redirection implementation.
734
        # Some codes make no sense in our context and are treated
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
735
        # as errors:
736
737
        # 300: Multiple choices for different representations of
738
        #      the URI. Using that mechanisn with bzr will violate the
739
        #      protocol neutrality of Transport.
740
741
        # 304: Not modified (SHOULD only occurs with conditional
742
        #      GETs which are not used by our implementation)
743
744
        # 305: Use proxy. I can't imagine this one occurring in
745
        #      our context-- vila/20060909
746
747
        # 306: Unused (if the RFC says so...)
748
2164.2.1 by v.ladeuil+lp at free
First rough http branch redirection implementation.
749
        # If the code is 302 and the request is HEAD, some may
750
        # think that it is a sufficent hint that the file exists
751
        # and that we MAY avoid following the redirections. But
752
        # if we want to be sure, we MUST follow them.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
753
754
        if code in (301, 302, 303, 307):
755
            return Request(req.get_method(),newurl,
756
                           headers = req.headers,
757
                           origin_req_host = req.get_origin_req_host(),
758
                           unverifiable = True,
759
                           # TODO: It will be nice to be able to
760
                           # detect virtual hosts sharing the same
761
                           # IP address, that will allow us to
762
                           # share the same connection...
763
                           connection = None,
764
                           parent = req,
765
                           )
766
        else:
767
            raise urllib2.HTTPError(req.get_full_url(), code, msg, headers, fp)
768
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
769
    def http_error_302(self, req, fp, code, msg, headers):
2004.3.1 by vila
Test ConnectionError exceptions.
770
        """Requests the redirected to URI.
771
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
772
        Copied from urllib2 to be able to clean the pipe of the associated
773
        connection, *before* issuing the redirected request but *after* having
774
        eventually raised an error.
2004.3.1 by vila
Test ConnectionError exceptions.
775
        """
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
776
        # Some servers (incorrectly) return multiple Location headers
777
        # (so probably same goes for URI).  Use first header.
778
779
        # TODO: Once we get rid of addinfourl objects, the
780
        # following will need to be updated to use correct case
781
        # for headers.
782
        if 'location' in headers:
783
            newurl = headers.getheaders('location')[0]
784
        elif 'uri' in headers:
785
            newurl = headers.getheaders('uri')[0]
786
        else:
787
            return
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
788
        if self._debuglevel >= 1:
2164.2.1 by v.ladeuil+lp at free
First rough http branch redirection implementation.
789
            print 'Redirected to: %s (followed: %r)' % (newurl,
790
                                                        req.follow_redirections)
791
        if req.follow_redirections is False:
792
            req.redirected_to = newurl
793
            return fp
794
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
795
        newurl = urlparse.urljoin(req.get_full_url(), newurl)
796
797
        # This call succeeds or raise an error. urllib2 returns
798
        # if redirect_request returns None, but our
799
        # redirect_request never returns None.
800
        redirected_req = self.redirect_request(req, fp, code, msg, headers,
801
                                               newurl)
802
803
        # loop detection
804
        # .redirect_dict has a key url if url was previously visited.
805
        if hasattr(req, 'redirect_dict'):
806
            visited = redirected_req.redirect_dict = req.redirect_dict
807
            if (visited.get(newurl, 0) >= self.max_repeats or
808
                len(visited) >= self.max_redirections):
809
                raise urllib2.HTTPError(req.get_full_url(), code,
810
                                        self.inf_msg + msg, headers, fp)
811
        else:
812
            visited = redirected_req.redirect_dict = req.redirect_dict = {}
813
        visited[newurl] = visited.get(newurl, 0) + 1
814
815
        # We can close the fp now that we are sure that we won't
816
        # use it with HTTPError.
817
        fp.close()
818
        # We have all we need already in the response
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
819
        req.connection.cleanup_pipe()
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
820
821
        return self.parent.open(redirected_req)
822
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
823
    http_error_301 = http_error_303 = http_error_307 = http_error_302
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
824
825
2167.3.1 by v.ladeuil+lp at free
Fix bug #74759.
826
class ProxyHandler(urllib2.ProxyHandler):
827
    """Handles proxy setting.
828
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
829
    Copied and modified from urllib2 to be able to modify the request during
830
    the request pre-processing instead of modifying it at _open time. As we
831
    capture (or create) the connection object during request processing, _open
832
    time was too late.
833
834
    The main task is to modify the request so that the connection is done to
835
    the proxy while the request still refers to the destination host.
836
837
    Note: the proxy handling *may* modify the protocol used; the request may be
838
    against an https server proxied through an http proxy. So, https_request
839
    will be called, but later it's really http_open that will be called. This
2540.2.3 by Vincent Ladeuil
Take Aaron's comments into account.
840
    explains why we don't have to call self.parent.open as the urllib2 did.
2167.3.1 by v.ladeuil+lp at free
Fix bug #74759.
841
    """
842
843
    # Proxies must be in front
844
    handler_order = 100
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
845
    _debuglevel = DEBUG
2167.3.1 by v.ladeuil+lp at free
Fix bug #74759.
846
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
847
    def __init__(self, proxies=None):
2167.3.1 by v.ladeuil+lp at free
Fix bug #74759.
848
        urllib2.ProxyHandler.__init__(self, proxies)
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
849
        # First, let's get rid of urllib2 implementation
2167.3.1 by v.ladeuil+lp at free
Fix bug #74759.
850
        for type, proxy in self.proxies.items():
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
851
            if self._debuglevel >= 3:
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
852
                print 'Will unbind %s_open for %r' % (type, proxy)
2167.3.1 by v.ladeuil+lp at free
Fix bug #74759.
853
            delattr(self, '%s_open' % type)
854
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
855
        # We are interested only by the http[s] proxies
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
856
        http_proxy = self.get_proxy_env_var('http')
857
        https_proxy = self.get_proxy_env_var('https')
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
858
859
        if http_proxy is not None:
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
860
            if self._debuglevel >= 3:
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
861
                print 'Will bind http_request for %r' % http_proxy
862
            setattr(self, 'http_request',
863
                    lambda request: self.set_proxy(request, 'http'))
864
865
        if https_proxy is not None:
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
866
            if self._debuglevel >= 3:
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
867
                print 'Will bind http_request for %r' % https_proxy
868
            setattr(self, 'https_request',
869
                    lambda request: self.set_proxy(request, 'https'))
870
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
871
    def get_proxy_env_var(self, name, default_to='all'):
872
        """Get a proxy env var.
873
2182.1.1 by Aaron Bentley
Respect proxy environment settings (Vincent Ladeuil, #74759)
874
        Note that we indirectly rely on
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
875
        urllib.getproxies_environment taking into account the
876
        uppercased values for proxy variables.
877
        """
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
878
        try:
879
            return self.proxies[name.lower()]
880
        except KeyError:
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
881
            if default_to is not None:
882
                # Try to get the alternate environment variable
883
                try:
884
                    return self.proxies[default_to]
885
                except KeyError:
886
                    pass
887
        return None
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
888
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
889
    def proxy_bypass(self, host):
890
        """Check if host should be proxied or not"""
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
891
        no_proxy = self.get_proxy_env_var('no', default_to=None)
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
892
        if no_proxy is None:
893
            return False
894
        hhost, hport = urllib.splitport(host)
2182.1.1 by Aaron Bentley
Respect proxy environment settings (Vincent Ladeuil, #74759)
895
        # Does host match any of the domains mentioned in
896
        # no_proxy ? The rules about what is authorized in no_proxy
897
        # are fuzzy (to say the least). We try to allow most
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
898
        # commonly seen values.
899
        for domain in no_proxy.split(','):
900
            dhost, dport = urllib.splitport(domain)
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
901
            if hport == dport or dport is None:
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
902
                # Protect glob chars
903
                dhost = dhost.replace(".", r"\.")
904
                dhost = dhost.replace("*", r".*")
905
                dhost = dhost.replace("?", r".")
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
906
                if re.match(dhost, hhost, re.IGNORECASE):
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
907
                    return True
2182.1.1 by Aaron Bentley
Respect proxy environment settings (Vincent Ladeuil, #74759)
908
        # Nevertheless, there are platform-specific ways to
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
909
        # ignore proxies...
910
        return urllib.proxy_bypass(host)
911
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
912
    def set_proxy(self, request, type):
2167.3.4 by v.ladeuil+lp at free
Better fix for #74759, but still not tests.
913
        if self.proxy_bypass(request.get_host()):
914
            return request
915
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
916
        proxy = self.get_proxy_env_var(type)
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
917
        if self._debuglevel >= 3:
2167.3.3 by v.ladeuil+lp at free
* bzrlib/transport/http/_urllib2_wrappers.py:
918
            print 'set_proxy %s_request for %r' % (type, proxy)
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
919
        # FIXME: python 2.5 urlparse provides a better _parse_proxy which can
920
        # grok user:password@host:port as well as
921
        # http://user:password@host:port
922
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
923
        (scheme, user, password,
924
         host, port, path) = transport.ConnectedTransport._split_url(proxy)
4294.2.9 by Robert Collins
Fixup tests broken by cleaning up the layering.
925
        if not host:
926
            raise errors.InvalidURL(proxy, 'No host component')
2900.2.15 by Vincent Ladeuil
AuthenticationConfig can be queried for logins too (first step).
927
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
928
        if request.proxy_auth == {}:
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
929
            # No proxy auth parameter are available, we are handling the first
930
            # proxied request, intialize.  scheme (the authentication scheme)
931
            # and realm will be set by the AuthHandler
932
            request.proxy_auth = {
933
                                  'host': host, 'port': port,
934
                                  'user': user, 'password': password,
935
                                  'protocol': scheme,
936
                                   # We ignore path since we connect to a proxy
937
                                  'path': None}
938
        if port is None:
939
            phost = host
940
        else:
941
            phost = host + ':%d' % port
942
        request.set_proxy(phost, type)
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
943
        if self._debuglevel >= 3:
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
944
            print 'set_proxy: proxy set to %s://%s' % (type, phost)
2167.3.1 by v.ladeuil+lp at free
Fix bug #74759.
945
        return request
946
947
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
948
class AbstractAuthHandler(urllib2.BaseHandler):
949
    """A custom abstract authentication handler for all http authentications.
950
951
    Provides the meat to handle authentication errors and
952
    preventively set authentication headers after the first
953
    successful authentication.
954
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
955
    This can be used for http and proxy, as well as for basic, negotiate and
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
956
    digest authentications.
957
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
958
    This provides an unified interface for all authentication handlers
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
959
    (urllib2 provides far too many with different policies).
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
960
961
    The interaction between this handler and the urllib2
962
    framework is not obvious, it works as follow:
963
964
    opener.open(request) is called:
965
966
    - that may trigger http_request which will add an authentication header
967
      (self.build_header) if enough info is available.
968
969
    - the request is sent to the server,
970
971
    - if an authentication error is received self.auth_required is called,
972
      we acquire the authentication info in the error headers and call
973
      self.auth_match to check that we are able to try the
974
      authentication and complete the authentication parameters,
975
976
    - we call parent.open(request), that may trigger http_request
977
      and will add a header (self.build_header), but here we have
978
      all the required info (keep in mind that the request and
979
      authentication used in the recursive calls are really (and must be)
980
      the *same* objects).
981
982
    - if the call returns a response, the authentication have been
983
      successful and the request authentication parameters have been updated.
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
984
    """
985
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
986
    scheme = None
987
    """The scheme as it appears in the server header (lower cased)"""
988
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
989
    _max_retry = 3
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
990
    """We don't want to retry authenticating endlessly"""
991
4050.2.3 by Vincent Ladeuil
Slight cosmetic tweaks.
992
    requires_username = True
993
    """Whether the auth mechanism requires a username."""
994
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
995
    # The following attributes should be defined by daughter
996
    # classes:
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
997
    # - auth_required_header:  the header received from the server
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
998
    # - auth_header: the header sent in the request
999
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1000
    def __init__(self):
1001
        # We want to know when we enter into an try/fail cycle of
1002
        # authentications so we initialize to None to indicate that we aren't
1003
        # in such a cycle by default.
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
1004
        self._retry_count = None
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1005
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
1006
    def _parse_auth_header(self, server_header):
1007
        """Parse the authentication header.
1008
1009
        :param server_header: The value of the header sent by the server
1010
            describing the authenticaion request.
1011
1012
        :return: A tuple (scheme, remainder) scheme being the first word in the
1013
            given header (lower cased), remainder may be None.
1014
        """
1015
        try:
1016
            scheme, remainder = server_header.split(None, 1)
1017
        except ValueError:
1018
            scheme = server_header
1019
            remainder = None
1020
        return (scheme.lower(), remainder)
1021
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1022
    def update_auth(self, auth, key, value):
1023
        """Update a value in auth marking the auth as modified if needed"""
1024
        old_value = auth.get(key, None)
1025
        if old_value != value:
1026
            auth[key] = value
1027
            auth['modified'] = True
1028
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1029
    def auth_required(self, request, headers):
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1030
        """Retry the request if the auth scheme is ours.
1031
1032
        :param request: The request needing authentication.
1033
        :param headers: The headers for the authentication error response.
1034
        :return: None or the response for the authenticated request.
1035
        """
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
1036
        # Don't try  to authenticate endlessly
1037
        if self._retry_count is None:
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1038
            # The retry being recusrsive calls, None identify the first retry
1039
            self._retry_count = 1
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
1040
        else:
1041
            self._retry_count += 1
1042
            if self._retry_count > self._max_retry:
1043
                # Let's be ready for next round
1044
                self._retry_count = None
1045
                return None
4307.4.2 by Vincent Ladeuil
Handle servers proposing several authentication schemes.
1046
        server_headers = headers.getheaders(self.auth_required_header)
1047
        if not server_headers:
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1048
            # The http error MUST have the associated
1049
            # header. This must never happen in production code.
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1050
            raise KeyError('%s not found' % self.auth_required_header)
1051
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1052
        auth = self.get_auth(request)
1053
        auth['modified'] = False
4307.4.2 by Vincent Ladeuil
Handle servers proposing several authentication schemes.
1054
        # FIXME: the auth handler should be selected at a single place instead
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
1055
        # of letting all handlers try to match all headers, but the current
1056
        # design doesn't allow a simple implementation.
4307.4.2 by Vincent Ladeuil
Handle servers proposing several authentication schemes.
1057
        for server_header in server_headers:
1058
            # Several schemes can be proposed by the server, try to match each
1059
            # one in turn
1060
            matching_handler = self.auth_match(server_header, auth)
1061
            if matching_handler:
1062
                # auth_match may have modified auth (by adding the
1063
                # password or changing the realm, for example)
1064
                if (request.get_header(self.auth_header, None) is not None
1065
                    and not auth['modified']):
1066
                    # We already tried that, give up
1067
                    return None
1068
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
1069
                # Only the most secure scheme proposed by the server should be
1070
                # used, since the handlers use 'handler_order' to describe that
1071
                # property, the first handler tried takes precedence, the
1072
                # others should not attempt to authenticate if the best one
1073
                # failed.
1074
                best_scheme = auth.get('best_scheme', None)
1075
                if best_scheme is None:
1076
                    # At that point, if current handler should doesn't succeed
1077
                    # the credentials are wrong (or incomplete), but we know
1078
                    # that the associated scheme should be used.
1079
                    best_scheme = auth['best_scheme'] = self.scheme
1080
                if  best_scheme != self.scheme:
1081
                    continue
1082
4307.4.2 by Vincent Ladeuil
Handle servers proposing several authentication schemes.
1083
                if self.requires_username and auth.get('user', None) is None:
1084
                    # Without a known user, we can't authenticate
1085
                    return None
1086
1087
                # Housekeeping
1088
                request.connection.cleanup_pipe()
1089
                # Retry the request with an authentication header added
1090
                response = self.parent.open(request)
1091
                if response:
1092
                    self.auth_successful(request, response)
1093
                return response
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1094
        # We are not qualified to handle the authentication.
1095
        # Note: the authentication error handling will try all
1096
        # available handlers. If one of them authenticates
1097
        # successfully, a response will be returned. If none of
1098
        # them succeeds, None will be returned and the error
1099
        # handler will raise the 401 'Unauthorized' or the 407
1100
        # 'Proxy Authentication Required' error.
1101
        return None
1102
1103
    def add_auth_header(self, request, header):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1104
        """Add the authentication header to the request"""
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1105
        request.add_unredirected_header(self.auth_header, header)
1106
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1107
    def auth_match(self, header, auth):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1108
        """Check that we are able to handle that authentication scheme.
1109
1110
        The request authentication parameters may need to be
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1111
        updated with info from the server. Some of these
1112
        parameters, when combined, are considered to be the
1113
        authentication key, if one of them change the
1114
        authentication result may change. 'user' and 'password'
1115
        are exampls, but some auth schemes may have others
1116
        (digest's nonce is an example, digest's nonce_count is a
1117
        *counter-example*). Such parameters must be updated by
1118
        using the update_auth() method.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1119
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1120
        :param header: The authentication header sent by the server.
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1121
        :param auth: The auth parameters already known. They may be
1122
             updated.
1123
        :returns: True if we can try to handle the authentication.
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1124
        """
1125
        raise NotImplementedError(self.auth_match)
1126
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1127
    def build_auth_header(self, auth, request):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1128
        """Build the value of the header used to authenticate.
1129
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1130
        :param auth: The auth parameters needed to build the header.
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1131
        :param request: The request needing authentication.
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1132
1133
        :return: None or header.
1134
        """
1135
        raise NotImplementedError(self.build_auth_header)
1136
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1137
    def auth_successful(self, request, response):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1138
        """The authentification was successful for the request.
1139
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1140
        Additional infos may be available in the response.
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1141
1142
        :param request: The succesfully authenticated request.
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1143
        :param response: The server response (may contain auth info).
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1144
        """
2540.2.2 by Vincent Ladeuil
Fix #120678 by issuing a CONNECT request when https is used via a proxy.
1145
        # It may happen that we need to reconnect later, let's be ready
1146
        self._retry_count = None
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1147
2900.2.20 by Vincent Ladeuil
http can query AuthenticationConfig for logins too.
1148
    def get_user_password(self, auth):
3910.2.3 by Ben Jansen
Made tweaks requested by John Arbash Meinel.
1149
        """Ask user for a password if none is already available.
1150
3910.2.4 by Vincent Ladeuil
Fixed as per John's review.
1151
        :param auth: authentication info gathered so far (from the initial url
1152
            and then during dialog with the server).
3910.2.3 by Ben Jansen
Made tweaks requested by John Arbash Meinel.
1153
        """
2900.2.20 by Vincent Ladeuil
http can query AuthenticationConfig for logins too.
1154
        auth_conf = config.AuthenticationConfig()
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1155
        user = auth['user']
1156
        password = auth['password']
2900.2.20 by Vincent Ladeuil
http can query AuthenticationConfig for logins too.
1157
        realm = auth['realm']
1158
1159
        if user is None:
3910.2.1 by Ben Jansen
Changed HTTP transport auth so that URLs no longer need to include the username for HTTP Auth to work. Now, if bzr gets a 401 HTTP response, it looks in the authentication config for an appropriate username and password. If it doesn't find a username, it defaults to the local user. If it doesn't find a password, it prompts.
1160
            user = auth_conf.get_user(auth['protocol'], auth['host'],
3910.2.2 by Vincent Ladeuil
Fix bug #300347 by allowing querying authentication.conf if no
1161
                                      port=auth['port'], path=auth['path'],
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1162
                                      realm=realm, ask=True,
1163
                                      prompt=self.build_username_prompt(auth))
3910.2.2 by Vincent Ladeuil
Fix bug #300347 by allowing querying authentication.conf if no
1164
        if user is not None and password is None:
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1165
            password = auth_conf.get_password(
1166
                auth['protocol'], auth['host'], user, port=auth['port'],
1167
                path=auth['path'], realm=realm,
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1168
                prompt=self.build_password_prompt(auth))
2900.2.20 by Vincent Ladeuil
http can query AuthenticationConfig for logins too.
1169
1170
        return user, password
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1171
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1172
    def _build_password_prompt(self, auth):
1173
        """Build a prompt taking the protocol used into account.
1174
1175
        The AuthHandler is used by http and https, we want that information in
1176
        the prompt, so we build the prompt from the authentication dict which
1177
        contains all the needed parts.
1178
3133.1.3 by Vincent Ladeuil
Fix typo (hi John ;).
1179
        Also, http and proxy AuthHandlers present different prompts to the
3133.1.2 by Vincent Ladeuil
Fix #177643 by making pycurl handle url-embedded credentials again.
1180
        user. The daughter classes should implements a public
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1181
        build_password_prompt using this method.
1182
        """
1183
        prompt = '%s' % auth['protocol'].upper() + ' %(user)s@%(host)s'
1184
        realm = auth['realm']
1185
        if realm is not None:
1186
            prompt += ", Realm: '%s'" % realm
1187
        prompt += ' password'
1188
        return prompt
1189
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1190
    def _build_username_prompt(self, auth):
1191
        """Build a prompt taking the protocol used into account.
1192
1193
        The AuthHandler is used by http and https, we want that information in
1194
        the prompt, so we build the prompt from the authentication dict which
1195
        contains all the needed parts.
1196
1197
        Also, http and proxy AuthHandlers present different prompts to the
1198
        user. The daughter classes should implements a public
1199
        build_username_prompt using this method.
1200
        """
1201
        prompt = '%s' % auth['protocol'].upper() + ' %(host)s'
1202
        realm = auth['realm']
1203
        if realm is not None:
1204
            prompt += ", Realm: '%s'" % realm
1205
        prompt += ' username'
1206
        return prompt
1207
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1208
    def http_request(self, request):
1209
        """Insert an authentication header if information is available"""
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1210
        auth = self.get_auth(request)
1211
        if self.auth_params_reusable(auth):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1212
            self.add_auth_header(request, self.build_auth_header(auth, request))
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1213
        return request
1214
1215
    https_request = http_request # FIXME: Need test
1216
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1217
1218
class NegotiateAuthHandler(AbstractAuthHandler):
1219
    """A authentication handler that handles WWW-Authenticate: Negotiate.
1220
4032.1.4 by John Arbash Meinel
Found 2 more files with trailing whitespace.
1221
    At the moment this handler supports just Kerberos. In the future,
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1222
    NTLM support may also be added.
1223
    """
1224
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
1225
    scheme = 'negotiate'
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1226
    handler_order = 480
4017.5.1 by Jelmer Vernooij
Allow HTTP authentication handlers (such as the NegotiateAuthHandler) to
1227
    requires_username = False
1228
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1229
    def auth_match(self, header, auth):
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
1230
        scheme, raw_auth = self._parse_auth_header(header)
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
1231
        if scheme != self.scheme:
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1232
            return False
1233
        self.update_auth(auth, 'scheme', scheme)
4011.3.2 by Jelmer Vernooij
Only attempt GSSAPI authentication when the kerberos module is present.
1234
        resp = self._auth_match_kerberos(auth)
1235
        if resp is None:
1236
            return False
1237
        # Optionally should try to authenticate using NTLM here
1238
        self.update_auth(auth, 'negotiate_response', resp)
1239
        return True
1240
1241
    def _auth_match_kerberos(self, auth):
1242
        """Try to create a GSSAPI response for authenticating against a host."""
4011.3.4 by Jelmer Vernooij
review from vila: mention HTTPS, clarify error a bit, move import to top-level.
1243
        if not have_kerberos:
4011.3.2 by Jelmer Vernooij
Only attempt GSSAPI authentication when the kerberos module is present.
1244
            return None
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1245
        ret, vc = kerberos.authGSSClientInit("HTTP@%(host)s" % auth)
1246
        if ret < 1:
4011.3.5 by Jelmer Vernooij
Move import next to other system libs, fix format.
1247
            trace.warning('Unable to create GSSAPI context for %s: %d',
1248
                auth['host'], ret)
4011.3.2 by Jelmer Vernooij
Only attempt GSSAPI authentication when the kerberos module is present.
1249
            return None
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1250
        ret = kerberos.authGSSClientStep(vc, "")
1251
        if ret < 0:
1252
            trace.mutter('authGSSClientStep failed: %d', ret)
4011.3.2 by Jelmer Vernooij
Only attempt GSSAPI authentication when the kerberos module is present.
1253
            return None
1254
        return kerberos.authGSSClientResponse(vc)
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1255
1256
    def build_auth_header(self, auth, request):
4011.3.2 by Jelmer Vernooij
Only attempt GSSAPI authentication when the kerberos module is present.
1257
        return "Negotiate %s" % auth['negotiate_response']
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1258
1259
    def auth_params_reusable(self, auth):
1260
        # If the auth scheme is known, it means a previous
1261
        # authentication was successful, all information is
1262
        # available, no further checks are needed.
4032.1.4 by John Arbash Meinel
Found 2 more files with trailing whitespace.
1263
        return (auth.get('scheme', None) == 'negotiate' and
4011.3.4 by Jelmer Vernooij
review from vila: mention HTTPS, clarify error a bit, move import to top-level.
1264
                auth.get('negotiate_response', None) is not None)
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1265
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1266
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1267
class BasicAuthHandler(AbstractAuthHandler):
1268
    """A custom basic authentication handler."""
1269
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
1270
    scheme = 'basic'
2545.2.1 by Vincent Ladeuil
Fix 121889 by working around urllib2 bug.
1271
    handler_order = 500
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1272
    auth_regexp = re.compile('realm="([^"]*)"', re.I)
1273
1274
    def build_auth_header(self, auth, request):
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1275
        raw = '%s:%s' % (auth['user'], auth['password'])
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1276
        auth_header = 'Basic ' + raw.encode('base64').strip()
1277
        return auth_header
1278
4284.1.1 by Vincent Ladeuil
Fix wrong realm extraction in http basic authentication (reported
1279
    def extract_realm(self, header_value):
1280
        match = self.auth_regexp.search(header_value)
1281
        realm = None
1282
        if match:
1283
            realm = match.group(1)
1284
        return match, realm
1285
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1286
    def auth_match(self, header, auth):
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
1287
        scheme, raw_auth = self._parse_auth_header(header)
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
1288
        if scheme != self.scheme:
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1289
            return False
1290
4284.1.1 by Vincent Ladeuil
Fix wrong realm extraction in http basic authentication (reported
1291
        match, realm = self.extract_realm(raw_auth)
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1292
        if match:
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1293
            # Put useful info into auth
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1294
            self.update_auth(auth, 'scheme', scheme)
1295
            self.update_auth(auth, 'realm', realm)
2900.2.20 by Vincent Ladeuil
http can query AuthenticationConfig for logins too.
1296
            if auth['user'] is None or auth['password'] is None:
1297
                user, password = self.get_user_password(auth)
1298
                self.update_auth(auth, 'user', user)
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1299
                self.update_auth(auth, 'password', password)
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1300
        return match is not None
1301
1302
    def auth_params_reusable(self, auth):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1303
        # If the auth scheme is known, it means a previous
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1304
        # authentication was successful, all information is
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1305
        # available, no further checks are needed.
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1306
        return auth.get('scheme', None) == 'basic'
1307
1308
1309
def get_digest_algorithm_impls(algorithm):
1310
    H = None
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1311
    KD = None
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1312
    if algorithm == 'MD5':
2929.3.1 by Vincent Ladeuil
Fix python2.6 deprecation warnings (still 4 failures 5 errors in test suite).
1313
        H = lambda x: osutils.md5(x).hexdigest()
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1314
    elif algorithm == 'SHA':
2929.3.1 by Vincent Ladeuil
Fix python2.6 deprecation warnings (still 4 failures 5 errors in test suite).
1315
        H = lambda x: osutils.sha(x).hexdigest()
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1316
    if H is not None:
1317
        KD = lambda secret, data: H("%s:%s" % (secret, data))
1318
    return H, KD
1319
1320
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1321
def get_new_cnonce(nonce, nonce_count):
1322
    raw = '%s:%d:%s:%s' % (nonce, nonce_count, time.ctime(),
1323
                           urllib2.randombytes(8))
2929.3.1 by Vincent Ladeuil
Fix python2.6 deprecation warnings (still 4 failures 5 errors in test suite).
1324
    return osutils.sha(raw).hexdigest()[:16]
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1325
1326
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1327
class DigestAuthHandler(AbstractAuthHandler):
1328
    """A custom digest authentication handler."""
1329
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
1330
    scheme = 'digest'
4050.2.3 by Vincent Ladeuil
Slight cosmetic tweaks.
1331
    # Before basic as digest is a bit more secure and should be preferred
2545.2.1 by Vincent Ladeuil
Fix 121889 by working around urllib2 bug.
1332
    handler_order = 490
1333
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1334
    def auth_params_reusable(self, auth):
1335
        # If the auth scheme is known, it means a previous
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1336
        # authentication was successful, all information is
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1337
        # available, no further checks are needed.
1338
        return auth.get('scheme', None) == 'digest'
1339
1340
    def auth_match(self, header, auth):
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
1341
        scheme, raw_auth = self._parse_auth_header(header)
4307.4.3 by Vincent Ladeuil
Tighten multiple auth schemes handling.
1342
        if scheme != self.scheme:
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1343
            return False
1344
1345
        # Put the requested authentication info into a dict
1346
        req_auth = urllib2.parse_keqv_list(urllib2.parse_http_list(raw_auth))
1347
1348
        # Check that we can handle that authentication
1349
        qop = req_auth.get('qop', None)
1350
        if qop != 'auth': # No auth-int so far
1351
            return False
1352
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1353
        H, KD = get_digest_algorithm_impls(req_auth.get('algorithm', 'MD5'))
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1354
        if H is None:
1355
            return False
1356
1357
        realm = req_auth.get('realm', None)
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1358
        # Put useful info into auth
1359
        self.update_auth(auth, 'scheme', scheme)
1360
        self.update_auth(auth, 'realm', realm)
2900.2.20 by Vincent Ladeuil
http can query AuthenticationConfig for logins too.
1361
        if auth['user'] is None or auth['password'] is None:
1362
            user, password = self.get_user_password(auth)
1363
            self.update_auth(auth, 'user', user)
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1364
            self.update_auth(auth, 'password', password)
1365
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1366
        try:
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1367
            if req_auth.get('algorithm', None) is not None:
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1368
                self.update_auth(auth, 'algorithm', req_auth.get('algorithm'))
1369
            nonce = req_auth['nonce']
1370
            if auth.get('nonce', None) != nonce:
1371
                # A new nonce, never used
1372
                self.update_auth(auth, 'nonce_count', 0)
1373
            self.update_auth(auth, 'nonce', nonce)
1374
            self.update_auth(auth, 'qop', qop)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1375
            auth['opaque'] = req_auth.get('opaque', None)
1376
        except KeyError:
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1377
            # Some required field is not there
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1378
            return False
1379
1380
        return True
1381
1382
    def build_auth_header(self, auth, request):
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1383
        url_scheme, url_selector = urllib.splittype(request.get_selector())
1384
        sel_host, uri = urllib.splithost(url_selector)
1385
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1386
        A1 = '%s:%s:%s' % (auth['user'], auth['realm'], auth['password'])
1387
        A2 = '%s:%s' % (request.get_method(), uri)
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1388
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1389
        nonce = auth['nonce']
1390
        qop = auth['qop']
1391
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1392
        nonce_count = auth['nonce_count'] + 1
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1393
        ncvalue = '%08x' % nonce_count
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1394
        cnonce = get_new_cnonce(nonce, nonce_count)
1395
1396
        H, KD = get_digest_algorithm_impls(auth.get('algorithm', 'MD5'))
1397
        nonce_data = '%s:%s:%s:%s:%s' % (nonce, ncvalue, cnonce, qop, H(A2))
1398
        request_digest = KD(H(A1), nonce_data)
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1399
1400
        header = 'Digest '
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1401
        header += 'username="%s", realm="%s", nonce="%s"' % (auth['user'],
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1402
                                                             auth['realm'],
1403
                                                             nonce)
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1404
        header += ', uri="%s"' % uri
1405
        header += ', cnonce="%s", nc=%s' % (cnonce, ncvalue)
1406
        header += ', qop="%s"' % qop
1407
        header += ', response="%s"' % request_digest
1408
        # Append the optional fields
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1409
        opaque = auth.get('opaque', None)
1410
        if opaque:
1411
            header += ', opaque="%s"' % opaque
2420.1.14 by Vincent Ladeuil
Tested against squid-2.6.5 with digest authentication.
1412
        if auth.get('algorithm', None):
1413
            header += ', algorithm="%s"' % auth.get('algorithm')
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1414
1415
        # We have used the nonce once more, update the count
1416
        auth['nonce_count'] = nonce_count
1417
1418
        return header
1419
1420
1421
class HTTPAuthHandler(AbstractAuthHandler):
1422
    """Custom http authentication handler.
2004.3.1 by vila
Test ConnectionError exceptions.
1423
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1424
    Send the authentication preventively to avoid the roundtrip
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1425
    associated with the 401 error and keep the revelant info in
1426
    the auth request attribute.
2004.3.1 by vila
Test ConnectionError exceptions.
1427
    """
1428
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1429
    auth_required_header = 'www-authenticate'
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1430
    auth_header = 'Authorization'
1431
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1432
    def get_auth(self, request):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1433
        """Get the auth params from the request"""
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1434
        return request.auth
1435
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1436
    def set_auth(self, request, auth):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1437
        """Set the auth params for the request"""
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1438
        request.auth = auth
2004.3.1 by vila
Test ConnectionError exceptions.
1439
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1440
    def build_password_prompt(self, auth):
1441
        return self._build_password_prompt(auth)
1442
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1443
    def build_username_prompt(self, auth):
1444
        return self._build_username_prompt(auth)
1445
2363.4.9 by Vincent Ladeuil
Catch first succesful authentification to avoid further 401
1446
    def http_error_401(self, req, fp, code, msg, headers):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1447
        return self.auth_required(req, headers)
1448
1449
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1450
class ProxyAuthHandler(AbstractAuthHandler):
1451
    """Custom proxy authentication handler.
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1452
1453
    Send the authentication preventively to avoid the roundtrip
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1454
    associated with the 407 error and keep the revelant info in
1455
    the proxy_auth request attribute..
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1456
    """
1457
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1458
    auth_required_header = 'proxy-authenticate'
2420.1.7 by Vincent Ladeuil
Tested against squid-2.6.5 with basic authentication.
1459
    # FIXME: the correct capitalization is Proxy-Authorization,
2420.1.8 by Vincent Ladeuil
Interesting typo :-) A mix between capitalize, title and fuzzy may be...
1460
    # but python-2.4 urllib2.Request insist on using capitalize()
2420.1.7 by Vincent Ladeuil
Tested against squid-2.6.5 with basic authentication.
1461
    # instead of title().
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1462
    auth_header = 'Proxy-authorization'
1463
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1464
    def get_auth(self, request):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1465
        """Get the auth params from the request"""
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1466
        return request.proxy_auth
1467
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1468
    def set_auth(self, request, auth):
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1469
        """Set the auth params for the request"""
2420.1.6 by Vincent Ladeuil
Update NEWS to explain the intent of the modification. Also, use dicts
1470
        request.proxy_auth = auth
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1471
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1472
    def build_password_prompt(self, auth):
1473
        prompt = self._build_password_prompt(auth)
1474
        prompt = 'Proxy ' + prompt
1475
        return prompt
1476
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1477
    def build_username_prompt(self, auth):
1478
        prompt = self._build_username_prompt(auth)
1479
        prompt = 'Proxy ' + prompt
1480
        return prompt
1481
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1482
    def http_error_407(self, req, fp, code, msg, headers):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1483
        return self.auth_required(req, headers)
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1484
1485
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1486
class HTTPBasicAuthHandler(BasicAuthHandler, HTTPAuthHandler):
1487
    """Custom http basic authentication handler"""
1488
1489
1490
class ProxyBasicAuthHandler(BasicAuthHandler, ProxyAuthHandler):
1491
    """Custom proxy basic authentication handler"""
1492
1493
1494
class HTTPDigestAuthHandler(DigestAuthHandler, HTTPAuthHandler):
1495
    """Custom http basic authentication handler"""
1496
1497
1498
class ProxyDigestAuthHandler(DigestAuthHandler, ProxyAuthHandler):
1499
    """Custom proxy basic authentication handler"""
1500
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1501
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1502
class HTTPNegotiateAuthHandler(NegotiateAuthHandler, HTTPAuthHandler):
1503
    """Custom http negotiate authentication handler"""
1504
1505
1506
class ProxyNegotiateAuthHandler(NegotiateAuthHandler, ProxyAuthHandler):
1507
    """Custom proxy negotiate authentication handler"""
1508
1509
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1510
class HTTPErrorProcessor(urllib2.HTTPErrorProcessor):
1511
    """Process HTTP error responses.
1512
1513
    We don't really process the errors, quite the contrary
1514
    instead, we leave our Transport handle them.
1515
    """
1516
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
1517
    accepted_errors = [200, # Ok
1518
                       206, # Partial content
1519
                       404, # Not found
1520
                       ]
1521
    """The error codes the caller will handle.
1522
1523
    This can be specialized in the request on a case-by case basis, but the
1524
    common cases are covered here.
1525
    """
1526
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1527
    def http_response(self, request, response):
1528
        code, msg, hdrs = response.code, response.msg, response.info()
1529
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
1530
        accepted_errors = request.accepted_errors
1531
        if accepted_errors is None:
1532
            accepted_errors = self.accepted_errors
1533
1534
        if code not in accepted_errors:
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1535
            response = self.parent.error('http', request, response,
1536
                                         code, msg, hdrs)
1537
        return response
1538
1539
    https_response = http_response
1540
1541
1542
class HTTPDefaultErrorHandler(urllib2.HTTPDefaultErrorHandler):
1543
    """Translate common errors into bzr Exceptions"""
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
1544
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1545
    def http_error_default(self, req, fp, code, msg, hdrs):
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
1546
        if code == 403:
3430.3.1 by Vincent Ladeuil
Fix #230223 by making both http implementations raise appropriate exceptions.
1547
            raise errors.TransportError(
1548
                'Server refuses to fulfill the request (403 Forbidden)'
1549
                ' for %s' % req.get_full_url())
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1550
        else:
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
1551
            raise errors.InvalidHttpResponse(req.get_full_url(),
1552
                                             'Unable to handle http code %d: %s'
1553
                                             % (code, msg))
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
1554
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
1555
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1556
class Opener(object):
1557
    """A wrapper around urllib2.build_opener
1558
1559
    Daughter classes can override to build their own specific opener
1560
    """
2145.1.1 by mbp at sourcefrog
merge urllib keepalive etc
1561
    # TODO: Provides hooks for daughter classes.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1562
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
1563
    def __init__(self,
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1564
                 connection=ConnectionHandler,
1565
                 redirect=HTTPRedirectHandler,
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
1566
                 error=HTTPErrorProcessor,
1567
                 report_activity=None):
1568
        self._opener = urllib2.build_opener(
1569
            connection(report_activity=report_activity),
1570
            redirect, error,
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1571
            ProxyHandler(),
1572
            HTTPBasicAuthHandler(),
1573
            HTTPDigestAuthHandler(),
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1574
            HTTPNegotiateAuthHandler(),
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
1575
            ProxyBasicAuthHandler(),
1576
            ProxyDigestAuthHandler(),
4011.3.1 by Jelmer Vernooij
Add simple support for GSSAPI authentication over HTTP.
1577
            ProxyNegotiateAuthHandler(),
2004.1.2 by vila
Implements a BasicAuthManager.
1578
            HTTPHandler,
1579
            HTTPSHandler,
1580
            HTTPDefaultErrorHandler,
2004.2.1 by John Arbash Meinel
Cleanup of urllib functions
1581
            )
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
1582
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1583
        self.open = self._opener.open
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
1584
        if DEBUG >= 9:
2004.1.9 by vila
Takes jam's remarks into account when possible, add TODOs for the rest.
1585
            # When dealing with handler order, it's easy to mess
1586
            # things up, the following will help understand which
1587
            # handler is used, when and for what.
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
1588
            import pprint
1589
            pprint.pprint(self._opener.__dict__)