~bzr-pqm/bzr/bzr.dev

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