/brz/remove-bazaar

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