/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
1
# Copyright (C) 2005, 2006 Canonical Ltd
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
2
#
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
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.
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
7
#
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
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.
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
12
#
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
16
1540.3.3 by Martin Pool
Review updates of pycurl transport
17
# FIXME: This test should be repeated for each available http client
18
# implementation; at the moment we have urllib and pycurl.
19
1540.3.22 by Martin Pool
[patch] Add TestCase.assertIsInstance
20
# TODO: Should be renamed to bzrlib.transport.http.tests?
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
21
# TODO: What about renaming to bzrlib.tests.transport.http ?
1540.3.22 by Martin Pool
[patch] Add TestCase.assertIsInstance
22
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
23
from cStringIO import StringIO
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
24
import os
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
25
import select
2000.2.2 by John Arbash Meinel
Update the urllib.has test.
26
import socket
2420.1.20 by Vincent Ladeuil
Fix test failure on pqm.
27
import sys
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
28
import threading
2000.2.2 by John Arbash Meinel
Update the urllib.has test.
29
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
30
import bzrlib
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
31
from bzrlib import (
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
32
    config,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
33
    errors,
34
    osutils,
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
35
    ui,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
36
    urlutils,
37
    )
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
38
from bzrlib.tests import (
39
    TestCase,
2363.4.10 by Vincent Ladeuil
Complete tests.
40
    TestUIFactory,
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
41
    TestSkipped,
2363.4.10 by Vincent Ladeuil
Complete tests.
42
    StringIOWrapper,
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
43
    )
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
44
from bzrlib.tests.HttpServer import (
45
    HttpServer,
46
    HttpServer_PyCurl,
47
    HttpServer_urllib,
48
    )
49
from bzrlib.tests.HTTPTestUtil import (
50
    BadProtocolRequestHandler,
51
    BadStatusRequestHandler,
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
52
    ForbiddenRequestHandler,
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
53
    HTTPBasicAuthServer,
54
    HTTPDigestAuthServer,
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
55
    HTTPServerRedirecting,
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
56
    InvalidStatusRequestHandler,
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
57
    LimitedRangeHTTPServer,
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
58
    NoRangeRequestHandler,
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
59
    ProxyBasicAuthServer,
60
    ProxyDigestAuthServer,
61
    ProxyServer,
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
62
    SingleRangeRequestHandler,
2481.3.1 by Vincent Ladeuil
Fix bug #112719 by using the right range header.
63
    SingleOnlyRangeRequestHandler,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
64
    TestCaseWithRedirectedWebserver,
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
65
    TestCaseWithTwoWebservers,
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
66
    TestCaseWithWebserver,
67
    WallRequestHandler,
68
    )
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
69
from bzrlib.transport import (
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
70
    _CoalescedOffset,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
71
    do_catching_redirections,
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
72
    get_transport,
73
    Transport,
74
    )
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
75
from bzrlib.transport.http import (
76
    extract_auth,
77
    HttpTransportBase,
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
78
    _urllib2_wrappers,
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
79
    )
1540.3.26 by Martin Pool
[merge] bzr.dev; pycurl not updated for readv yet
80
from bzrlib.transport.http._urllib import HttpTransport_urllib
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
81
from bzrlib.transport.http._urllib2_wrappers import (
82
    ProxyHandler,
83
    Request,
84
    )
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
85
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
86
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
87
class FakeManager(object):
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
88
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
89
    def __init__(self):
90
        self.credentials = []
2004.3.1 by vila
Test ConnectionError exceptions.
91
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
92
    def add_password(self, realm, host, username, password):
93
        self.credentials.append([realm, host, username, password])
94
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
95
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
96
class RecordingServer(object):
97
    """A fake HTTP server.
98
    
99
    It records the bytes sent to it, and replies with a 200.
100
    """
101
102
    def __init__(self, expect_body_tail=None):
2018.2.28 by Andrew Bennetts
Changes in response to review: re-use _base_curl, rather than keeping a seperate _post_curl object; add docstring to test_http.RecordingServer, set is_user_error on some new exceptions.
103
        """Constructor.
104
105
        :type expect_body_tail: str
106
        :param expect_body_tail: a reply won't be sent until this string is
107
            received.
108
        """
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
109
        self._expect_body_tail = expect_body_tail
110
        self.host = None
111
        self.port = None
112
        self.received_bytes = ''
113
114
    def setUp(self):
115
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
116
        self._sock.bind(('127.0.0.1', 0))
117
        self.host, self.port = self._sock.getsockname()
118
        self._ready = threading.Event()
119
        self._thread = threading.Thread(target=self._accept_read_and_reply)
120
        self._thread.setDaemon(True)
121
        self._thread.start()
122
        self._ready.wait(5)
123
124
    def _accept_read_and_reply(self):
125
        self._sock.listen(1)
126
        self._ready.set()
127
        self._sock.settimeout(5)
128
        try:
129
            conn, address = self._sock.accept()
130
            # On win32, the accepted connection will be non-blocking to start
131
            # with because we're using settimeout.
132
            conn.setblocking(True)
133
            while not self.received_bytes.endswith(self._expect_body_tail):
134
                self.received_bytes += conn.recv(4096)
135
            conn.sendall('HTTP/1.1 200 OK\r\n')
136
        except socket.timeout:
137
            # Make sure the client isn't stuck waiting for us to e.g. accept.
138
            self._sock.close()
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
139
        except socket.error:
140
            # The client may have already closed the socket.
141
            pass
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
142
143
    def tearDown(self):
144
        try:
145
            self._sock.close()
146
        except socket.error:
147
            # We might have already closed it.  We don't care.
148
            pass
149
        self.host = None
150
        self.port = None
151
152
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
153
class TestWithTransport_pycurl(object):
154
    """Test case to inherit from if pycurl is present"""
155
156
    def _get_pycurl_maybe(self):
157
        try:
158
            from bzrlib.transport.http._pycurl import PyCurlTransport
159
            return PyCurlTransport
160
        except errors.DependencyNotPresent:
161
            raise TestSkipped('pycurl not present')
162
163
    _transport = property(_get_pycurl_maybe)
164
165
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
166
class TestHttpUrls(TestCase):
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
167
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
168
    # TODO: This should be moved to authorization tests once they
169
    # are written.
2004.1.40 by v.ladeuil+lp at free
Fix the race condition again and correct some small typos to be in
170
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
171
    def test_url_parsing(self):
172
        f = FakeManager()
173
        url = extract_auth('http://example.com', f)
174
        self.assertEquals('http://example.com', url)
175
        self.assertEquals(0, len(f.credentials))
1185.50.94 by John Arbash Meinel
Updated web page url to http://bazaar-vcs.org
176
        url = extract_auth('http://user:pass@www.bazaar-vcs.org/bzr/bzr.dev', f)
177
        self.assertEquals('http://www.bazaar-vcs.org/bzr/bzr.dev', url)
1185.40.20 by Robey Pointer
allow user:pass@ info in http urls to be used for auth; this should be easily expandable later to use auth config files
178
        self.assertEquals(1, len(f.credentials))
2004.3.1 by vila
Test ConnectionError exceptions.
179
        self.assertEquals([None, 'www.bazaar-vcs.org', 'user', 'pass'],
180
                          f.credentials[0])
181
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
182
183
class TestHttpTransportUrls(object):
184
    """Test the http urls.
185
186
    This MUST be used by daughter classes that also inherit from
187
    TestCase.
188
189
    We can't inherit directly from TestCase or the
190
    test framework will try to create an instance which cannot
191
    run, its implementation being incomplete.
192
    """
193
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
194
    def test_abs_url(self):
195
        """Construction of absolute http URLs"""
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
196
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
197
        eq = self.assertEqualDiff
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
198
        eq(t.abspath('.'), 'http://bazaar-vcs.org/bzr/bzr.dev')
199
        eq(t.abspath('foo/bar'), 'http://bazaar-vcs.org/bzr/bzr.dev/foo/bar')
