/brz/remove-bazaar

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