~bzr-pqm/bzr/bzr.dev

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