200
        eq(t.abspath('.bzr'), 'http://bazaar-vcs.org/bzr/bzr.dev/.bzr')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
201
        eq(t.abspath('.bzr/1//2/./3'),
1185.50.94 by John Arbash Meinel
Updated web page url to http://bazaar-vcs.org
202
           'http://bazaar-vcs.org/bzr/bzr.dev/.bzr/1/2/3')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
203
204
    def test_invalid_http_urls(self):
205
        """Trap invalid construction of urls"""
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
206
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
207
        self.assertRaises(errors.InvalidURL,
2485.8.24 by Vincent Ladeuil
Finish http refactoring. Test suite passing.
208
                          self._transport,
209
                          'http://http://bazaar-vcs.org/bzr/bzr.dev/')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
210
211
    def test_http_root_urls(self):
212
        """Construction of URLs from server root"""
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
213
        t = self._transport('http://bzr.ozlabs.org/')
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
214
        eq = self.assertEqualDiff
215
        eq(t.abspath('.bzr/tree-version'),
216
           'http://bzr.ozlabs.org/.bzr/tree-version')
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
217
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
218
    def test_http_impl_urls(self):
219
        """There are servers which ask for particular clients to connect"""
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
220
        server = self._server()
1540.3.24 by Martin Pool
Add new protocol 'http+pycurl' that always uses PyCurl.
221
        try:
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
222
            server.setUp()
223
            url = server.get_url()
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
224
            self.assertTrue(url.startswith('%s://' % self._qualified_prefix))
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
225
        finally:
226
            server.tearDown()
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
227
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
228
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
229
class TestHttpUrls_urllib(TestHttpTransportUrls, TestCase):
230
    """Test http urls with urllib"""
231
232
    _transport = HttpTransport_urllib
233
    _server = HttpServer_urllib
234
    _qualified_prefix = 'http+urllib'
235
236
237
class TestHttpUrls_pycurl(TestWithTransport_pycurl, TestHttpTransportUrls,
238
                          TestCase):
239
    """Test http urls with pycurl"""
240
241
    _server = HttpServer_PyCurl
242
    _qualified_prefix = 'http+pycurl'
243
244
    # TODO: This should really be moved into another pycurl
245
    # specific test. When https tests will be implemented, take
246
    # this one into account.
247
    def test_pycurl_without_https_support(self):
248
        """Test that pycurl without SSL do not fail with a traceback.
249
250
        For the purpose of the test, we force pycurl to ignore
251
        https by supplying a fake version_info that do not
252
        support it.
253
        """
254
        try:
255
            import pycurl
256
        except ImportError:
257
            raise TestSkipped('pycurl not present')
258
        # Now that we have pycurl imported, we can fake its version_info
259
        # This was taken from a windows pycurl without SSL
260
        # (thanks to bialix)
261
        pycurl.version_info = lambda : (2,
262
                                        '7.13.2',
263
                                        462082,
264
                                        'i386-pc-win32',
265
                                        2576,
266
                                        None,
267
                                        0,
268
                                        None,
2294.3.2 by Aaron Bentley
Remove trailing whitespace
269
                                        ('ftp', 'gopher', 'telnet',
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
270
                                         'dict', 'ldap', 'http', 'file'),
271
                                        None,
272
                                        0,
273
                                        None)
274
        self.assertRaises(errors.DependencyNotPresent, self._transport,
275
                          'https://launchpad.net')
276
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
277
class TestHttpConnections(object):
278
    """Test the http connections.
279
280
    This MUST be used by daughter classes that also inherit from
281
    TestCaseWithWebserver.
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
282
283
    We can't inherit directly from TestCaseWithWebserver or the
284
    test framework will try to create an instance which cannot
285
    run, its implementation being incomplete.
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
286
    """
287
288
    def setUp(self):
289
        TestCaseWithWebserver.setUp(self)
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
290
        self.build_tree(['xxx', 'foo/', 'foo/bar'], line_endings='binary',
291
                        transport=self.get_transport())
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
292
293
    def test_http_has(self):
1185.50.84 by John Arbash Meinel
[merge] bzr.dev, cleanup conflicts, fixup http tests for new TestCase layout.
294
        server = self.get_readonly_server()
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
295
        t = self._transport(server.get_url())
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
296
        self.assertEqual(t.has('foo/bar'), True)
1185.50.84 by John Arbash Meinel
[merge] bzr.dev, cleanup conflicts, fixup http tests for new TestCase layout.
297
        self.assertEqual(len(server.logs), 1)
