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