2004.3.1 by vila
Test ConnectionError exceptions.
298
        self.assertContainsRe(server.logs[0],
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
299
            r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "bzr/')
1553.1.5 by James Henstridge
Make HTTP transport has() method do HEAD requests, and update test to
300
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
301
    def test_http_has_not_found(self):
302
        server = self.get_readonly_server()
303
        t = self._transport(server.get_url())
1553.1.5 by James Henstridge
Make HTTP transport has() method do HEAD requests, and update test to
304
        self.assertEqual(t.has('not-found'), False)
2004.3.1 by vila
Test ConnectionError exceptions.
305
        self.assertContainsRe(server.logs[1],
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
306
            r'"HEAD /not-found HTTP/1.." 404 - "-" "bzr/')
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
307
308
    def test_http_get(self):
1185.50.84 by John Arbash Meinel
[merge] bzr.dev, cleanup conflicts, fixup http tests for new TestCase layout.
309
        server = self.get_readonly_server()
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
310
        t = self._transport(server.get_url())
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
311
        fp = t.get('foo/bar')
312
        self.assertEqualDiff(
313
            fp.read(),
1553.1.3 by James Henstridge
Make bzrlib.transport.http.HttpServer output referer and user agent as in
314
            'contents of foo/bar\n')
1185.50.84 by John Arbash Meinel
[merge] bzr.dev, cleanup conflicts, fixup http tests for new TestCase layout.
315
        self.assertEqual(len(server.logs), 1)
1540.3.15 by Martin Pool
[merge] large merge to sync with bzr.dev
316
        self.assertTrue(server.logs[0].find(
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
317
            '"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s'
318
            % bzrlib.__version__) > -1)
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
319
2018.2.3 by Andrew Bennetts
Starting factoring out the smart server client "medium" from the protocol.
320
    def test_get_smart_medium(self):
321
        # For HTTP, get_smart_medium should return the transport object.
322
        server = self.get_readonly_server()
323
        http_transport = self._transport(server.get_url())
324
        medium = http_transport.get_smart_medium()
2018.2.26 by Andrew Bennetts
Changes prompted by j-a-meinel's review.
325
        self.assertIs(medium, http_transport)
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
326
2000.2.2 by John Arbash Meinel
Update the urllib.has test.
327
    def test_has_on_bogus_host(self):
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
328
        # Get a free address and don't 'accept' on it, so that we
329
        # can be sure there is no http handler there, but set a
330
        # reasonable timeout to not slow down tests too much.
331
        default_timeout = socket.getdefaulttimeout()
332
        try:
333
            socket.setdefaulttimeout(2)
334
            s = socket.socket()
335
            s.bind(('localhost', 0))
336
            t = self._transport('http://%s:%s/' % s.getsockname())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
337
            self.assertRaises(errors.ConnectionError, t.has, 'foo/bar')
2004.1.1 by vila
Connection sharing, with redirection. without authentification.
338
        finally:
339
            socket.setdefaulttimeout(default_timeout)
340
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
341
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
342
class TestHttpConnections_urllib(TestHttpConnections, TestCaseWithWebserver):
343
    """Test http connections with urllib"""
344
345
    _transport = HttpTransport_urllib
346
347
348
349
class TestHttpConnections_pycurl(TestWithTransport_pycurl,
350
                                 TestHttpConnections,
351
                                 TestCaseWithWebserver):
352
    """Test http connections with pycurl"""
1540.3.33 by Martin Pool
Fix http tests that were failing to run tearDown when setup got a missing dependency
353
354
1540.3.23 by Martin Pool
Allow urls like http+pycurl://host/ to use a particular impl
355
class TestHttpTransportRegistration(TestCase):
356
    """Test registrations of various http implementations"""
357
358
    def test_http_registered(self):
359
        # urlllib should always be present
360
        t = get_transport('http+urllib://bzr.google.com/')
361
        self.assertIsInstance(t, Transport)
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
362
        self.assertIsInstance(t, HttpTransport_urllib)
1786.1.23 by John Arbash Meinel
Move offset_to_http_ranges back onto HttpTransportBase, clarify tests.
363
364
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
365
class TestPost(object):
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
366
367
    def _test_post_body_is_received(self, scheme):
368
        server = RecordingServer(expect_body_tail='end-of-body')
369
        server.setUp()
370
        self.addCleanup(server.tearDown)
371
        url = '%s://%s:%s/' % (scheme, server.host, server.port)
372
        try:
373
            http_transport = get_transport(url)
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
374
        except errors.UnsupportedProtocol:
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
375
            raise TestSkipped('%s not available' % scheme)
376
        code, response = http_transport._post('abc def end-of-body')
377
        self.assertTrue(
378
            server.received_bytes.startswith('POST /.bzr/smart HTTP/1.'))
379
        self.assertTrue('content-length: 19\r' in server.received_bytes.lower())
380
        # The transport should not be assuming that the server can accept
381
        # chunked encoding the first time it connects, because HTTP/1.1, so we
382
        # check for the literal string.
383
        self.assertTrue(
384
            server.received_bytes.endswith('\r\n\r\nabc def end-of-body'))
385
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
386
387
class TestPost_urllib(TestCase, TestPost):
388
    """TestPost for urllib implementation"""
389
390
    _transport = HttpTransport_urllib
391
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
392
    def test_post_body_is_received_urllib(self):
393
        self._test_post_body_is_received('http+urllib')
394
2158.2.1 by v.ladeuil+lp at free
Windows tests cleanup.
395
396
class TestPost_pycurl(TestWithTransport_pycurl, TestCase, TestPost):
397
    """TestPost for pycurl implementation"""
398
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
399
    def test_post_body_is_received_pycurl(self):
400
        self._test_post_body_is_received('http+pycurl')
401
402
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
403
class TestRangeHeader(TestCase):
404
    """Test range_header method"""
405
406
    def check_header(self, value, ranges=[], tail=0):
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
407
        offsets = [ (start, end - start + 1) for start, end in ranges]
408
        coalesce = Transport._coalesce_offsets
409
        coalesced = list(coalesce(offsets, limit=0, fudge_factor=0))
410
        range_header = HttpTransportBase._range_header
411
        self.assertEqual(value, range_header(coalesced, tail))
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
412
413
    def test_range_header_single(self):
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
414
        self.check_header('0-9', ranges=[(0,9)])
415
        self.check_header('100-109', ranges=[(100,109)])
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
416
417
    def test_range_header_tail(self):
1786.1.36 by John Arbash Meinel
pycurl expects us to just set the range of bytes, not including bytes=
418
        self.check_header('-10', tail=10)
419
        self.check_header('-50', tail=50)
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
420
421
    def test_range_header_multi(self):
1786.1.36 by John Arbash Meinel
pycurl expects us to just set the range of bytes, not including bytes=
422
        self.check_header('0-9,100-200,300-5000',
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
423
                          ranges=[(0,9), (100, 200), (300,5000)])
424
425
    def test_range_header_mixed(self):
1786.1.36 by John Arbash Meinel
pycurl expects us to just set the range of bytes, not including bytes=
426
        self.check_header('0-9,300-5000,-50',
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
427
                          ranges=[(0,9), (300,5000)],
428
                          tail=50)
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
429
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
430
431
class TestWallServer(object):
432
    """Tests exceptions during the connection phase"""
433
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
434
    def create_transport_readonly_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
435
        return HttpServer(WallRequestHandler)
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
436
437
    def test_http_has(self):
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
438
        server = self.get_readonly_server()
2004.3.1 by vila
Test ConnectionError exceptions.
439
        t = self._transport(server.get_url())
2004.1.40 by v.ladeuil+lp at free
Fix the race condition again and correct some small typos to be in
440
        # Unfortunately httplib (see HTTPResponse._read_status
441
        # for details) make no distinction between a closed
442
        # socket and badly formatted status line, so we can't
443
        # just test for ConnectionError, we have to test
444
        # InvalidHttpResponse too.
445
        self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
446
                          t.has, 'foo/bar')
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
447
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
448
    def test_http_get(self):
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
449
        server = self.get_readonly_server()
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
450
        t = self._transport(server.get_url())
2145.1.1 by mbp at sourcefrog
merge urllib keepalive etc
451
        self.assertRaises((errors.ConnectionError, errors.InvalidHttpResponse),
452
                          t.get, 'foo/bar')
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
453
454
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
455
class TestWallServer_urllib(TestWallServer, TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
456
    """Tests "wall" server for urllib implementation"""
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
457
458
    _transport = HttpTransport_urllib
459
460
461
class TestWallServer_pycurl(TestWithTransport_pycurl,
462
                            TestWallServer,
463
                            TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
464
    """Tests "wall" server for pycurl implementation"""
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
465
466
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
467
class TestBadStatusServer(object):
468
    """Tests bad status from server."""
469
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
470
    def create_transport_readonly_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
471
        return HttpServer(BadStatusRequestHandler)
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
472
473
    def test_http_has(self):
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
474
        server = self.get_readonly_server()
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
475
        t = self._transport(server.get_url())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
476
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
477
478
    def test_http_get(self):
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
479
        server = self.get_readonly_server()
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
480
        t = self._transport(server.get_url())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
481
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
482
483
484
class TestBadStatusServer_urllib(TestBadStatusServer, TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
485
    """Tests bad status server for urllib implementation"""
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
486
487
    _transport = HttpTransport_urllib
488
489
490
class TestBadStatusServer_pycurl(TestWithTransport_pycurl,
491
                                 TestBadStatusServer,
492
                                 TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
493
    """Tests bad status server for pycurl implementation"""
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
494
495
496
class TestInvalidStatusServer(TestBadStatusServer):
497
    """Tests invalid status from server.
498
499
    Both implementations raises the same error as for a bad status.
500
    """
501
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
502
    def create_transport_readonly_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
503
        return HttpServer(InvalidStatusRequestHandler)
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
504
505
506
class TestInvalidStatusServer_urllib(TestInvalidStatusServer,
507
                                     TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
508
    """Tests invalid status server for urllib implementation"""
2004.1.16 by v.ladeuil+lp at free
Add tests against erroneous http status lines.
509
510
    _transport = HttpTransport_urllib
511
512
513
class TestInvalidStatusServer_pycurl(TestWithTransport_pycurl,
514
                                     TestInvalidStatusServer,
515
                                     TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
516
    """Tests invalid status server for pycurl implementation"""
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
517
518
519
class TestBadProtocolServer(object):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
520
    """Tests bad protocol from server."""
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
521
522
    def create_transport_readonly_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
523
        return HttpServer(BadProtocolRequestHandler)
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
524
525
    def test_http_has(self):
526
        server = self.get_readonly_server()
527
        t = self._transport(server.get_url())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
528
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
529
530
    def test_http_get(self):
531
        server = self.get_readonly_server()
532
        t = self._transport(server.get_url())
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
533
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
534
535
536
class TestBadProtocolServer_urllib(TestBadProtocolServer,
537
                                   TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
538
    """Tests bad protocol server for urllib implementation"""
2004.1.19 by v.ladeuil+lp at free
Test protocol version in http responses.
539
540
    _transport = HttpTransport_urllib
541
542
# curl don't check the protocol version
543
#class TestBadProtocolServer_pycurl(TestWithTransport_pycurl,
544
#                                   TestBadProtocolServer,
545
#                                   TestCaseWithWebserver):
2004.1.27 by v.ladeuil+lp at free
Fix bug #57644 by issuing an explicit error message.
546
#    """Tests bad protocol server for pycurl implementation"""
547
548
549
class TestForbiddenServer(object):
550
    """Tests forbidden server"""
551
552
    def create_transport_readonly_server(self):
553
        return HttpServer(ForbiddenRequestHandler)
554
555
    def test_http_has(self):
556
        server = self.get_readonly_server()
557
        t = self._transport(server.get_url())
558
        self.assertRaises(errors.TransportError, t.has, 'foo/bar')
559
560
    def test_http_get(self):
561
        server = self.get_readonly_server()
562
        t = self._transport(server.get_url())
563
        self.assertRaises(errors.TransportError, t.get, 'foo/bar')
564
565
566
class TestForbiddenServer_urllib(TestForbiddenServer, TestCaseWithWebserver):
567
    """Tests forbidden server for urllib implementation"""
568
569
    _transport = HttpTransport_urllib
570
571
572
class TestForbiddenServer_pycurl(TestWithTransport_pycurl,
573
                                 TestForbiddenServer,
574
                                 TestCaseWithWebserver):
575
    """Tests forbidden server for pycurl implementation"""
576
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
577
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
578
class TestRecordingServer(TestCase):
579
580
    def test_create(self):
581
        server = RecordingServer(expect_body_tail=None)
582
        self.assertEqual('', server.received_bytes)
583
        self.assertEqual(None, server.host)
584
        self.assertEqual(None, server.port)
585
586
    def test_setUp_and_tearDown(self):
587
        server = RecordingServer(expect_body_tail=None)
588
        server.setUp()
589
        try:
590
            self.assertNotEqual(None, server.host)
591
            self.assertNotEqual(None, server.port)
592
        finally:
593
            server.tearDown()
594
        self.assertEqual(None, server.host)
595
        self.assertEqual(None, server.port)
596
597
    def test_send_receive_bytes(self):
598
        server = RecordingServer(expect_body_tail='c')
599
        server.setUp()
600
        self.addCleanup(server.tearDown)
601
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
602
        sock.connect((server.host, server.port))
603
        sock.sendall('abc')
604
        self.assertEqual('HTTP/1.1 200 OK\r\n',
2091.1.1 by Martin Pool
Avoid MSG_WAITALL as it doesn't work on Windows
605
                         osutils.recv_all(sock, 4096))
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
606
        self.assertEqual('abc', server.received_bytes)
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
607
608
609
class TestRangeRequestServer(object):
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
610
    """Tests readv requests against server.
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
611
612
    This MUST be used by daughter classes that also inherit from
613
    TestCaseWithWebserver.
614
615
    We can't inherit directly from TestCaseWithWebserver or the
616
    test framework will try to create an instance which cannot
617
    run, its implementation being incomplete.
618
    """
619
620
    def setUp(self):
621
        TestCaseWithWebserver.setUp(self)
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
622
        self.build_tree_contents([('a', '0123456789')],)
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
623
624
    def test_readv(self):
625
        server = self.get_readonly_server()
626
        t = self._transport(server.get_url())
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
627
        l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
628
        self.assertEqual(l[0], (0, '0'))
629
        self.assertEqual(l[1], (1, '1'))
630
        self.assertEqual(l[2], (3, '34'))
631
        self.assertEqual(l[3], (9, '9'))
632
633
    def test_readv_out_of_order(self):
634
        server = self.get_readonly_server()
635
        t = self._transport(server.get_url())
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
636
        l = list(t.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
637
        self.assertEqual(l[0], (1, '1'))
638
        self.assertEqual(l[1], (9, '9'))
639
        self.assertEqual(l[2], (0, '0'))
640
        self.assertEqual(l[3], (3, '34'))
641
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
642
    def test_readv_invalid_ranges(self):
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
643
        server = self.get_readonly_server()
644
        t = self._transport(server.get_url())
645
646
        # This is intentionally reading off the end of the file
647
        # since we are sure that it cannot get there
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
648
        self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
649
                              t.readv, 'a', [(1,1), (8,10)])
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
650
651
        # This is trying to seek past the end of the file, it should
652
        # also raise a special error
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
653
        self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
2004.1.30 by v.ladeuil+lp at free
Fix #62276 and #62029 by providing a more robust http range handling.
654
                              t.readv, 'a', [(12,2)])
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
655
656
657
class TestSingleRangeRequestServer(TestRangeRequestServer):
658
    """Test readv against a server which accept only single range requests"""
659
660
    def create_transport_readonly_server(self):
661
        return HttpServer(SingleRangeRequestHandler)
662
663
664
class TestSingleRangeRequestServer_urllib(TestSingleRangeRequestServer,
665
                                          TestCaseWithWebserver):
666
    """Tests single range requests accepting server for urllib implementation"""
667
668
    _transport = HttpTransport_urllib
669
670
671
class TestSingleRangeRequestServer_pycurl(TestWithTransport_pycurl,
672
                                          TestSingleRangeRequestServer,
673
                                          TestCaseWithWebserver):
674
    """Tests single range requests accepting server for pycurl implementation"""
675
676
2481.3.1 by Vincent Ladeuil
Fix bug #112719 by using the right range header.
677
class TestSingleOnlyRangeRequestServer(TestRangeRequestServer):
678
    """Test readv against a server which only accept single range requests"""
679
680
    def create_transport_readonly_server(self):
681
        return HttpServer(SingleOnlyRangeRequestHandler)
682
683
684
class TestSingleOnlyRangeRequestServer_urllib(TestSingleOnlyRangeRequestServer,
685
                                              TestCaseWithWebserver):
686
    """Tests single range requests accepting server for urllib implementation"""
687
688
    _transport = HttpTransport_urllib
689
690
691
class TestSingleOnlyRangeRequestServer_pycurl(TestWithTransport_pycurl,
692
                                              TestSingleOnlyRangeRequestServer,
693
                                              TestCaseWithWebserver):
694
    """Tests single range requests accepting server for pycurl implementation"""
695
696
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
697
class TestNoRangeRequestServer(TestRangeRequestServer):
698
    """Test readv against a server which do not accept range requests"""
699
700
    def create_transport_readonly_server(self):
701
        return HttpServer(NoRangeRequestHandler)
702
703
704
class TestNoRangeRequestServer_urllib(TestNoRangeRequestServer,
705
                                      TestCaseWithWebserver):
706
    """Tests range requests refusing server for urllib implementation"""
707
708
    _transport = HttpTransport_urllib
709
710
711
class TestNoRangeRequestServer_pycurl(TestWithTransport_pycurl,
712
                               TestNoRangeRequestServer,
713
                               TestCaseWithWebserver):
714
    """Tests range requests refusing server for pycurl implementation"""
715
716
2520.2.2 by Vincent Ladeuil
Fix #115209 by issuing a single range request on 400: Bad Request
717
class TestLimitedRangeRequestServer(object):
718
    """Tests readv requests against server that errors out on too much ranges.
719
720
    This MUST be used by daughter classes that also inherit from
721
    TestCaseWithWebserver.
722
723
    We can't inherit directly from TestCaseWithWebserver or the
724
    test framework will try to create an instance which cannot
725
    run, its implementation being incomplete.
726
    """
727
728
    range_limit = 3
729
730
    def create_transport_readonly_server(self):
731
        # Requests with more range specifiers will error out
732
        return LimitedRangeHTTPServer(range_limit=self.range_limit)
733
734
    def get_transport(self):
735
        return self._transport(self.get_readonly_server().get_url())
736
737
    def setUp(self):
738
        TestCaseWithWebserver.setUp(self)
739
        # We need to manipulate ranges that correspond to real chunks in the
740
        # response, so we build a content appropriately.
741
        filler = ''.join(['abcdefghij' for _ in range(102)])
742
        content = ''.join(['%04d' % v + filler for v in range(16)])
743
        self.build_tree_contents([('a', content)],)
744
745
    def test_few_ranges(self):
746
        t = self.get_transport()
747
        l = list(t.readv('a', ((0, 4), (1024, 4), )))
748
        self.assertEqual(l[0], (0, '0000'))
749
        self.assertEqual(l[1], (1024, '0001'))
750
        self.assertEqual(1, self.get_readonly_server().GET_request_nb)
751
752
    def test_a_lot_of_ranges(self):
753
        t = self.get_transport()
754
        l = list(t.readv('a', ((0, 4), (1024, 4), (4096, 4), (8192, 4))))
755
        self.assertEqual(l[0], (0, '0000'))
756
        self.assertEqual(l[1], (1024, '0001'))
757
        self.assertEqual(l[2], (4096, '0004'))
758
        self.assertEqual(l[3], (8192, '0008'))
759
        # The server will refuse to serve the first request (too much ranges),
760
        # a second request will succeeds.
761
        self.assertEqual(2, self.get_readonly_server().GET_request_nb)
762
763
764
class TestLimitedRangeRequestServer_urllib(TestLimitedRangeRequestServer,
765
                                          TestCaseWithWebserver):
766
    """Tests limited range requests server for urllib implementation"""
767
768
    _transport = HttpTransport_urllib
769
770
771
class TestLimitedRangeRequestServer_pycurl(TestWithTransport_pycurl,
772
                                          TestLimitedRangeRequestServer,
773
                                          TestCaseWithWebserver):
774
    """Tests limited range requests server for pycurl implementation"""
775
776
777
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
778
class TestHttpProxyWhiteBox(TestCase):
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
779
    """Whitebox test proxy http authorization.
780
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
781
    Only the urllib implementation is tested here.
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
782
    """
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
783
784
    def setUp(self):
785
        TestCase.setUp(self)
786
        self._old_env = {}
787
788
    def tearDown(self):
789
        self._restore_env()
790
791
    def _install_env(self, env):
792
        for name, value in env.iteritems():
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
793
            self._old_env[name] = osutils.set_or_unset_env(name, value)
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
794
795
    def _restore_env(self):
796
        for name, value in self._old_env.iteritems():
797
            osutils.set_or_unset_env(name, value)
798
799
    def _proxied_request(self):
2900.2.16 by Vincent Ladeuil
Make hhtp proxy aware of AuthenticationConfig (for password).
800
        handler = ProxyHandler()
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
801
        request = Request('GET','http://baz/buzzle')
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
802
        handler.set_proxy(request, 'http')
803
        return request
804
805
    def test_empty_user(self):
806
        self._install_env({'http_proxy': 'http://bar.com'})
807
        request = self._proxied_request()
808
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
809
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
810
    def test_invalid_proxy(self):
811
        """A proxy env variable without scheme"""
812
        self._install_env({'http_proxy': 'host:1234'})
813
        self.assertRaises(errors.InvalidURL, self._proxied_request)
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
814
815
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
816
class TestProxyHttpServer(object):
817
    """Tests proxy server.
818
819
    This MUST be used by daughter classes that also inherit from
820
    TestCaseWithTwoWebservers.
821
822
    We can't inherit directly from TestCaseWithTwoWebservers or
823
    the test framework will try to create an instance which
824
    cannot run, its implementation being incomplete.
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
825
826
    Be aware that we do not setup a real proxy here. Instead, we
2167.3.7 by v.ladeuil+lp at free
Typos corrected.
827
    check that the *connection* goes through the proxy by serving
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
828
    different content (the faked proxy server append '-proxied'
829
    to the file names).
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
830
    """
831
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
832
    # FIXME: We don't have an https server available, so we don't
833
    # test https connections.
834
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
835
    def setUp(self):
836
        TestCaseWithTwoWebservers.setUp(self)
837
        self.build_tree_contents([('foo', 'contents of foo\n'),
838
                                  ('foo-proxied', 'proxied contents of foo\n')])
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
839
        # Let's setup some attributes for tests
840
        self.server = self.get_readonly_server()
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
841
        self.proxy_address = '%s:%d' % (self.server.host, self.server.port)
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
842
        self.no_proxy_host = self.proxy_address
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
843
        # The secondary server is the proxy
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
844
        self.proxy = self.get_secondary_server()
845
        self.proxy_url = self.proxy.get_url()
846
        self._old_env = {}
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
847
848
    def create_transport_secondary_server(self):
849
        """Creates an http server that will serve files with
850
        '-proxied' appended to their names.
851
        """
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
852
        return ProxyServer()
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
853
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
854
    def _install_env(self, env):
855
        for name, value in env.iteritems():
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
856
            self._old_env[name] = osutils.set_or_unset_env(name, value)
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
857
858
    def _restore_env(self):
859
        for name, value in self._old_env.iteritems():
860
            osutils.set_or_unset_env(name, value)
861
862
    def proxied_in_env(self, env):
863
        self._install_env(env)
864
        url = self.server.get_url()
865
        t = self._transport(url)
866
        try:
867
            self.assertEqual(t.get('foo').read(), 'proxied contents of foo\n')
868
        finally:
869
            self._restore_env()
870
871
    def not_proxied_in_env(self, env):
872
        self._install_env(env)
873
        url = self.server.get_url()
874
        t = self._transport(url)
875
        try:
876
            self.assertEqual(t.get('foo').read(), 'contents of foo\n')
877
        finally:
878
            self._restore_env()
879
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
880
    def test_http_proxy(self):
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
881
        self.proxied_in_env({'http_proxy': self.proxy_url})
882
883
    def test_HTTP_PROXY(self):
884
        self.proxied_in_env({'HTTP_PROXY': self.proxy_url})
885
886
    def test_all_proxy(self):
887
        self.proxied_in_env({'all_proxy': self.proxy_url})
888
889
    def test_ALL_PROXY(self):
890
        self.proxied_in_env({'ALL_PROXY': self.proxy_url})
891
892
    def test_http_proxy_with_no_proxy(self):
893
        self.not_proxied_in_env({'http_proxy': self.proxy_url,
894
                                 'no_proxy': self.no_proxy_host})
895
896
    def test_HTTP_PROXY_with_NO_PROXY(self):
897
        self.not_proxied_in_env({'HTTP_PROXY': self.proxy_url,
898
                                 'NO_PROXY': self.no_proxy_host})
899
900
    def test_all_proxy_with_no_proxy(self):
901
        self.not_proxied_in_env({'all_proxy': self.proxy_url,
902
                                 'no_proxy': self.no_proxy_host})
903
904
    def test_ALL_PROXY_with_NO_PROXY(self):
905
        self.not_proxied_in_env({'ALL_PROXY': self.proxy_url,
906
                                 'NO_PROXY': self.no_proxy_host})
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
907
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
908
    def test_http_proxy_without_scheme(self):
909
        self.assertRaises(errors.InvalidURL,
910
                          self.proxied_in_env,
911
                          {'http_proxy': self.proxy_address})
912
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
913
914
class TestProxyHttpServer_urllib(TestProxyHttpServer,
915
                                 TestCaseWithTwoWebservers):
916
    """Tests proxy server for urllib implementation"""
917
918
    _transport = HttpTransport_urllib
919
920
921
class TestProxyHttpServer_pycurl(TestWithTransport_pycurl,
922
                                 TestProxyHttpServer,
923
                                 TestCaseWithTwoWebservers):
924
    """Tests proxy server for pycurl implementation"""
925
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
926
    def setUp(self):
927
        TestProxyHttpServer.setUp(self)
928
        # Oh my ! pycurl does not check for the port as part of
929
        # no_proxy :-( So we just test the host part
930
        self.no_proxy_host = 'localhost'
931
932
    def test_HTTP_PROXY(self):
2949.5.2 by Alexander Belchenko
John's review
933
        # pycurl does not check HTTP_PROXY for security reasons
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
934
        # (for use in a CGI context that we do not care
935
        # about. Should we ?)
2949.5.2 by Alexander Belchenko
John's review
936
        raise TestSkipped('pycurl does not check HTTP_PROXY '
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
937
            'for security reasons')
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
938
939
    def test_HTTP_PROXY_with_NO_PROXY(self):
2949.5.2 by Alexander Belchenko
John's review
940
        raise TestSkipped('pycurl does not check HTTP_PROXY '
2949.5.1 by Alexander Belchenko
selftest: use SymlinkFeature instead of TestSkipped where appropriate
941
            'for security reasons')
2183.1.1 by Aaron Bentley
Make test HTTP server's range handling more spec-compliant (Vincent Ladeuil)
942
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
943
    def test_http_proxy_without_scheme(self):
944
        # pycurl *ignores* invalid proxy env variables. If that
945
        # ever change in the future, this test will fail
946
        # indicating that pycurl do not ignore anymore such
947
        # variables.
948
        self.not_proxied_in_env({'http_proxy': self.proxy_address})
949
2183.1.1 by Aaron Bentley
Make test HTTP server's range handling more spec-compliant (Vincent Ladeuil)
950
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
951
class TestRanges(object):
952
    """Test the Range header in GET methods..
953
954
    This MUST be used by daughter classes that also inherit from
955
    TestCaseWithWebserver.
956
957
    We can't inherit directly from TestCaseWithWebserver or the
958
    test framework will try to create an instance which cannot
959
    run, its implementation being incomplete.
960
    """
961
962
    def setUp(self):
963
        TestCaseWithWebserver.setUp(self)
964
        self.build_tree_contents([('a', '0123456789')],)
965
        server = self.get_readonly_server()
966
        self.transport = self._transport(server.get_url())
967
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
968
    def _file_contents(self, relpath, ranges):
969
        offsets = [ (start, end - start + 1) for start, end in ranges]
970
        coalesce = self.transport._coalesce_offsets
971
        coalesced = list(coalesce(offsets, limit=0, fudge_factor=0))
972
        code, data = self.transport._get(relpath, coalesced)
973
        self.assertTrue(code in (200, 206),'_get returns: %d' % code)
974
        for start, end in ranges:
975
            data.seek(start)
976
            yield data.read(end - start + 1)
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
977
978
    def _file_tail(self, relpath, tail_amount):
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
979
        code, data = self.transport._get(relpath, [], tail_amount)
980
        self.assertTrue(code in (200, 206),'_get returns: %d' % code)
981
        data.seek(-tail_amount + 1, 2)
982
        return data.read(tail_amount)
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
983
984
    def test_range_header(self):
985
        # Valid ranges
986
        map(self.assertEqual,['0', '234'],
987
            list(self._file_contents('a', [(0,0), (2,4)])),)
988
        # Tail
989
        self.assertEqual('789', self._file_tail('a', 3))
990
        # Syntactically invalid range
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
991
        self.assertListRaises(errors.InvalidRange,
992
                          self._file_contents, 'a', [(4, 3)])
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
993
        # Semantically invalid range
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
994
        self.assertListRaises(errors.InvalidRange,
995
                          self._file_contents, 'a', [(42, 128)])
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
996
997
998
class TestRanges_urllib(TestRanges, TestCaseWithWebserver):
999
    """Test the Range header in GET methods for urllib implementation"""
1000
1001
    _transport = HttpTransport_urllib
1002
1003
1004
class TestRanges_pycurl(TestWithTransport_pycurl,
1005
                        TestRanges,
1006
                        TestCaseWithWebserver):
1007
    """Test the Range header in GET methods for pycurl implementation"""
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1008
1009
2164.2.16 by Vincent Ladeuil
Add tests.
1010
class TestHTTPRedirections(object):
1011
    """Test redirection between http servers.
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1012
1013
    This MUST be used by daughter classes that also inherit from
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1014
    TestCaseWithRedirectedWebserver.
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1015
1016
    We can't inherit directly from TestCaseWithTwoWebservers or the
1017
    test framework will try to create an instance which cannot
1018
    run, its implementation being incomplete. 
1019
    """
1020
1021
    def create_transport_secondary_server(self):
1022
        """Create the secondary server redirecting to the primary server"""
2164.2.16 by Vincent Ladeuil
Add tests.
1023
        new = self.get_readonly_server()
1024
1025
        redirecting = HTTPServerRedirecting()
1026
        redirecting.redirect_to(new.host, new.port)
1027
        return redirecting
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1028
1029
    def setUp(self):
2164.2.16 by Vincent Ladeuil
Add tests.
1030
        super(TestHTTPRedirections, self).setUp()
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1031
        self.build_tree_contents([('a', '0123456789'),
1032
                                  ('bundle',
1033
                                  '# Bazaar revision bundle v0.9\n#\n')
1034
                                  ],)
1035
1036
        self.old_transport = self._transport(self.old_server.get_url())
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1037
1038
    def test_redirected(self):
2164.2.16 by Vincent Ladeuil
Add tests.
1039
        self.assertRaises(errors.RedirectRequested, self.old_transport.get, 'a')
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1040
        t = self._transport(self.new_server.get_url())
1041
        self.assertEqual('0123456789', t.get('a').read())
1042
1043
    def test_read_redirected_bundle_from_url(self):
1044
        from bzrlib.bundle import read_bundle_from_url
1045
        url = self.old_transport.abspath('bundle')
1046
        bundle = read_bundle_from_url(url)
1047
        # If read_bundle_from_url was successful we get an empty bundle
1048
        self.assertEqual([], bundle.revisions)
2164.2.16 by Vincent Ladeuil
Add tests.
1049
1050
1051
class TestHTTPRedirections_urllib(TestHTTPRedirections,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1052
                                  TestCaseWithRedirectedWebserver):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
1053
    """Tests redirections for urllib implementation"""
1054
1055
    _transport = HttpTransport_urllib
1056
2164.2.16 by Vincent Ladeuil
Add tests.
1057
1058
1059
class TestHTTPRedirections_pycurl(TestWithTransport_pycurl,
1060
                                  TestHTTPRedirections,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1061
                                  TestCaseWithRedirectedWebserver):
2164.2.16 by Vincent Ladeuil
Add tests.
1062
    """Tests redirections for pycurl implementation"""
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1063
1064
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1065
class RedirectedRequest(Request):
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
1066
    """Request following redirections"""
1067
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1068
    init_orig = Request.__init__
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
1069
1070
    def __init__(self, method, url, *args, **kwargs):
1071
        RedirectedRequest.init_orig(self, method, url, args, kwargs)
1072
        self.follow_redirections = True
1073
1074
1075
class TestHTTPSilentRedirections_urllib(TestCaseWithRedirectedWebserver):
1076
    """Test redirections provided by urllib.
1077
1078
    http implementations do not redirect silently anymore (they
1079
    do not redirect at all in fact). The mechanism is still in
1080
    place at the _urllib2_wrappers.Request level and these tests
1081
    exercise it.
1082
1083
    For the pycurl implementation
1084
    the redirection have been deleted as we may deprecate pycurl
1085
    and I have no place to keep a working implementation.
1086
    -- vila 20070212
1087
    """
1088
1089
    _transport = HttpTransport_urllib
1090
1091
    def setUp(self):
1092
        super(TestHTTPSilentRedirections_urllib, self).setUp()
1093
        self.setup_redirected_request()
1094
        self.addCleanup(self.cleanup_redirected_request)
1095
        self.build_tree_contents([('a','a'),
1096
                                  ('1/',),
1097
                                  ('1/a', 'redirected once'),
1098
                                  ('2/',),
1099
                                  ('2/a', 'redirected twice'),
1100
                                  ('3/',),
1101
                                  ('3/a', 'redirected thrice'),
1102
                                  ('4/',),
1103
                                  ('4/a', 'redirected 4 times'),
1104
                                  ('5/',),
1105
                                  ('5/a', 'redirected 5 times'),
1106
                                  ],)
1107
1108
        self.old_transport = self._transport(self.old_server.get_url())
1109
1110
    def setup_redirected_request(self):
1111
        self.original_class = _urllib2_wrappers.Request
1112
        _urllib2_wrappers.Request = RedirectedRequest
1113
1114
    def cleanup_redirected_request(self):
1115
        _urllib2_wrappers.Request = self.original_class
1116
1117
    def create_transport_secondary_server(self):
1118
        """Create the secondary server, redirections are defined in the tests"""
1119
        return HTTPServerRedirecting()
1120
1121
    def test_one_redirection(self):
1122
        t = self.old_transport
1123
1124
        req = RedirectedRequest('GET', t.abspath('a'))
1125
        req.follow_redirections = True
1126
        new_prefix = 'http://%s:%s' % (self.new_server.host,
1127
                                       self.new_server.port)
1128
        self.old_server.redirections = \
1129
            [('(.*)', r'%s/1\1' % (new_prefix), 301),]
1130
        self.assertEquals('redirected once',t._perform(req).read())
1131
1132
    def test_five_redirections(self):
1133
        t = self.old_transport
1134
1135
        req = RedirectedRequest('GET', t.abspath('a'))
1136
        req.follow_redirections = True
1137
        old_prefix = 'http://%s:%s' % (self.old_server.host,
1138
                                       self.old_server.port)
1139
        new_prefix = 'http://%s:%s' % (self.new_server.host,
1140
                                       self.new_server.port)
1141
        self.old_server.redirections = \
1142
            [('/1(.*)', r'%s/2\1' % (old_prefix), 302),
1143
             ('/2(.*)', r'%s/3\1' % (old_prefix), 303),
1144
             ('/3(.*)', r'%s/4\1' % (old_prefix), 307),
1145
             ('/4(.*)', r'%s/5\1' % (new_prefix), 301),
1146
             ('(/[^/]+)', r'%s/1\1' % (old_prefix), 301),
1147
             ]
1148
        self.assertEquals('redirected 5 times',t._perform(req).read())
1149
1150
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
1151
class TestDoCatchRedirections(TestCaseWithRedirectedWebserver):
1152
    """Test transport.do_catching_redirections.
1153
1154
    We arbitrarily choose to use urllib transports
1155
    """
1156
1157
    _transport = HttpTransport_urllib
1158
1159
    def setUp(self):
1160
        super(TestDoCatchRedirections, self).setUp()
1161
        self.build_tree_contents([('a', '0123456789'),],)
1162
1163
        self.old_transport = self._transport(self.old_server.get_url())
1164
1165
    def get_a(self, transport):
1166
        return transport.get('a')
1167
1168
    def test_no_redirection(self):
1169
        t = self._transport(self.new_server.get_url())
1170
1171
        # We use None for redirected so that we fail if redirected
1172
        self.assertEquals('0123456789',
1173
                          do_catching_redirections(self.get_a, t, None).read())
1174
1175
    def test_one_redirection(self):
1176
        self.redirections = 0
1177
1178
        def redirected(transport, exception, redirection_notice):
1179
            self.redirections += 1
1180
            dir, file = urlutils.split(exception.target)
1181
            return self._transport(dir)
1182
1183
        self.assertEquals('0123456789',
1184
                          do_catching_redirections(self.get_a,
1185
                                                   self.old_transport,
1186
                                                   redirected
1187
                                                   ).read())
1188
        self.assertEquals(1, self.redirections)
1189
1190
    def test_redirection_loop(self):
1191
1192
        def redirected(transport, exception, redirection_notice):
1193
            # By using the redirected url as a base dir for the
1194
            # *old* transport, we create a loop: a => a/a =>
1195
            # a/a/a
1196
            return self.old_transport.clone(exception.target)
1197
1198
        self.assertRaises(errors.TooManyRedirections, do_catching_redirections,
1199
                          self.get_a, self.old_transport, redirected)
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1200
1201
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1202
class TestAuth(object):
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1203
    """Test some authentication scheme specified by daughter class.
1204
1205
    This MUST be used by daughter classes that also inherit from
1206
    either TestCaseWithWebserver or TestCaseWithTwoWebservers.
1207
    """
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1208
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1209
    _password_prompt_prefix = ''
1210
2363.4.7 by Vincent Ladeuil
Deeper tests, prepare the auth setting that will avoid the
1211
    def setUp(self):
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1212
        """Set up the test environment
1213
1214
        Daughter classes should set up their own environment
1215
        (including self.server) and explicitely call this
1216
        method. This is needed because we want to reuse the same
1217
        tests for proxy and no-proxy accesses which have
1218
        different ways of setting self.server.
1219
        """
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
1220
        self.build_tree_contents([('a', 'contents of a\n'),
1221
                                  ('b', 'contents of b\n'),])
2363.4.10 by Vincent Ladeuil
Complete tests.
1222
1223
    def get_user_url(self, user=None, password=None):
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
1224
        """Build an url embedding user and password"""
1225
        url = '%s://' % self.server._url_protocol
1226
        if user is not None:
1227
            url += user
1228
            if password is not None:
1229
                url += ':' + password
1230
            url += '@'
1231
        url += '%s:%s/' % (self.server.host, self.server.port)
1232
        return url
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1233
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1234
    def test_no_user(self):
1235
        self.server.add_user('joe', 'foo')
1236
        t = self.get_user_transport()
1237
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
1238
        # Only one 'Authentication Required' error should occur
1239
        self.assertEqual(1, self.server.auth_required_errors)
1240
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1241
    def test_empty_pass(self):
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
1242
        self.server.add_user('joe', '')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1243
        t = self.get_user_transport('joe', '')
2363.4.10 by Vincent Ladeuil
Complete tests.
1244
        self.assertEqual('contents of a\n', t.get('a').read())
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1245
        # Only one 'Authentication Required' error should occur
1246
        self.assertEqual(1, self.server.auth_required_errors)
2363.4.5 by Vincent Ladeuil
Add white box tests for basic HTTP auth.
1247
1248
    def test_user_pass(self):
2363.4.8 by Vincent Ladeuil
Implement a basic auth HTTP server, rewrite tests accordingly.
1249
        self.server.add_user('joe', 'foo')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1250
        t = self.get_user_transport('joe', 'foo')
2363.4.10 by Vincent Ladeuil
Complete tests.
1251
        self.assertEqual('contents of a\n', t.get('a').read())
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1252
        # Only one 'Authentication Required' error should occur
1253
        self.assertEqual(1, self.server.auth_required_errors)
2363.4.10 by Vincent Ladeuil
Complete tests.
1254
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1255
    def test_unknown_user(self):
1256
        self.server.add_user('joe', 'foo')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1257
        t = self.get_user_transport('bill', 'foo')
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1258
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1259
        # Two 'Authentication Required' errors should occur (the
1260
        # initial 'who are you' and 'I don't know you, who are
1261
        # you').
1262
        self.assertEqual(2, self.server.auth_required_errors)
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1263
2363.4.10 by Vincent Ladeuil
Complete tests.
1264
    def test_wrong_pass(self):
1265
        self.server.add_user('joe', 'foo')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1266
        t = self.get_user_transport('joe', 'bar')
2363.4.10 by Vincent Ladeuil
Complete tests.
1267
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1268
        # Two 'Authentication Required' errors should occur (the
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1269
        # initial 'who are you' and 'this is not you, who are you')
1270
        self.assertEqual(2, self.server.auth_required_errors)
2363.4.10 by Vincent Ladeuil
Complete tests.
1271
1272
    def test_prompt_for_password(self):
1273
        self.server.add_user('joe', 'foo')
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1274
        t = self.get_user_transport('joe', None)
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1275
        stdout = StringIOWrapper()
1276
        ui.ui_factory = TestUIFactory(stdin='foo\n', stdout=stdout)
2363.4.10 by Vincent Ladeuil
Complete tests.
1277
        self.assertEqual('contents of a\n',t.get('a').read())
1278
        # stdin should be empty
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1279
        self.assertEqual('', ui.ui_factory.stdin.readline())
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1280
        self._check_password_prompt(t._unqualified_scheme, 'joe',
1281
                                    stdout.getvalue())
2363.4.10 by Vincent Ladeuil
Complete tests.
1282
        # And we shouldn't prompt again for a different request
1283
        # against the same transport.
1284
        self.assertEqual('contents of b\n',t.get('b').read())
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
1285
        t2 = t.clone()
1286
        # And neither against a clone
1287
        self.assertEqual('contents of b\n',t2.get('b').read())
2420.1.4 by Vincent Ladeuil
Add test checking the number of roundtrips due to 401 or 407 errors.
1288
        # Only one 'Authentication Required' error should occur
1289
        self.assertEqual(1, self.server.auth_required_errors)
1290
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1291
    def _check_password_prompt(self, scheme, user, actual_prompt):
1292
        expected_prompt = (self._password_prompt_prefix
1293
                           + ("%s %s@%s:%d, Realm: '%s' password: "
1294
                              % (scheme.upper(),
1295
                                 user, self.server.host, self.server.port,
1296
                                 self.server.auth_realm)))
1297
        self.assertEquals(expected_prompt, actual_prompt)
1298
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
1299
    def test_no_prompt_for_password_when_using_auth_config(self):
1300
        user =' joe'
1301
        password = 'foo'
1302
        stdin_content = 'bar\n'  # Not the right password
1303
        self.server.add_user(user, password)
1304
        t = self.get_user_transport(user, None)
2900.2.12 by Vincent Ladeuil
Since all schemes query AuthenticationConfig then prompt user, make that
1305
        ui.ui_factory = TestUIFactory(stdin=stdin_content,
1306
                                      stdout=StringIOWrapper())
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
1307
        # Create a minimal config file with the right password
1308
        conf = config.AuthenticationConfig()
1309
        conf._get_config().update(
1310
            {'httptest': {'scheme': 'http', 'port': self.server.port,
1311
                          'user': user, 'password': password}})
1312
        conf._save()
1313
        # Issue a request to the server to connect
1314
        self.assertEqual('contents of a\n',t.get('a').read())
1315
        # stdin should have  been left untouched
1316
        self.assertEqual(stdin_content, ui.ui_factory.stdin.readline())
2900.2.15 by Vincent Ladeuil
AuthenticationConfig can be queried for logins too (first step).
1317
        # Only one 'Authentication Required' error should occur
1318
        self.assertEqual(1, self.server.auth_required_errors)
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
1319
1320
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1321
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1322
class TestHTTPAuth(TestAuth):
1323
    """Test HTTP authentication schemes.
1324
1325
    Daughter classes MUST inherit from TestCaseWithWebserver too.
1326
    """
1327
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1328
    _auth_header = 'Authorization'
1329
1330
    def setUp(self):
1331
        TestCaseWithWebserver.setUp(self)
1332
        self.server = self.get_readonly_server()
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1333
        TestAuth.setUp(self)
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1334
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1335
    def get_user_transport(self, user=None, password=None):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1336
        return self._transport(self.get_user_url(user, password))
1337
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1338
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1339
class TestProxyAuth(TestAuth):
1340
    """Test proxy authentication schemes.
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1341
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1342
    Daughter classes MUST also inherit from TestCaseWithWebserver.
1343
    """
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1344
    _auth_header = 'Proxy-authorization'
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
1345
    _password_prompt_prefix = 'Proxy '
1346
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1347
1348
    def setUp(self):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1349
        TestCaseWithWebserver.setUp(self)
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1350
        self.server = self.get_readonly_server()
1351
        self._old_env = {}
1352
        self.addCleanup(self._restore_env)
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1353
        TestAuth.setUp(self)
2420.1.2 by Vincent Ladeuil
Define tests for http proxy basic authentication. They fail.
1354
        # Override the contents to avoid false positives
1355
        self.build_tree_contents([('a', 'not proxied contents of a\n'),
1356
                                  ('b', 'not proxied contents of b\n'),
1357
                                  ('a-proxied', 'contents of a\n'),
1358
                                  ('b-proxied', 'contents of b\n'),
1359
                                  ])
1360
2420.1.11 by Vincent Ladeuil
Implement digest authentication. Test suite passes. Tested against apache-2.x.
1361
    def get_user_transport(self, user=None, password=None):
2420.1.5 by Vincent Ladeuil
Refactor http and proxy authentication. Tests passing. proxy password can be prompted too.
1362
        self._install_env({'all_proxy': self.get_user_url(user, password)})
1363
        return self._transport(self.server.get_url())
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1364
1365
    def _install_env(self, env):
1366
        for name, value in env.iteritems():
1367
            self._old_env[name] = osutils.set_or_unset_env(name, value)
1368
1369
    def _restore_env(self):
1370
        for name, value in self._old_env.iteritems():
1371
            osutils.set_or_unset_env(name, value)
1372
1373
1374
class TestHTTPBasicAuth(TestHTTPAuth, TestCaseWithWebserver):
1375
    """Test http basic authentication scheme"""
1376
1377
    _transport = HttpTransport_urllib
1378
1379
    def create_transport_readonly_server(self):
1380
        return HTTPBasicAuthServer()
1381
1382
1383
class TestHTTPProxyBasicAuth(TestProxyAuth, TestCaseWithWebserver):
1384
    """Test proxy basic authentication scheme"""
1385
1386
    _transport = HttpTransport_urllib
1387
1388
    def create_transport_readonly_server(self):
1389
        return ProxyBasicAuthServer()
1390
1391
2420.1.15 by Vincent Ladeuil
Check digest robustness.
1392
class TestDigestAuth(object):
1393
    """Digest Authentication specific tests"""
1394
1395
    def test_changing_nonce(self):
1396
        self.server.add_user('joe', 'foo')
1397
        t = self.get_user_transport('joe', 'foo')
1398
        self.assertEqual('contents of a\n', t.get('a').read())
1399
        self.assertEqual('contents of b\n', t.get('b').read())
1400
        # Only one 'Authentication Required' error should have
1401
        # occured so far
1402
        self.assertEqual(1, self.server.auth_required_errors)
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1403
        # The server invalidates the current nonce
1404
        self.server.auth_nonce = self.server.auth_nonce + '. No, now!'
2420.1.15 by Vincent Ladeuil
Check digest robustness.
1405
        self.assertEqual('contents of a\n', t.get('a').read())
2420.1.16 by Vincent Ladeuil
Handle nonce changes. Fix a nasty bug breaking the auth parameters sharing.
1406
        # Two 'Authentication Required' errors should occur (the
2420.1.15 by Vincent Ladeuil
Check digest robustness.
1407
        # initial 'who are you' and a second 'who are you' with the new nonce)
1408
        self.assertEqual(2, self.server.auth_required_errors)
1409
1410
1411
class TestHTTPDigestAuth(TestHTTPAuth, TestDigestAuth, TestCaseWithWebserver):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1412
    """Test http digest authentication scheme"""
1413
1414
    _transport = HttpTransport_urllib
1415
1416
    def create_transport_readonly_server(self):
1417
        return HTTPDigestAuthServer()
1418
1419
2420.1.15 by Vincent Ladeuil
Check digest robustness.
1420
class TestHTTPProxyDigestAuth(TestProxyAuth, TestDigestAuth,
1421
                              TestCaseWithWebserver):
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
1422
    """Test proxy digest authentication scheme"""
1423
1424
    _transport = HttpTransport_urllib
1425
1426
    def create_transport_readonly_server(self):
1427
        return ProxyDigestAuthServer()
1428