/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2005-2011 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1185.16.68 by Martin Pool
- http url fixes suggested by Robey Pointer, and tests
16
3111.1.30 by Vincent Ladeuil
Update NEWS. Some cosmetic changes.
17
"""Tests for HTTP implementations.
3111.1.10 by Vincent Ladeuil
Finish http parameterization, 24 auth tests failing for pycurl (not
18
3111.1.30 by Vincent Ladeuil
Update NEWS. Some cosmetic changes.
19
This module defines a load_tests() method that parametrize tests classes for
20
transport implementation, http protocol versions and authentication schemes.
3111.1.10 by Vincent Ladeuil
Finish http parameterization, 24 auth tests failing for pycurl (not
21
"""
1540.3.3 by Martin Pool
Review updates of pycurl transport
22
1540.3.22 by Martin Pool
[patch] Add TestCase.assertIsInstance
23
# TODO: Should be renamed to bzrlib.transport.http.tests?
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
24
# TODO: What about renaming to bzrlib.tests.transport.http ?
1540.3.22 by Martin Pool
[patch] Add TestCase.assertIsInstance
25
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
26
import httplib
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
27
import SimpleHTTPServer
2000.2.2 by John Arbash Meinel
Update the urllib.has test.
28
import socket
2420.1.20 by Vincent Ladeuil
Fix test failure on pqm.
29
import sys
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
30
import threading
2000.2.2 by John Arbash Meinel
Update the urllib.has test.
31
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
32
import bzrlib
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
33
from bzrlib import (
3606.4.1 by Andrew Bennetts
Fix NotImplementedError when probing for smart protocol via HTTP.
34
    bzrdir,
5652.1.6 by Vincent Ladeuil
thread is already a python module, avoid confusion and use cethread instead.
35
    cethread,
2900.2.6 by Vincent Ladeuil
Make http aware of authentication config.
36
    config,
2164.2.22 by Vincent Ladeuil
Take Aaron's review comments into account.
37
    errors,
38
    osutils,
3606.4.1 by Andrew Bennetts
Fix NotImplementedError when probing for smart protocol via HTTP.
39
    remote as _mod_remote,
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
40
    tests,
3111.1.10 by Vincent Ladeuil
Finish http parameterization, 24 auth tests failing for pycurl (not
41
    transport,
2363.4.12 by Vincent Ladeuil
Take jam's review comments into account. Fix typos, give better
42
    ui,
3995.2.2 by Martin Pool
Cope with read_bundle_from_url deprecation in test_http
43
    )
3102.1.1 by Vincent Ladeuil
Rename bzrlib/test/HTTPTestUtils.py to bzrlib/tests/http_utils.py and fix
44
from bzrlib.tests import (
4913.2.11 by John Arbash Meinel
Convert a bunch more features over to ModuleAvailableFeature
45
    features,
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
46
    http_server,
3111.1.7 by Vincent Ladeuil
Further refactoring.
47
    http_utils,
5247.2.5 by Vincent Ladeuil
Some cleanups.
48
    test_server,
3102.1.1 by Vincent Ladeuil
Rename bzrlib/test/HTTPTestUtils.py to bzrlib/tests/http_utils.py and fix
49
    )
5462.3.15 by Martin Pool
Turn variations into scenario lists
50
from bzrlib.tests.scenarios import (
5462.3.21 by Martin Pool
Rename to load_tests_apply_scenarios
51
    load_tests_apply_scenarios,
5462.3.15 by Martin Pool
Turn variations into scenario lists
52
    multiply_scenarios,
5462.3.2 by Martin Pool
Split variations code to bzrlib.tests.variations
53
    )
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
54
from bzrlib.transport import (
55
    http,
56
    remote,
57
    )
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
58
from bzrlib.transport.http import (
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
59
    _urllib,
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
60
    _urllib2_wrappers,
2004.3.3 by vila
Better (but still incomplete) design for bogus servers.
61
    )
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
62
63
4913.2.11 by John Arbash Meinel
Convert a bunch more features over to ModuleAvailableFeature
64
if features.pycurl.available():
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
65
    from bzrlib.transport.http._pycurl import PyCurlTransport
66
67
5462.3.21 by Martin Pool
Rename to load_tests_apply_scenarios
68
load_tests = load_tests_apply_scenarios
5462.3.15 by Martin Pool
Turn variations into scenario lists
69
70
71
def vary_by_http_client_implementation():
5462.3.1 by Martin Pool
Split out generation of scenario lists into TestVariations
72
    """Test the two libraries we can use, pycurl and urllib."""
5462.3.15 by Martin Pool
Turn variations into scenario lists
73
    transport_scenarios = [
74
        ('urllib', dict(_transport=_urllib.HttpTransport_urllib,
75
                        _server=http_server.HttpServer_urllib,
76
                        _url_protocol='http+urllib',)),
77
        ]
78
    if features.pycurl.available():
79
        transport_scenarios.append(
80
            ('pycurl', dict(_transport=PyCurlTransport,
81
                            _server=http_server.HttpServer_PyCurl,
82
                            _url_protocol='http+pycurl',)))
83
    return transport_scenarios
84
85
86
def vary_by_http_protocol_version():
5462.3.1 by Martin Pool
Split out generation of scenario lists into TestVariations
87
    """Test on http/1.0 and 1.1"""
5462.3.15 by Martin Pool
Turn variations into scenario lists
88
    return [
89
        ('HTTP/1.0',  dict(_protocol_version='HTTP/1.0')),
90
        ('HTTP/1.1',  dict(_protocol_version='HTTP/1.1')),
91
        ]
92
93
5957.2.1 by Vincent Ladeuil
Tweak the http Authorization tests to make some parts easier to reuse (parametrization mostly).
94
def vary_by_http_auth_scheme():
95
    scenarios = [
96
        ('basic', dict(_auth_server=http_utils.HTTPBasicAuthServer)),
97
        ('digest', dict(_auth_server=http_utils.HTTPDigestAuthServer)),
98
        ('basicdigest',
99
            dict(_auth_server=http_utils.HTTPBasicAndDigestAuthServer)),
100
        ]
101
    # Add some attributes common to all scenarios
102
    for scenario_id, scenario_dict in scenarios:
103
        scenario_dict.update(_username_prompt_prefix='',
104
                             _password_prompt_prefix='')
105
    return scenarios
106
107
5462.3.15 by Martin Pool
Turn variations into scenario lists
108
def vary_by_http_proxy_auth_scheme():
5957.2.1 by Vincent Ladeuil
Tweak the http Authorization tests to make some parts easier to reuse (parametrization mostly).
109
    scenarios = [
5462.3.15 by Martin Pool
Turn variations into scenario lists
110
        ('basic', dict(_auth_server=http_utils.ProxyBasicAuthServer)),
111
        ('digest', dict(_auth_server=http_utils.ProxyDigestAuthServer)),
112
        ('basicdigest',
113
            dict(_auth_server=http_utils.ProxyBasicAndDigestAuthServer)),
114
        ]
5957.2.1 by Vincent Ladeuil
Tweak the http Authorization tests to make some parts easier to reuse (parametrization mostly).
115
    # Add some attributes common to all scenarios
116
    for scenario_id, scenario_dict in scenarios:
117
        scenario_dict.update(_username_prompt_prefix='Proxy ',
118
                             _password_prompt_prefix='Proxy ')
119
    return scenarios
5462.3.15 by Martin Pool
Turn variations into scenario lists
120
121
122
def vary_by_http_activity():
123
    activity_scenarios = [
124
        ('urllib,http', dict(_activity_server=ActivityHTTPServer,
125
                            _transport=_urllib.HttpTransport_urllib,)),
126
        ]
127
    if tests.HTTPSServerFeature.available():
128
        activity_scenarios.append(
129
            ('urllib,https', dict(_activity_server=ActivityHTTPSServer,
130
                                _transport=_urllib.HttpTransport_urllib,)),)
131
    if features.pycurl.available():
132
        activity_scenarios.append(
133
            ('pycurl,http', dict(_activity_server=ActivityHTTPServer,
134
                                _transport=PyCurlTransport,)),)
5462.3.1 by Martin Pool
Split out generation of scenario lists into TestVariations
135
        if tests.HTTPSServerFeature.available():
5462.3.15 by Martin Pool
Turn variations into scenario lists
136
            from bzrlib.tests import (
137
                ssl_certs,
138
                )
139
            # FIXME: Until we have a better way to handle self-signed
140
            # certificates (like allowing them in a test specific
141
            # authentication.conf for example), we need some specialized pycurl
142
            # transport for tests.
143
            class HTTPS_pycurl_transport(PyCurlTransport):
144
145
                def __init__(self, base, _from_transport=None):
146
                    super(HTTPS_pycurl_transport, self).__init__(
147
                        base, _from_transport)
148
                    self.cabundle = str(ssl_certs.build_path('ca.crt'))
149
150
            activity_scenarios.append(
151
                ('pycurl,https', dict(_activity_server=ActivityHTTPSServer,
152
                                    _transport=HTTPS_pycurl_transport,)),)
153
    return activity_scenarios
5462.3.1 by Martin Pool
Split out generation of scenario lists into TestVariations
154
155
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
156
class FakeManager(object):
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
157
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
158
    def __init__(self):
159
        self.credentials = []
2004.3.1 by vila
Test ConnectionError exceptions.
160
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
161
    def add_password(self, realm, host, username, password):
162
        self.credentials.append([realm, host, username, password])
163
1553.1.2 by James Henstridge
Add a test to make sure the user-agent header is being sent correctly.
164
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
165
class RecordingServer(object):
166
    """A fake HTTP server.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
167
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
168
    It records the bytes sent to it, and replies with a 200.
169
    """
170
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
171
    def __init__(self, expect_body_tail=None, scheme=''):
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
172
        """Constructor.
173
174
        :type expect_body_tail: str
175
        :param expect_body_tail: a reply won't be sent until this string is
176
            received.
177
        """
178
        self._expect_body_tail = expect_body_tail
179
        self.host = None
180
        self.port = None
181
        self.received_bytes = ''
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
182
        self.scheme = scheme
183
184
    def get_url(self):
185
        return '%s://%s:%s/' % (self.scheme, self.host, self.port)
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
186
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
187
    def start_server(self):
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
188
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
189
        self._sock.bind(('127.0.0.1', 0))
190
        self.host, self.port = self._sock.getsockname()
191
        self._ready = threading.Event()
5652.1.1 by Vincent Ladeuil
Split ThreadWithException out of the tests hierarchy.
192
        self._thread = test_server.TestThread(
5652.1.2 by Vincent Ladeuil
Use clearer names.
193
            sync_event=self._ready, target=self._accept_read_and_reply)
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
194
        self._thread.start()
4731.2.9 by Vincent Ladeuil
Implement a new -Ethreads to better track the leaks.
195
        if 'threads' in tests.selftest_debug_flags:
5247.5.29 by Vincent Ladeuil
Fixed as per jam's review.
196
            sys.stderr.write('Thread started: %s\n' % (self._thread.ident,))
4731.2.4 by Vincent Ladeuil
No more leaks in http tests.
197
        self._ready.wait()
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
198
199
    def _accept_read_and_reply(self):
200
        self._sock.listen(1)
201
        self._ready.set()
5247.2.5 by Vincent Ladeuil
Some cleanups.
202
        conn, address = self._sock.accept()
203
        if self._expect_body_tail is not None:
204
            while not self.received_bytes.endswith(self._expect_body_tail):
205
                self.received_bytes += conn.recv(4096)
206
            conn.sendall('HTTP/1.1 200 OK\r\n')
4731.2.4 by Vincent Ladeuil
No more leaks in http tests.
207
        try:
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
208
            self._sock.close()
209
        except socket.error:
210
            # The client may have already closed the socket.
211
            pass
212
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
213
    def stop_server(self):
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
214
        try:
4731.2.4 by Vincent Ladeuil
No more leaks in http tests.
215
            # Issue a fake connection to wake up the server and allow it to
216
            # finish quickly
5247.3.7 by Vincent Ladeuil
Provide connect_socket (socket.create_connection) for pythons older than 2.6.
217
            fake_conn = osutils.connect_socket((self.host, self.port))
4731.2.4 by Vincent Ladeuil
No more leaks in http tests.
218
            fake_conn.close()
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
219
        except socket.error:
220
            # We might have already closed it.  We don't care.
221
            pass
222
        self.host = None
223
        self.port = None
4731.2.4 by Vincent Ladeuil
No more leaks in http tests.
224
        self._thread.join()
4731.2.9 by Vincent Ladeuil
Implement a new -Ethreads to better track the leaks.
225
        if 'threads' in tests.selftest_debug_flags:
5247.5.29 by Vincent Ladeuil
Fixed as per jam's review.
226
            sys.stderr.write('Thread  joined: %s\n' % (self._thread.ident,))
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
227
228
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
229
class TestAuthHeader(tests.TestCase):
230
4284.1.1 by Vincent Ladeuil
Fix wrong realm extraction in http basic authentication (reported
231
    def parse_header(self, header, auth_handler_class=None):
232
        if auth_handler_class is None:
233
            auth_handler_class = _urllib2_wrappers.AbstractAuthHandler
234
        self.auth_handler =  auth_handler_class()
235
        return self.auth_handler._parse_auth_header(header)
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
236
237
    def test_empty_header(self):
238
        scheme, remainder = self.parse_header('')
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
239
        self.assertEqual('', scheme)
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
240
        self.assertIs(None, remainder)
241
242
    def test_negotiate_header(self):
243
        scheme, remainder = self.parse_header('Negotiate')
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
244
        self.assertEqual('negotiate', scheme)
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
245
        self.assertIs(None, remainder)
246
247
    def test_basic_header(self):
248
        scheme, remainder = self.parse_header(
249
            'Basic realm="Thou should not pass"')
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
250
        self.assertEqual('basic', scheme)
251
        self.assertEqual('realm="Thou should not pass"', remainder)
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
252
4284.1.1 by Vincent Ladeuil
Fix wrong realm extraction in http basic authentication (reported
253
    def test_basic_extract_realm(self):
254
        scheme, remainder = self.parse_header(
255
            'Basic realm="Thou should not pass"',
256
            _urllib2_wrappers.BasicAuthHandler)
257
        match, realm = self.auth_handler.extract_realm(remainder)
258
        self.assertTrue(match is not None)
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
259
        self.assertEqual('Thou should not pass', realm)
4284.1.1 by Vincent Ladeuil
Fix wrong realm extraction in http basic authentication (reported
260
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
261
    def test_digest_header(self):
262
        scheme, remainder = self.parse_header(
263
            'Digest realm="Thou should not pass"')
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
264
        self.assertEqual('digest', scheme)
265
        self.assertEqual('realm="Thou should not pass"', remainder)
4050.2.2 by Vincent Ladeuil
Ensures all auth handlers correctly parse all auth headers.
266
267
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
268
class TestHTTPRangeParsing(tests.TestCase):
269
270
    def setUp(self):
271
        super(TestHTTPRangeParsing, self).setUp()
272
        # We focus on range  parsing here and ignore everything else
273
        class RequestHandler(http_server.TestingHTTPRequestHandler):
274
            def setup(self): pass
275
            def handle(self): pass
276
            def finish(self): pass
277
5705.1.2 by Vincent Ladeuil
Fix spurious space and add a test.
278
        self.req_handler = RequestHandler(None, None, None)
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
279
280
    def assertRanges(self, ranges, header, file_size):
281
        self.assertEquals(ranges,
282
                          self.req_handler._parse_ranges(header, file_size))
283
284
    def test_simple_range(self):
285
        self.assertRanges([(0,2)], 'bytes=0-2', 12)
286
287
    def test_tail(self):
288
        self.assertRanges([(8, 11)], 'bytes=-4', 12)
289
290
    def test_tail_bigger_than_file(self):
291
        self.assertRanges([(0, 11)], 'bytes=-99', 12)
292
293
    def test_range_without_end(self):
294
        self.assertRanges([(4, 11)], 'bytes=4-', 12)
295
296
    def test_invalid_ranges(self):
297
        self.assertRanges(None, 'bytes=12-22', 12)
298
        self.assertRanges(None, 'bytes=1-3,12-22', 12)
5705.1.2 by Vincent Ladeuil
Fix spurious space and add a test.
299
        self.assertRanges(None, 'bytes=-', 12)
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
300
301
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
302
class TestHTTPServer(tests.TestCase):
303
    """Test the HTTP servers implementations."""
304
305
    def test_invalid_protocol(self):
306
        class BogusRequestHandler(http_server.TestingHTTPRequestHandler):
307
308
            protocol_version = 'HTTP/0.1'
309
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
310
        self.assertRaises(httplib.UnknownProtocol,
311
                          http_server.HttpServer, BogusRequestHandler)
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
312
3111.1.17 by Vincent Ladeuil
Add tests for the protocol version parameter.
313
    def test_force_invalid_protocol(self):
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
314
        self.assertRaises(httplib.UnknownProtocol,
315
                          http_server.HttpServer, protocol_version='HTTP/0.1')
3111.1.17 by Vincent Ladeuil
Add tests for the protocol version parameter.
316
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
317
    def test_server_start_and_stop(self):
318
        server = http_server.HttpServer()
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
319
        self.addCleanup(server.stop_server)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
320
        server.start_server()
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
321
        self.assertTrue(server.server is not None)
322
        self.assertTrue(server.server.serving is not None)
5247.6.7 by Vincent Ladeuil
Merge propagate-exceptions into http-leaks resolving conflicts
323
        self.assertTrue(server.server.serving)
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
324
325
    def test_create_http_server_one_zero(self):
326
        class RequestHandlerOneZero(http_server.TestingHTTPRequestHandler):
327
328
            protocol_version = 'HTTP/1.0'
329
330
        server = http_server.HttpServer(RequestHandlerOneZero)
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
331
        self.start_server(server)
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
332
        self.assertIsInstance(server.server, http_server.TestingHTTPServer)
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
333
334
    def test_create_http_server_one_one(self):
335
        class RequestHandlerOneOne(http_server.TestingHTTPRequestHandler):
336
337
            protocol_version = 'HTTP/1.1'
338
339
        server = http_server.HttpServer(RequestHandlerOneOne)
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
340
        self.start_server(server)
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
341
        self.assertIsInstance(server.server,
3111.1.17 by Vincent Ladeuil
Add tests for the protocol version parameter.
342
                              http_server.TestingThreadingHTTPServer)
343
344
    def test_create_http_server_force_one_one(self):
345
        class RequestHandlerOneZero(http_server.TestingHTTPRequestHandler):
346
347
            protocol_version = 'HTTP/1.0'
348
349
        server = http_server.HttpServer(RequestHandlerOneZero,
350
                                        protocol_version='HTTP/1.1')
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
351
        self.start_server(server)
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
352
        self.assertIsInstance(server.server,
3111.1.17 by Vincent Ladeuil
Add tests for the protocol version parameter.
353
                              http_server.TestingThreadingHTTPServer)
354
355
    def test_create_http_server_force_one_zero(self):
356
        class RequestHandlerOneOne(http_server.TestingHTTPRequestHandler):
357
358
            protocol_version = 'HTTP/1.1'
359
360
        server = http_server.HttpServer(RequestHandlerOneOne,
361
                                        protocol_version='HTTP/1.0')
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
362
        self.start_server(server)
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
363
        self.assertIsInstance(server.server,
3111.1.17 by Vincent Ladeuil
Add tests for the protocol version parameter.
364
                              http_server.TestingHTTPServer)
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
365
366
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
367
class TestWithTransport_pycurl(object):
368
    """Test case to inherit from if pycurl is present"""
369
370
    def _get_pycurl_maybe(self):
4913.2.11 by John Arbash Meinel
Convert a bunch more features over to ModuleAvailableFeature
371
        self.requireFeature(features.pycurl)
372
        return PyCurlTransport
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
373
374
    _transport = property(_get_pycurl_maybe)
375
376
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
377
class TestHttpUrls(tests.TestCase):
1786.1.8 by John Arbash Meinel
[merge] Johan Rydberg test updates
378
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
379
    # TODO: This should be moved to authorization tests once they
380
    # are written.
2004.1.40 by v.ladeuil+lp at free
Fix the race condition again and correct some small typos to be in
381
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
382
    def test_url_parsing(self):
383
        f = FakeManager()
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
384
        url = http.extract_auth('http://example.com', f)
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
385
        self.assertEqual('http://example.com', url)
386
        self.assertEqual(0, len(f.credentials))
3111.1.30 by Vincent Ladeuil
Update NEWS. Some cosmetic changes.
387
        url = http.extract_auth(
4988.4.2 by Martin Pool
Change url to canonical.com or wiki, plus some doc improvements in passing
388
            'http://user:pass@example.com/bzr/bzr.dev', f)
389
        self.assertEqual('http://example.com/bzr/bzr.dev', url)
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
390
        self.assertEqual(1, len(f.credentials))
4988.4.2 by Martin Pool
Change url to canonical.com or wiki, plus some doc improvements in passing
391
        self.assertEqual([None, 'example.com', 'user', 'pass'],
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
392
                         f.credentials[0])
2004.3.1 by vila
Test ConnectionError exceptions.
393
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
394
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
395
class TestHttpTransportUrls(tests.TestCase):
396
    """Test the http urls."""
397
5462.3.15 by Martin Pool
Turn variations into scenario lists
398
    scenarios = vary_by_http_client_implementation()
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
399
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
400
    def test_abs_url(self):
401
        """Construction of absolute http URLs"""
5560.2.1 by Vincent Ladeuil
Fix the remaining references to http://bazaar-vcs.org (except the explicitly historical ones).
402
        t = self._transport('http://example.com/bzr/bzr.dev/')
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
403
        eq = self.assertEqualDiff
5560.2.1 by Vincent Ladeuil
Fix the remaining references to http://bazaar-vcs.org (except the explicitly historical ones).
404
        eq(t.abspath('.'), 'http://example.com/bzr/bzr.dev')
405
        eq(t.abspath('foo/bar'), 'http://example.com/bzr/bzr.dev/foo/bar')
406
        eq(t.abspath('.bzr'), 'http://example.com/bzr/bzr.dev/.bzr')
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
407
        eq(t.abspath('.bzr/1//2/./3'),
5560.2.1 by Vincent Ladeuil
Fix the remaining references to http://bazaar-vcs.org (except the explicitly historical ones).
408
           'http://example.com/bzr/bzr.dev/.bzr/1/2/3')
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
409
410
    def test_invalid_http_urls(self):
411
        """Trap invalid construction of urls"""
5560.2.1 by Vincent Ladeuil
Fix the remaining references to http://bazaar-vcs.org (except the explicitly historical ones).
412
        self._transport('http://example.com/bzr/bzr.dev/')
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
413
        self.assertRaises(errors.InvalidURL,
414
                          self._transport,
5560.2.1 by Vincent Ladeuil
Fix the remaining references to http://bazaar-vcs.org (except the explicitly historical ones).
415
                          'http://http://example.com/bzr/bzr.dev/')
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
416
417
    def test_http_root_urls(self):
418
        """Construction of URLs from server root"""
5560.2.1 by Vincent Ladeuil
Fix the remaining references to http://bazaar-vcs.org (except the explicitly historical ones).
419
        t = self._transport('http://example.com/')
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
420
        eq = self.assertEqualDiff
421
        eq(t.abspath('.bzr/tree-version'),
5560.2.1 by Vincent Ladeuil
Fix the remaining references to http://bazaar-vcs.org (except the explicitly historical ones).
422
           'http://example.com/.bzr/tree-version')
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
423
424
    def test_http_impl_urls(self):
425
        """There are servers which ask for particular clients to connect"""
426
        server = self._server()
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
427
        server.start_server()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
428
        try:
429
            url = server.get_url()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
430
            self.assertTrue(url.startswith('%s://' % self._url_protocol))
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
431
        finally:
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
432
            server.stop_server()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
433
434
3111.1.9 by Vincent Ladeuil
Most refactoring regarding parameterization for urllib/pycurl and custom
435
class TestHttps_pycurl(TestWithTransport_pycurl, tests.TestCase):
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
436
437
    # TODO: This should really be moved into another pycurl
438
    # specific test. When https tests will be implemented, take
439
    # this one into account.
440
    def test_pycurl_without_https_support(self):
441
        """Test that pycurl without SSL do not fail with a traceback.
442
443
        For the purpose of the test, we force pycurl to ignore
444
        https by supplying a fake version_info that do not
445
        support it.
446
        """
4913.2.13 by John Arbash Meinel
Finish the pycurl feature.
447
        self.requireFeature(features.pycurl)
4926.1.1 by Vincent Ladeuil
Fix ModuleFeature() side-effect.
448
        # Import the module locally now that we now it's available.
449
        pycurl = features.pycurl.module
3111.1.14 by Vincent Ladeuil
Fix test leakage.
450
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
451
        self.overrideAttr(pycurl, 'version_info',
452
                          # Fake the pycurl version_info This was taken from
453
                          # a windows pycurl without SSL (thanks to bialix)
454
                          lambda : (2,
455
                                    '7.13.2',
456
                                    462082,
457
                                    'i386-pc-win32',
458
                                    2576,
459
                                    None,
460
                                    0,
461
                                    None,
462
                                    ('ftp', 'gopher', 'telnet',
463
                                     'dict', 'ldap', 'http', 'file'),
464
                                    None,
465
                                    0,
466
                                    None))
4926.1.1 by Vincent Ladeuil
Fix ModuleFeature() side-effect.
467
        self.assertRaises(errors.DependencyNotPresent, self._transport,
468
                          'https://launchpad.net')
2294.3.1 by Vincent Ladeuil
Fix #85305 by issuing an exception instead of a traceback.
469
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
470
471
class TestHTTPConnections(http_utils.TestCaseWithWebserver):
472
    """Test the http connections."""
473
5462.3.15 by Martin Pool
Turn variations into scenario lists
474
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
475
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
476
        vary_by_http_protocol_version(),
477
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
478
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
479
    def setUp(self):
480
        http_utils.TestCaseWithWebserver.setUp(self)
481
        self.build_tree(['foo/', 'foo/bar'], line_endings='binary',
482
                        transport=self.get_transport())
483
484
    def test_http_has(self):
485
        server = self.get_readonly_server()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
486
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
487
        self.assertEqual(t.has('foo/bar'), True)
488
        self.assertEqual(len(server.logs), 1)
489
        self.assertContainsRe(server.logs[0],
490
            r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "bzr/')
491
492
    def test_http_has_not_found(self):
493
        server = self.get_readonly_server()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
494
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
495
        self.assertEqual(t.has('not-found'), False)
496
        self.assertContainsRe(server.logs[1],
497
            r'"HEAD /not-found HTTP/1.." 404 - "-" "bzr/')
498
499
    def test_http_get(self):
500
        server = self.get_readonly_server()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
501
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
502
        fp = t.get('foo/bar')
503
        self.assertEqualDiff(
504
            fp.read(),
505
            'contents of foo/bar\n')
506
        self.assertEqual(len(server.logs), 1)
507
        self.assertTrue(server.logs[0].find(
508
            '"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s'
509
            % bzrlib.__version__) > -1)
510
511
    def test_has_on_bogus_host(self):
512
        # Get a free address and don't 'accept' on it, so that we
513
        # can be sure there is no http handler there, but set a
514
        # reasonable timeout to not slow down tests too much.
515
        default_timeout = socket.getdefaulttimeout()
516
        try:
517
            socket.setdefaulttimeout(2)
518
            s = socket.socket()
519
            s.bind(('localhost', 0))
520
            t = self._transport('http://%s:%s/' % s.getsockname())
521
            self.assertRaises(errors.ConnectionError, t.has, 'foo/bar')
522
        finally:
523
            socket.setdefaulttimeout(default_timeout)
524
525
526
class TestHttpTransportRegistration(tests.TestCase):
527
    """Test registrations of various http implementations"""
528
5462.3.15 by Martin Pool
Turn variations into scenario lists
529
    scenarios = vary_by_http_client_implementation()
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
530
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
531
    def test_http_registered(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
532
        t = transport.get_transport('%s://foo.com/' % self._url_protocol)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
533
        self.assertIsInstance(t, transport.Transport)
534
        self.assertIsInstance(t, self._transport)
535
536
537
class TestPost(tests.TestCase):
538
5462.3.15 by Martin Pool
Turn variations into scenario lists
539
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
540
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
541
        vary_by_http_protocol_version(),
542
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
543
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
544
    def test_post_body_is_received(self):
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
545
        server = RecordingServer(expect_body_tail='end-of-body',
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
546
                                 scheme=self._url_protocol)
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
547
        self.start_server(server)
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
548
        url = server.get_url()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
549
        # FIXME: needs a cleanup -- vila 20100611
550
        http_transport = transport.get_transport(url)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
551
        code, response = http_transport._post('abc def end-of-body')
552
        self.assertTrue(
553
            server.received_bytes.startswith('POST /.bzr/smart HTTP/1.'))
554
        self.assertTrue('content-length: 19\r' in server.received_bytes.lower())
5514.1.1 by Vincent Ladeuil
Correctly set the Content-Type header when POSTing.
555
        self.assertTrue('content-type: application/octet-stream\r'
556
                        in server.received_bytes.lower())
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
557
        # The transport should not be assuming that the server can accept
558
        # chunked encoding the first time it connects, because HTTP/1.1, so we
559
        # check for the literal string.
560
        self.assertTrue(
561
            server.received_bytes.endswith('\r\n\r\nabc def end-of-body'))
562
563
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
564
class TestRangeHeader(tests.TestCase):
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
565
    """Test range_header method"""
566
567
    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.
568
        offsets = [ (start, end - start + 1) for start, end in ranges]
3111.1.10 by Vincent Ladeuil
Finish http parameterization, 24 auth tests failing for pycurl (not
569
        coalesce = transport.Transport._coalesce_offsets
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
570
        coalesced = list(coalesce(offsets, limit=0, fudge_factor=0))
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
571
        range_header = http.HttpTransportBase._range_header
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
572
        self.assertEqual(value, range_header(coalesced, tail))
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
573
574
    def test_range_header_single(self):
2520.2.1 by Vincent Ladeuil
First step to fix #115209 use _coalesce_offsets like other transports.
575
        self.check_header('0-9', ranges=[(0,9)])
576
        self.check_header('100-109', ranges=[(100,109)])
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
577
578
    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=
579
        self.check_header('-10', tail=10)
580
        self.check_header('-50', tail=50)
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
581
582
    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=
583
        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
584
                          ranges=[(0,9), (100, 200), (300,5000)])
585
586
    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=
587
        self.check_header('0-9,300-5000,-50',
1786.1.28 by John Arbash Meinel
Update and add tests for the HttpTransportBase.range_header
588
                          ranges=[(0,9), (300,5000)],
589
                          tail=50)
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
590
2004.1.15 by v.ladeuil+lp at free
Better design for bogus servers. Both urllib and pycurl pass tests.
591
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
592
class TestSpecificRequestHandler(http_utils.TestCaseWithWebserver):
593
    """Tests a specific request handler.
594
3111.1.31 by Vincent Ladeuil
Review feeback.
595
    Daughter classes are expected to override _req_handler_class
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
596
    """
597
5462.3.15 by Martin Pool
Turn variations into scenario lists
598
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
599
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
600
        vary_by_http_protocol_version(),
601
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
602
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
603
    # Provide a useful default
604
    _req_handler_class = http_server.TestingHTTPRequestHandler
605
606
    def create_transport_readonly_server(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
607
        server = http_server.HttpServer(self._req_handler_class,
608
                                        protocol_version=self._protocol_version)
609
        server._url_protocol = self._url_protocol
610
        return server
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
611
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
612
    def _testing_pycurl(self):
4913.2.11 by John Arbash Meinel
Convert a bunch more features over to ModuleAvailableFeature
613
        # TODO: This is duplicated for lots of the classes in this file
614
        return (features.pycurl.available()
615
                and self._transport == PyCurlTransport)
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
616
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
617
618
class WallRequestHandler(http_server.TestingHTTPRequestHandler):
619
    """Whatever request comes in, close the connection"""
620
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
621
    def _handle_one_request(self):
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
622
        """Handle a single HTTP request, by abruptly closing the connection"""
623
        self.close_connection = 1
624
625
626
class TestWallServer(TestSpecificRequestHandler):
627
    """Tests exceptions during the connection phase"""
628
629
    _req_handler_class = WallRequestHandler
630
631
    def test_http_has(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
632
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
633
        # Unfortunately httplib (see HTTPResponse._read_status
634
        # for details) make no distinction between a closed
635
        # socket and badly formatted status line, so we can't
636
        # just test for ConnectionError, we have to test
4628.1.2 by Vincent Ladeuil
More complete fix.
637
        # InvalidHttpResponse too. And pycurl may raise ConnectionReset
638
        # instead of ConnectionError too.
639
        self.assertRaises(( errors.ConnectionError, errors.ConnectionReset,
640
                            errors.InvalidHttpResponse),
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
641
                          t.has, 'foo/bar')
642
643
    def test_http_get(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
644
        t = self.get_readonly_transport()
4628.1.2 by Vincent Ladeuil
More complete fix.
645
        self.assertRaises((errors.ConnectionError, errors.ConnectionReset,
646
                           errors.InvalidHttpResponse),
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
647
                          t.get, 'foo/bar')
648
649
650
class BadStatusRequestHandler(http_server.TestingHTTPRequestHandler):
651
    """Whatever request comes in, returns a bad status"""
652
653
    def parse_request(self):
654
        """Fakes handling a single HTTP request, returns a bad status"""
655
        ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
656
        self.send_response(0, "Bad status")
657
        self.close_connection = 1
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
658
        return False
659
660
661
class TestBadStatusServer(TestSpecificRequestHandler):
662
    """Tests bad status from server."""
663
664
    _req_handler_class = BadStatusRequestHandler
665
666
    def test_http_has(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
667
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
668
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
669
670
    def test_http_get(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
671
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
672
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
673
674
675
class InvalidStatusRequestHandler(http_server.TestingHTTPRequestHandler):
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
676
    """Whatever request comes in, returns an invalid status"""
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
677
678
    def parse_request(self):
679
        """Fakes handling a single HTTP request, returns a bad status"""
680
        ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
681
        self.wfile.write("Invalid status line\r\n")
5247.6.6 by Vincent Ladeuil
Closing the connection is what pycurl was waiting for.
682
        # If we don't close the connection pycurl will hang. Since this is a
683
        # stress test we don't *have* to respect the protocol, but we don't
684
        # have to sabotage it too much either.
685
        self.close_connection = True
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
686
        return False
687
688
689
class TestInvalidStatusServer(TestBadStatusServer):
690
    """Tests invalid status from server.
691
692
    Both implementations raises the same error as for a bad status.
693
    """
694
695
    _req_handler_class = InvalidStatusRequestHandler
696
697
698
class BadProtocolRequestHandler(http_server.TestingHTTPRequestHandler):
699
    """Whatever request comes in, returns a bad protocol version"""
700
701
    def parse_request(self):
702
        """Fakes handling a single HTTP request, returns a bad status"""
703
        ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
704
        # Returns an invalid protocol version, but curl just
705
        # ignores it and those cannot be tested.
706
        self.wfile.write("%s %d %s\r\n" % ('HTTP/0.0',
707
                                           404,
708
                                           'Look at my protocol version'))
709
        return False
710
711
712
class TestBadProtocolServer(TestSpecificRequestHandler):
713
    """Tests bad protocol from server."""
714
715
    _req_handler_class = BadProtocolRequestHandler
716
717
    def setUp(self):
4913.2.11 by John Arbash Meinel
Convert a bunch more features over to ModuleAvailableFeature
718
        if self._testing_pycurl():
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
719
            raise tests.TestNotApplicable(
720
                "pycurl doesn't check the protocol version")
721
        super(TestBadProtocolServer, self).setUp()
722
723
    def test_http_has(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
724
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
725
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
726
727
    def test_http_get(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
728
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
729
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
730
731
732
class ForbiddenRequestHandler(http_server.TestingHTTPRequestHandler):
733
    """Whatever request comes in, returns a 403 code"""
734
735
    def parse_request(self):
736
        """Handle a single HTTP request, by replying we cannot handle it"""
737
        ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
738
        self.send_error(403)
739
        return False
740
741
742
class TestForbiddenServer(TestSpecificRequestHandler):
743
    """Tests forbidden server"""
744
745
    _req_handler_class = ForbiddenRequestHandler
746
747
    def test_http_has(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
748
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
749
        self.assertRaises(errors.TransportError, t.has, 'foo/bar')
750
751
    def test_http_get(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
752
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
753
        self.assertRaises(errors.TransportError, t.get, 'foo/bar')
754
755
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
756
class TestRecordingServer(tests.TestCase):
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
757
758
    def test_create(self):
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
759
        server = RecordingServer(expect_body_tail=None)
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
760
        self.assertEqual('', server.received_bytes)
761
        self.assertEqual(None, server.host)
762
        self.assertEqual(None, server.port)
763
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
764
    def test_setUp_and_stop(self):
3111.1.29 by Vincent Ladeuil
Cancel RecordingServer move, that was useless.
765
        server = RecordingServer(expect_body_tail=None)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
766
        server.start_server()
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
767
        try:
768
            self.assertNotEqual(None, server.host)
769
            self.assertNotEqual(None, server.port)
770
        finally:
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
771
            server.stop_server()
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
772
        self.assertEqual(None, server.host)
773
        self.assertEqual(None, server.port)
774
775
    def test_send_receive_bytes(self):
4691.2.1 by Robert Collins
Add stronger test isolation by interception BzrDir.open and checking the thing being opened is known to the test suite.
776
        server = RecordingServer(expect_body_tail='c', scheme='http')
4659.1.2 by Robert Collins
Refactor creation and shutdown of test servers to use a common helper,
777
        self.start_server(server)
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
778
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
779
        sock.connect((server.host, server.port))
5011.3.11 by Andrew Bennetts
Consolidate changes, try to minimise unnecessary changes and tidy up those that kept.
780
        sock.sendall('abc')
781
        self.assertEqual('HTTP/1.1 200 OK\r\n',
782
                         osutils.recv_all(sock, 4096))
2018.2.9 by Andrew Bennetts
(Andrew Bennetts, Robert Collins) Add test_http.RecordingServer, and use it to
783
        self.assertEqual('abc', server.received_bytes)
2004.1.29 by v.ladeuil+lp at free
New tests for http range requests handling.
784
785
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
786
class TestRangeRequestServer(TestSpecificRequestHandler):
787
    """Tests readv requests against server.
788
789
    We test against default "normal" server.
790
    """
791
792
    def setUp(self):
793
        super(TestRangeRequestServer, self).setUp()
794
        self.build_tree_contents([('a', '0123456789')],)
795
796
    def test_readv(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
797
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
798
        l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
799
        self.assertEqual(l[0], (0, '0'))
800
        self.assertEqual(l[1], (1, '1'))
801
        self.assertEqual(l[2], (3, '34'))
802
        self.assertEqual(l[3], (9, '9'))
803
804
    def test_readv_out_of_order(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
805
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
806
        l = list(t.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
807
        self.assertEqual(l[0], (1, '1'))
808
        self.assertEqual(l[1], (9, '9'))
809
        self.assertEqual(l[2], (0, '0'))
810
        self.assertEqual(l[3], (3, '34'))
811
812
    def test_readv_invalid_ranges(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
813
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
814
815
        # This is intentionally reading off the end of the file
816
        # since we are sure that it cannot get there
817
        self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
818
                              t.readv, 'a', [(1,1), (8,10)])
819
820
        # This is trying to seek past the end of the file, it should
821
        # also raise a special error
822
        self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
823
                              t.readv, 'a', [(12,2)])
824
825
    def test_readv_multiple_get_requests(self):
826
        server = self.get_readonly_server()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
827
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
828
        # force transport to issue multiple requests
829
        t._max_readv_combine = 1
830
        t._max_get_ranges = 1
831
        l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
832
        self.assertEqual(l[0], (0, '0'))
833
        self.assertEqual(l[1], (1, '1'))
834
        self.assertEqual(l[2], (3, '34'))
835
        self.assertEqual(l[3], (9, '9'))
836
        # The server should have issued 4 requests
837
        self.assertEqual(4, server.GET_request_nb)
838
839
    def test_readv_get_max_size(self):
840
        server = self.get_readonly_server()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
841
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
842
        # force transport to issue multiple requests by limiting the number of
843
        # bytes by request. Note that this apply to coalesced offsets only, a
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
844
        # single range will keep its size even if bigger than the limit.
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
845
        t._get_max_size = 2
846
        l = list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
847
        self.assertEqual(l[0], (0, '0'))
848
        self.assertEqual(l[1], (1, '1'))
849
        self.assertEqual(l[2], (2, '2345'))
850
        self.assertEqual(l[3], (6, '6789'))
851
        # The server should have issued 3 requests
852
        self.assertEqual(3, server.GET_request_nb)
853
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
854
    def test_complete_readv_leave_pipe_clean(self):
855
        server = self.get_readonly_server()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
856
        t = self.get_readonly_transport()
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
857
        # force transport to issue multiple requests
858
        t._get_max_size = 2
5462.3.16 by Martin Pool
pyflakes cleanups
859
        list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
860
        # The server should have issued 3 requests
861
        self.assertEqual(3, server.GET_request_nb)
862
        self.assertEqual('0123456789', t.get_bytes('a'))
863
        self.assertEqual(4, server.GET_request_nb)
864
865
    def test_incomplete_readv_leave_pipe_clean(self):
866
        server = self.get_readonly_server()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
867
        t = self.get_readonly_transport()
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
868
        # force transport to issue multiple requests
869
        t._get_max_size = 2
870
        # Don't collapse readv results into a list so that we leave unread
871
        # bytes on the socket
872
        ireadv = iter(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
873
        self.assertEqual((0, '0'), ireadv.next())
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
874
        # The server should have issued one request so far
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
875
        self.assertEqual(1, server.GET_request_nb)
876
        self.assertEqual('0123456789', t.get_bytes('a'))
877
        # get_bytes issued an additional request, the readv pending ones are
878
        # lost
879
        self.assertEqual(2, server.GET_request_nb)
880
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
881
882
class SingleRangeRequestHandler(http_server.TestingHTTPRequestHandler):
883
    """Always reply to range request as if they were single.
884
885
    Don't be explicit about it, just to annoy the clients.
886
    """
887
888
    def get_multiple_ranges(self, file, file_size, ranges):
889
        """Answer as if it was a single range request and ignores the rest"""
890
        (start, end) = ranges[0]
891
        return self.get_single_range(file, file_size, start, end)
892
893
894
class TestSingleRangeRequestServer(TestRangeRequestServer):
895
    """Test readv against a server which accept only single range requests"""
896
897
    _req_handler_class = SingleRangeRequestHandler
898
899
900
class SingleOnlyRangeRequestHandler(http_server.TestingHTTPRequestHandler):
901
    """Only reply to simple range requests, errors out on multiple"""
902
903
    def get_multiple_ranges(self, file, file_size, ranges):
904
        """Refuses the multiple ranges request"""
905
        if len(ranges) > 1:
906
            file.close()
907
            self.send_error(416, "Requested range not satisfiable")
908
            return
909
        (start, end) = ranges[0]
910
        return self.get_single_range(file, file_size, start, end)
911
912
913
class TestSingleOnlyRangeRequestServer(TestRangeRequestServer):
914
    """Test readv against a server which only accept single range requests"""
915
916
    _req_handler_class = SingleOnlyRangeRequestHandler
917
918
919
class NoRangeRequestHandler(http_server.TestingHTTPRequestHandler):
920
    """Ignore range requests without notice"""
921
922
    def do_GET(self):
923
        # Update the statistics
924
        self.server.test_case_server.GET_request_nb += 1
925
        # Just bypass the range handling done by TestingHTTPRequestHandler
926
        return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
927
928
929
class TestNoRangeRequestServer(TestRangeRequestServer):
930
    """Test readv against a server which do not accept range requests"""
931
932
    _req_handler_class = NoRangeRequestHandler
933
934
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
935
class MultipleRangeWithoutContentLengthRequestHandler(
936
    http_server.TestingHTTPRequestHandler):
937
    """Reply to multiple range requests without content length header."""
938
939
    def get_multiple_ranges(self, file, file_size, ranges):
940
        self.send_response(206)
941
        self.send_header('Accept-Ranges', 'bytes')
5462.3.16 by Martin Pool
pyflakes cleanups
942
        # XXX: this is strange; the 'random' name below seems undefined and
5462.3.19 by Martin Pool
Mention bug 658773 in comment
943
        # yet the tests pass -- mbp 2010-10-11 bug 658773
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
944
        boundary = "%d" % random.randint(0,0x7FFFFFFF)
945
        self.send_header("Content-Type",
946
                         "multipart/byteranges; boundary=%s" % boundary)
947
        self.end_headers()
948
        for (start, end) in ranges:
949
            self.wfile.write("--%s\r\n" % boundary)
950
            self.send_header("Content-type", 'application/octet-stream')
951
            self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
952
                                                                  end,
953
                                                                  file_size))
954
            self.end_headers()
955
            self.send_range_content(file, start, end - start + 1)
956
        # Final boundary
957
        self.wfile.write("--%s\r\n" % boundary)
958
959
960
class TestMultipleRangeWithoutContentLengthServer(TestRangeRequestServer):
961
962
    _req_handler_class = MultipleRangeWithoutContentLengthRequestHandler
963
3146.3.2 by Vincent Ladeuil
Fix #179368 by keeping the current range hint on ShortReadvErrors.
964
965
class TruncatedMultipleRangeRequestHandler(
966
    http_server.TestingHTTPRequestHandler):
967
    """Reply to multiple range requests truncating the last ones.
968
969
    This server generates responses whose Content-Length describes all the
970
    ranges, but fail to include the last ones leading to client short reads.
971
    This has been observed randomly with lighttpd (bug #179368).
972
    """
973
974
    _truncated_ranges = 2
975
976
    def get_multiple_ranges(self, file, file_size, ranges):
977
        self.send_response(206)
978
        self.send_header('Accept-Ranges', 'bytes')
979
        boundary = 'tagada'
980
        self.send_header('Content-Type',
981
                         'multipart/byteranges; boundary=%s' % boundary)
982
        boundary_line = '--%s\r\n' % boundary
983
        # Calculate the Content-Length
984
        content_length = 0
985
        for (start, end) in ranges:
986
            content_length += len(boundary_line)
987
            content_length += self._header_line_length(
988
                'Content-type', 'application/octet-stream')
989
            content_length += self._header_line_length(
990
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
991
            content_length += len('\r\n') # end headers
992
            content_length += end - start # + 1
993
        content_length += len(boundary_line)
994
        self.send_header('Content-length', content_length)
995
        self.end_headers()
996
997
        # Send the multipart body
998
        cur = 0
999
        for (start, end) in ranges:
1000
            self.wfile.write(boundary_line)
1001
            self.send_header('Content-type', 'application/octet-stream')
1002
            self.send_header('Content-Range', 'bytes %d-%d/%d'
1003
                             % (start, end, file_size))
1004
            self.end_headers()
1005
            if cur + self._truncated_ranges >= len(ranges):
1006
                # Abruptly ends the response and close the connection
1007
                self.close_connection = 1
1008
                return
1009
            self.send_range_content(file, start, end - start + 1)
1010
            cur += 1
5504.4.1 by Vincent Ladeuil
Fix http test spurious failures and get rid of some useless messages in log.
1011
        # Final boundary
3146.3.2 by Vincent Ladeuil
Fix #179368 by keeping the current range hint on ShortReadvErrors.
1012
        self.wfile.write(boundary_line)
1013
1014
1015
class TestTruncatedMultipleRangeServer(TestSpecificRequestHandler):
1016
1017
    _req_handler_class = TruncatedMultipleRangeRequestHandler
1018
1019
    def setUp(self):
1020
        super(TestTruncatedMultipleRangeServer, self).setUp()
1021
        self.build_tree_contents([('a', '0123456789')],)
1022
1023
    def test_readv_with_short_reads(self):
1024
        server = self.get_readonly_server()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1025
        t = self.get_readonly_transport()
3146.3.2 by Vincent Ladeuil
Fix #179368 by keeping the current range hint on ShortReadvErrors.
1026
        # Force separate ranges for each offset
1027
        t._bytes_to_read_before_seek = 0
1028
        ireadv = iter(t.readv('a', ((0, 1), (2, 1), (4, 2), (9, 1))))
1029
        self.assertEqual((0, '0'), ireadv.next())
1030
        self.assertEqual((2, '2'), ireadv.next())
1031
        if not self._testing_pycurl():
1032
            # Only one request have been issued so far (except for pycurl that
1033
            # try to read the whole response at once)
1034
            self.assertEqual(1, server.GET_request_nb)
1035
        self.assertEqual((4, '45'), ireadv.next())
1036
        self.assertEqual((9, '9'), ireadv.next())
1037
        # Both implementations issue 3 requests but:
1038
        # - urllib does two multiple (4 ranges, then 2 ranges) then a single
1039
        #   range,
1040
        # - pycurl does two multiple (4 ranges, 4 ranges) then a single range
1041
        self.assertEqual(3, server.GET_request_nb)
1042
        # Finally the client have tried a single range request and stays in
1043
        # that mode
1044
        self.assertEqual('single', t._range_hint)
1045
5504.4.1 by Vincent Ladeuil
Fix http test spurious failures and get rid of some useless messages in log.
1046
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1047
class LimitedRangeRequestHandler(http_server.TestingHTTPRequestHandler):
1048
    """Errors out when range specifiers exceed the limit"""
1049
1050
    def get_multiple_ranges(self, file, file_size, ranges):
1051
        """Refuses the multiple ranges request"""
1052
        tcs = self.server.test_case_server
1053
        if tcs.range_limit is not None and len(ranges) > tcs.range_limit:
1054
            file.close()
1055
            # Emulate apache behavior
1056
            self.send_error(400, "Bad Request")
1057
            return
1058
        return http_server.TestingHTTPRequestHandler.get_multiple_ranges(
1059
            self, file, file_size, ranges)
1060
1061
1062
class LimitedRangeHTTPServer(http_server.HttpServer):
1063
    """An HttpServer erroring out on requests with too much range specifiers"""
1064
1065
    def __init__(self, request_handler=LimitedRangeRequestHandler,
1066
                 protocol_version=None,
1067
                 range_limit=None):
1068
        http_server.HttpServer.__init__(self, request_handler,
1069
                                        protocol_version=protocol_version)
1070
        self.range_limit = range_limit
1071
1072
1073
class TestLimitedRangeRequestServer(http_utils.TestCaseWithWebserver):
1074
    """Tests readv requests against a server erroring out on too much ranges."""
1075
5462.3.15 by Martin Pool
Turn variations into scenario lists
1076
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1077
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
1078
        vary_by_http_protocol_version(),
1079
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1080
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
1081
    # Requests with more range specifiers will error out
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1082
    range_limit = 3
1083
1084
    def create_transport_readonly_server(self):
1085
        return LimitedRangeHTTPServer(range_limit=self.range_limit,
1086
                                      protocol_version=self._protocol_version)
1087
1088
    def setUp(self):
1089
        http_utils.TestCaseWithWebserver.setUp(self)
1090
        # We need to manipulate ranges that correspond to real chunks in the
1091
        # response, so we build a content appropriately.
1092
        filler = ''.join(['abcdefghij' for x in range(102)])
1093
        content = ''.join(['%04d' % v + filler for v in range(16)])
1094
        self.build_tree_contents([('a', content)],)
1095
1096
    def test_few_ranges(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1097
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1098
        l = list(t.readv('a', ((0, 4), (1024, 4), )))
1099
        self.assertEqual(l[0], (0, '0000'))
1100
        self.assertEqual(l[1], (1024, '0001'))
1101
        self.assertEqual(1, self.get_readonly_server().GET_request_nb)
1102
1103
    def test_more_ranges(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1104
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1105
        l = list(t.readv('a', ((0, 4), (1024, 4), (4096, 4), (8192, 4))))
1106
        self.assertEqual(l[0], (0, '0000'))
1107
        self.assertEqual(l[1], (1024, '0001'))
1108
        self.assertEqual(l[2], (4096, '0004'))
1109
        self.assertEqual(l[3], (8192, '0008'))
1110
        # The server will refuse to serve the first request (too much ranges),
3199.1.2 by Vincent Ladeuil
Fix two more leaked log files.
1111
        # a second request will succeed.
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1112
        self.assertEqual(2, self.get_readonly_server().GET_request_nb)
1113
1114
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
1115
class TestHttpProxyWhiteBox(tests.TestCase):
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
1116
    """Whitebox test proxy http authorization.
1117
2420.1.3 by Vincent Ladeuil
Implement http proxy basic authentication.
1118
    Only the urllib implementation is tested here.
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
1119
    """
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
1120
1121
    def _proxied_request(self):
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
1122
        handler = _urllib2_wrappers.ProxyHandler()
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1123
        request = _urllib2_wrappers.Request('GET', 'http://baz/buzzle')
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
1124
        handler.set_proxy(request, 'http')
1125
        return request
1126
5639.2.2 by Vincent Ladeuil
Add tests and comments to clarify the feature.
1127
    def assertEvaluateProxyBypass(self, expected, host, no_proxy):
1128
        handler = _urllib2_wrappers.ProxyHandler()
1129
        self.assertEquals(expected,
1130
                          handler.evaluate_proxy_bypass(host, no_proxy))
1131
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
1132
    def test_empty_user(self):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1133
        self.overrideEnv('http_proxy', 'http://bar.com')
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
1134
        request = self._proxied_request()
1135
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1136
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1137
    def test_user_with_at(self):
1138
        self.overrideEnv('http_proxy',
1139
                         'http://username@domain:password@proxy_host:1234')
1140
        request = self._proxied_request()
1141
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1142
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
1143
    def test_invalid_proxy(self):
1144
        """A proxy env variable without scheme"""
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1145
        self.overrideEnv('http_proxy', 'host:1234')
2298.7.1 by Vincent Ladeuil
Fix bug #87765: proxy env variables without scheme should cause
1146
        self.assertRaises(errors.InvalidURL, self._proxied_request)
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
1147
5639.2.2 by Vincent Ladeuil
Add tests and comments to clarify the feature.
1148
    def test_evaluate_proxy_bypass_true(self):
1149
        """The host is not proxied"""
1150
        self.assertEvaluateProxyBypass(True, 'example.com', 'example.com')
1151
        self.assertEvaluateProxyBypass(True, 'bzr.example.com', '*example.com')
1152
1153
    def test_evaluate_proxy_bypass_false(self):
1154
        """The host is proxied"""
1155
        self.assertEvaluateProxyBypass(False, 'bzr.example.com', None)
1156
1157
    def test_evaluate_proxy_bypass_unknown(self):
1158
        """The host is not explicitly proxied"""
1159
        self.assertEvaluateProxyBypass(None, 'example.com', 'not.example.com')
1160
        self.assertEvaluateProxyBypass(None, 'bzr.example.com', 'example.com')
1161
1162
    def test_evaluate_proxy_bypass_empty_entries(self):
1163
        """Ignore empty entries"""
1164
        self.assertEvaluateProxyBypass(None, 'example.com', '')
1165
        self.assertEvaluateProxyBypass(None, 'example.com', ',')
1166
        self.assertEvaluateProxyBypass(None, 'example.com', 'foo,,bar')
5639.2.1 by Martin Pool
Empty entries in the ``NO_PROXY`` variable are no longer treated as matching every host.
1167
2273.2.2 by v.ladeuil+lp at free
Really fix bug #83954, with tests.
1168
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1169
class TestProxyHttpServer(http_utils.TestCaseWithTwoWebservers):
1170
    """Tests proxy server.
1171
1172
    Be aware that we do not setup a real proxy here. Instead, we
1173
    check that the *connection* goes through the proxy by serving
1174
    different content (the faked proxy server append '-proxied'
1175
    to the file names).
1176
    """
1177
5462.3.15 by Martin Pool
Turn variations into scenario lists
1178
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1179
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
1180
        vary_by_http_protocol_version(),
1181
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1182
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1183
    # FIXME: We don't have an https server available, so we don't
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1184
    # test https connections. --vila toolongago
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1185
1186
    def setUp(self):
1187
        super(TestProxyHttpServer, self).setUp()
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1188
        self.transport_secondary_server = http_utils.ProxyServer
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1189
        self.build_tree_contents([('foo', 'contents of foo\n'),
1190
                                  ('foo-proxied', 'proxied contents of foo\n')])
1191
        # Let's setup some attributes for tests
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1192
        server = self.get_readonly_server()
1193
        self.server_host_port = '%s:%d' % (server.host, server.port)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1194
        if self._testing_pycurl():
1195
            # Oh my ! pycurl does not check for the port as part of
1196
            # no_proxy :-( So we just test the host part
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1197
            self.no_proxy_host = server.host
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1198
        else:
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1199
            self.no_proxy_host = self.server_host_port
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1200
        # The secondary server is the proxy
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1201
        self.proxy_url = self.get_secondary_url()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1202
1203
    def _testing_pycurl(self):
4913.2.11 by John Arbash Meinel
Convert a bunch more features over to ModuleAvailableFeature
1204
        # TODO: This is duplicated for lots of the classes in this file
1205
        return (features.pycurl.available()
1206
                and self._transport == PyCurlTransport)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1207
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1208
    def assertProxied(self):
1209
        t = self.get_readonly_transport()
1210
        self.assertEqual('proxied contents of foo\n', t.get('foo').read())
1211
1212
    def assertNotProxied(self):
1213
        t = self.get_readonly_transport()
1214
        self.assertEqual('contents of foo\n', t.get('foo').read())
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1215
1216
    def test_http_proxy(self):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1217
        self.overrideEnv('http_proxy', self.proxy_url)
1218
        self.assertProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1219
1220
    def test_HTTP_PROXY(self):
1221
        if self._testing_pycurl():
1222
            # pycurl does not check HTTP_PROXY for security reasons
1223
            # (for use in a CGI context that we do not care
1224
            # about. Should we ?)
1225
            raise tests.TestNotApplicable(
1226
                'pycurl does not check HTTP_PROXY for security reasons')
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1227
        self.overrideEnv('HTTP_PROXY', self.proxy_url)
1228
        self.assertProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1229
1230
    def test_all_proxy(self):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1231
        self.overrideEnv('all_proxy', self.proxy_url)
1232
        self.assertProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1233
1234
    def test_ALL_PROXY(self):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1235
        self.overrideEnv('ALL_PROXY', self.proxy_url)
1236
        self.assertProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1237
1238
    def test_http_proxy_with_no_proxy(self):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1239
        self.overrideEnv('no_proxy', self.no_proxy_host)
1240
        self.overrideEnv('http_proxy', self.proxy_url)
1241
        self.assertNotProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1242
1243
    def test_HTTP_PROXY_with_NO_PROXY(self):
1244
        if self._testing_pycurl():
1245
            raise tests.TestNotApplicable(
1246
                'pycurl does not check HTTP_PROXY for security reasons')
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1247
        self.overrideEnv('NO_PROXY', self.no_proxy_host)
1248
        self.overrideEnv('HTTP_PROXY', self.proxy_url)
1249
        self.assertNotProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1250
1251
    def test_all_proxy_with_no_proxy(self):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1252
        self.overrideEnv('no_proxy', self.no_proxy_host)
1253
        self.overrideEnv('all_proxy', self.proxy_url)
1254
        self.assertNotProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1255
1256
    def test_ALL_PROXY_with_NO_PROXY(self):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1257
        self.overrideEnv('NO_PROXY', self.no_proxy_host)
1258
        self.overrideEnv('ALL_PROXY', self.proxy_url)
1259
        self.assertNotProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1260
1261
    def test_http_proxy_without_scheme(self):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1262
        self.overrideEnv('http_proxy', self.server_host_port)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1263
        if self._testing_pycurl():
1264
            # pycurl *ignores* invalid proxy env variables. If that ever change
1265
            # in the future, this test will fail indicating that pycurl do not
1266
            # ignore anymore such variables.
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1267
            self.assertNotProxied()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1268
        else:
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1269
            self.assertRaises(errors.InvalidURL, self.assertProxied)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1270
1271
1272
class TestRanges(http_utils.TestCaseWithWebserver):
1273
    """Test the Range header in GET methods."""
1274
5462.3.15 by Martin Pool
Turn variations into scenario lists
1275
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1276
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
1277
        vary_by_http_protocol_version(),
1278
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1279
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1280
    def setUp(self):
1281
        http_utils.TestCaseWithWebserver.setUp(self)
1282
        self.build_tree_contents([('a', '0123456789')],)
1283
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
1284
    def create_transport_readonly_server(self):
1285
        return http_server.HttpServer(protocol_version=self._protocol_version)
1286
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1287
    def _file_contents(self, relpath, ranges):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1288
        t = self.get_readonly_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1289
        offsets = [ (start, end - start + 1) for start, end in ranges]
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1290
        coalesce = t._coalesce_offsets
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1291
        coalesced = list(coalesce(offsets, limit=0, fudge_factor=0))
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1292
        code, data = t._get(relpath, coalesced)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1293
        self.assertTrue(code in (200, 206),'_get returns: %d' % code)
1294
        for start, end in ranges:
1295
            data.seek(start)
1296
            yield data.read(end - start + 1)
1297
1298
    def _file_tail(self, relpath, tail_amount):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1299
        t = self.get_readonly_transport()
1300
        code, data = t._get(relpath, [], tail_amount)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1301
        self.assertTrue(code in (200, 206),'_get returns: %d' % code)
1302
        data.seek(-tail_amount, 2)
1303
        return data.read(tail_amount)
1304
1305
    def test_range_header(self):
1306
        # Valid ranges
1307
        map(self.assertEqual,['0', '234'],
1308
            list(self._file_contents('a', [(0,0), (2,4)])),)
1309
1310
    def test_range_header_tail(self):
1311
        self.assertEqual('789', self._file_tail('a', 3))
1312
1313
    def test_syntactically_invalid_range_header(self):
1314
        self.assertListRaises(errors.InvalidHttpRange,
1315
                          self._file_contents, 'a', [(4, 3)])
1316
1317
    def test_semantically_invalid_range_header(self):
1318
        self.assertListRaises(errors.InvalidHttpRange,
1319
                          self._file_contents, 'a', [(42, 128)])
1320
1321
1322
class TestHTTPRedirections(http_utils.TestCaseWithRedirectedWebserver):
1323
    """Test redirection between http servers."""
1324
5462.3.15 by Martin Pool
Turn variations into scenario lists
1325
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1326
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
1327
        vary_by_http_protocol_version(),
1328
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1329
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1330
    def setUp(self):
1331
        super(TestHTTPRedirections, self).setUp()
1332
        self.build_tree_contents([('a', '0123456789'),
1333
                                  ('bundle',
1334
                                  '# Bazaar revision bundle v0.9\n#\n')
1335
                                  ],)
1336
1337
    def test_redirected(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1338
        self.assertRaises(errors.RedirectRequested,
1339
                          self.get_old_transport().get, 'a')
1340
        self.assertEqual('0123456789', self.get_new_transport().get('a').read())
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1341
1342
1343
class RedirectedRequest(_urllib2_wrappers.Request):
1344
    """Request following redirections. """
1345
1346
    init_orig = _urllib2_wrappers.Request.__init__
1347
1348
    def __init__(self, method, url, *args, **kwargs):
1349
        """Constructor.
1350
1351
        """
1352
        # Since the tests using this class will replace
1353
        # _urllib2_wrappers.Request, we can't just call the base class __init__
1354
        # or we'll loop.
4208.3.2 by Andrew Bennetts
Fix one test failure in test_http under Python 2.7a0.
1355
        RedirectedRequest.init_orig(self, method, url, *args, **kwargs)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1356
        self.follow_redirections = True
1357
1358
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
1359
def install_redirected_request(test):
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
1360
    test.overrideAttr(_urllib2_wrappers, 'Request', RedirectedRequest)
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
1361
1362
5247.2.26 by Vincent Ladeuil
Fix http redirection socket leaks.
1363
def cleanup_http_redirection_connections(test):
1364
    # Some sockets are opened but never seen by _urllib, so we trap them at
1365
    # the _urllib2_wrappers level to be able to clean them up.
1366
    def socket_disconnect(sock):
1367
        try:
1368
            sock.shutdown(socket.SHUT_RDWR)
1369
            sock.close()
1370
        except socket.error:
1371
            pass
1372
    def connect(connection):
1373
        test.http_connect_orig(connection)
1374
        test.addCleanup(socket_disconnect, connection.sock)
1375
    test.http_connect_orig = test.overrideAttr(
1376
        _urllib2_wrappers.HTTPConnection, 'connect', connect)
1377
    def connect(connection):
1378
        test.https_connect_orig(connection)
1379
        test.addCleanup(socket_disconnect, connection.sock)
1380
    test.https_connect_orig = test.overrideAttr(
1381
        _urllib2_wrappers.HTTPSConnection, 'connect', connect)
1382
1383
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1384
class TestHTTPSilentRedirections(http_utils.TestCaseWithRedirectedWebserver):
1385
    """Test redirections.
1386
1387
    http implementations do not redirect silently anymore (they
1388
    do not redirect at all in fact). The mechanism is still in
1389
    place at the _urllib2_wrappers.Request level and these tests
1390
    exercise it.
1391
1392
    For the pycurl implementation
1393
    the redirection have been deleted as we may deprecate pycurl
1394
    and I have no place to keep a working implementation.
1395
    -- vila 20070212
1396
    """
1397
5462.3.15 by Martin Pool
Turn variations into scenario lists
1398
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1399
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
1400
        vary_by_http_protocol_version(),
1401
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1402
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1403
    def setUp(self):
4913.2.11 by John Arbash Meinel
Convert a bunch more features over to ModuleAvailableFeature
1404
        if (features.pycurl.available()
1405
            and self._transport == PyCurlTransport):
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1406
            raise tests.TestNotApplicable(
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1407
                "pycurl doesn't redirect silently anymore")
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1408
        super(TestHTTPSilentRedirections, self).setUp()
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
1409
        install_redirected_request(self)
5247.2.26 by Vincent Ladeuil
Fix http redirection socket leaks.
1410
        cleanup_http_redirection_connections(self)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1411
        self.build_tree_contents([('a','a'),
1412
                                  ('1/',),
1413
                                  ('1/a', 'redirected once'),
1414
                                  ('2/',),
1415
                                  ('2/a', 'redirected twice'),
1416
                                  ('3/',),
1417
                                  ('3/a', 'redirected thrice'),
1418
                                  ('4/',),
1419
                                  ('4/a', 'redirected 4 times'),
1420
                                  ('5/',),
1421
                                  ('5/a', 'redirected 5 times'),
1422
                                  ],)
1423
1424
    def test_one_redirection(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1425
        t = self.get_old_transport()
1426
        req = RedirectedRequest('GET', t._remote_path('a'))
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1427
        new_prefix = 'http://%s:%s' % (self.new_server.host,
1428
                                       self.new_server.port)
1429
        self.old_server.redirections = \
1430
            [('(.*)', r'%s/1\1' % (new_prefix), 301),]
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1431
        self.assertEqual('redirected once', t._perform(req).read())
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1432
1433
    def test_five_redirections(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1434
        t = self.get_old_transport()
1435
        req = RedirectedRequest('GET', t._remote_path('a'))
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1436
        old_prefix = 'http://%s:%s' % (self.old_server.host,
1437
                                       self.old_server.port)
1438
        new_prefix = 'http://%s:%s' % (self.new_server.host,
1439
                                       self.new_server.port)
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
1440
        self.old_server.redirections = [
1441
            ('/1(.*)', r'%s/2\1' % (old_prefix), 302),
1442
            ('/2(.*)', r'%s/3\1' % (old_prefix), 303),
1443
            ('/3(.*)', r'%s/4\1' % (old_prefix), 307),
1444
            ('/4(.*)', r'%s/5\1' % (new_prefix), 301),
1445
            ('(/[^/]+)', r'%s/1\1' % (old_prefix), 301),
1446
            ]
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1447
        self.assertEqual('redirected 5 times', t._perform(req).read())
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1448
1449
1450
class TestDoCatchRedirections(http_utils.TestCaseWithRedirectedWebserver):
1451
    """Test transport.do_catching_redirections."""
1452
5462.3.15 by Martin Pool
Turn variations into scenario lists
1453
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1454
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
1455
        vary_by_http_protocol_version(),
1456
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1457
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1458
    def setUp(self):
1459
        super(TestDoCatchRedirections, self).setUp()
1460
        self.build_tree_contents([('a', '0123456789'),],)
5247.2.26 by Vincent Ladeuil
Fix http redirection socket leaks.
1461
        cleanup_http_redirection_connections(self)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1462
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1463
        self.old_transport = self.get_old_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1464
5247.3.31 by Vincent Ladeuil
Cleanup some imports in http_utils.py.
1465
    def get_a(self, t):
1466
        return t.get('a')
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1467
1468
    def test_no_redirection(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1469
        t = self.get_new_transport()
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1470
1471
        # We use None for redirected so that we fail if redirected
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1472
        self.assertEqual('0123456789',
1473
                         transport.do_catching_redirections(
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1474
                self.get_a, t, None).read())
1475
1476
    def test_one_redirection(self):
1477
        self.redirections = 0
1478
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1479
        def redirected(t, exception, redirection_notice):
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1480
            self.redirections += 1
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1481
            redirected_t = t._redirected_to(exception.source, exception.target)
1482
            return redirected_t
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1483
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1484
        self.assertEqual('0123456789',
1485
                         transport.do_catching_redirections(
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1486
                self.get_a, self.old_transport, redirected).read())
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1487
        self.assertEqual(1, self.redirections)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1488
1489
    def test_redirection_loop(self):
1490
1491
        def redirected(transport, exception, redirection_notice):
1492
            # By using the redirected url as a base dir for the
1493
            # *old* transport, we create a loop: a => a/a =>
1494
            # a/a/a
1495
            return self.old_transport.clone(exception.target)
1496
1497
        self.assertRaises(errors.TooManyRedirections,
1498
                          transport.do_catching_redirections,
1499
                          self.get_a, self.old_transport, redirected)
1500
1501
5957.2.1 by Vincent Ladeuil
Tweak the http Authorization tests to make some parts easier to reuse (parametrization mostly).
1502
def _setup_authentication_config(**kwargs):
1503
    conf = config.AuthenticationConfig()
1504
    conf._get_config().update({'httptest': kwargs})
1505
    conf._save()
1506
1507
1508
class TestUrllib2AuthHandler(tests.TestCaseWithTransport):
1509
    """Unit tests for glue by which urllib2 asks us for authentication"""
1510
1511
    def test_get_user_password_without_port(self):
1512
        """We cope if urllib2 doesn't tell us the port.
1513
1514
        See https://bugs.launchpad.net/bzr/+bug/654684
1515
        """
1516
        user = 'joe'
1517
        password = 'foo'
1518
        _setup_authentication_config(scheme='http', host='localhost',
1519
                                     user=user, password=password)
1520
        handler = _urllib2_wrappers.HTTPAuthHandler()
1521
        got_pass = handler.get_user_password(dict(
1522
            user='joe',
1523
            protocol='http',
1524
            host='localhost',
1525
            path='/',
1526
            realm='Realm',
1527
            ))
1528
        self.assertEquals((user, password), got_pass)
1529
1530
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1531
class TestAuth(http_utils.TestCaseWithWebserver):
1532
    """Test authentication scheme"""
1533
5462.3.15 by Martin Pool
Turn variations into scenario lists
1534
    scenarios = multiply_scenarios(
1535
        vary_by_http_client_implementation(),
1536
        vary_by_http_protocol_version(),
1537
        vary_by_http_auth_scheme(),
1538
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1539
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1540
    def setUp(self):
1541
        super(TestAuth, self).setUp()
1542
        self.server = self.get_readonly_server()
1543
        self.build_tree_contents([('a', 'contents of a\n'),
1544
                                  ('b', 'contents of b\n'),])
1545
1546
    def create_transport_readonly_server(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1547
        server = self._auth_server(protocol_version=self._protocol_version)
1548
        server._url_protocol = self._url_protocol
1549
        return server
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1550
1551
    def _testing_pycurl(self):
4913.2.11 by John Arbash Meinel
Convert a bunch more features over to ModuleAvailableFeature
1552
        # TODO: This is duplicated for lots of the classes in this file
1553
        return (features.pycurl.available()
1554
                and self._transport == PyCurlTransport)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1555
3910.2.4 by Vincent Ladeuil
Fixed as per John's review.
1556
    def get_user_url(self, user, password):
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1557
        """Build an url embedding user and password"""
1558
        url = '%s://' % self.server._url_protocol
1559
        if user is not None:
1560
            url += user
1561
            if password is not None:
1562
                url += ':' + password
1563
            url += '@'
1564
        url += '%s:%s/' % (self.server.host, self.server.port)
1565
        return url
1566
3910.2.4 by Vincent Ladeuil
Fixed as per John's review.
1567
    def get_user_transport(self, user, password):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1568
        t = transport.get_transport(self.get_user_url(user, password))
1569
        return t
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1570
1571
    def test_no_user(self):
1572
        self.server.add_user('joe', 'foo')
3910.2.4 by Vincent Ladeuil
Fixed as per John's review.
1573
        t = self.get_user_transport(None, None)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1574
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
1575
        # Only one 'Authentication Required' error should occur
1576
        self.assertEqual(1, self.server.auth_required_errors)
1577
1578
    def test_empty_pass(self):
1579
        self.server.add_user('joe', '')
1580
        t = self.get_user_transport('joe', '')
1581
        self.assertEqual('contents of a\n', t.get('a').read())
1582
        # Only one 'Authentication Required' error should occur
1583
        self.assertEqual(1, self.server.auth_required_errors)
1584
1585
    def test_user_pass(self):
1586
        self.server.add_user('joe', 'foo')
1587
        t = self.get_user_transport('joe', 'foo')
1588
        self.assertEqual('contents of a\n', t.get('a').read())
1589
        # Only one 'Authentication Required' error should occur
1590
        self.assertEqual(1, self.server.auth_required_errors)
1591
1592
    def test_unknown_user(self):
1593
        self.server.add_user('joe', 'foo')
1594
        t = self.get_user_transport('bill', 'foo')
1595
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
1596
        # Two 'Authentication Required' errors should occur (the
1597
        # initial 'who are you' and 'I don't know you, who are
1598
        # you').
1599
        self.assertEqual(2, self.server.auth_required_errors)
1600
1601
    def test_wrong_pass(self):
1602
        self.server.add_user('joe', 'foo')
1603
        t = self.get_user_transport('joe', 'bar')
1604
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'a')
1605
        # Two 'Authentication Required' errors should occur (the
1606
        # initial 'who are you' and 'this is not you, who are you')
1607
        self.assertEqual(2, self.server.auth_required_errors)
1608
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1609
    def test_prompt_for_username(self):
1610
        if self._testing_pycurl():
1611
            raise tests.TestNotApplicable(
1612
                'pycurl cannot prompt, it handles auth by embedding'
1613
                ' user:pass in urls only')
1614
1615
        self.server.add_user('joe', 'foo')
1616
        t = self.get_user_transport(None, None)
1617
        stdout = tests.StringIOWrapper()
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
1618
        stderr = tests.StringIOWrapper()
1619
        ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n',
1620
                                            stdout=stdout, stderr=stderr)
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1621
        self.assertEqual('contents of a\n',t.get('a').read())
1622
        # stdin should be empty
1623
        self.assertEqual('', ui.ui_factory.stdin.readline())
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
1624
        stderr.seek(0)
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1625
        expected_prompt = self._expected_username_prompt(t._unqualified_scheme)
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1626
        self.assertEqual(expected_prompt, stderr.read(len(expected_prompt)))
1627
        self.assertEqual('', stdout.getvalue())
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1628
        self._check_password_prompt(t._unqualified_scheme, 'joe',
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
1629
                                    stderr.readline())
4284.1.2 by Vincent Ladeuil
Delete spurious space.
1630
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1631
    def test_prompt_for_password(self):
1632
        if self._testing_pycurl():
1633
            raise tests.TestNotApplicable(
1634
                'pycurl cannot prompt, it handles auth by embedding'
1635
                ' user:pass in urls only')
1636
1637
        self.server.add_user('joe', 'foo')
1638
        t = self.get_user_transport('joe', None)
1639
        stdout = tests.StringIOWrapper()
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
1640
        stderr = tests.StringIOWrapper()
1641
        ui.ui_factory = tests.TestUIFactory(stdin='foo\n',
1642
                                            stdout=stdout, stderr=stderr)
1643
        self.assertEqual('contents of a\n', t.get('a').read())
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1644
        # stdin should be empty
1645
        self.assertEqual('', ui.ui_factory.stdin.readline())
1646
        self._check_password_prompt(t._unqualified_scheme, 'joe',
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
1647
                                    stderr.getvalue())
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1648
        self.assertEqual('', stdout.getvalue())
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1649
        # And we shouldn't prompt again for a different request
1650
        # against the same transport.
1651
        self.assertEqual('contents of b\n',t.get('b').read())
1652
        t2 = t.clone()
1653
        # And neither against a clone
1654
        self.assertEqual('contents of b\n',t2.get('b').read())
1655
        # Only one 'Authentication Required' error should occur
1656
        self.assertEqual(1, self.server.auth_required_errors)
1657
1658
    def _check_password_prompt(self, scheme, user, actual_prompt):
1659
        expected_prompt = (self._password_prompt_prefix
1660
                           + ("%s %s@%s:%d, Realm: '%s' password: "
1661
                              % (scheme.upper(),
1662
                                 user, self.server.host, self.server.port,
1663
                                 self.server.auth_realm)))
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1664
        self.assertEqual(expected_prompt, actual_prompt)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1665
4222.3.12 by Jelmer Vernooij
Check that the HTTP transport prompts for usernames.
1666
    def _expected_username_prompt(self, scheme):
1667
        return (self._username_prompt_prefix
1668
                + "%s %s:%d, Realm: '%s' username: " % (scheme.upper(),
1669
                                 self.server.host, self.server.port,
1670
                                 self.server.auth_realm))
1671
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1672
    def test_no_prompt_for_password_when_using_auth_config(self):
1673
        if self._testing_pycurl():
1674
            raise tests.TestNotApplicable(
1675
                'pycurl does not support authentication.conf'
1676
                ' since it cannot prompt')
1677
1678
        user =' joe'
1679
        password = 'foo'
1680
        stdin_content = 'bar\n'  # Not the right password
1681
        self.server.add_user(user, password)
1682
        t = self.get_user_transport(user, None)
1683
        ui.ui_factory = tests.TestUIFactory(stdin=stdin_content,
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
1684
                                            stderr=tests.StringIOWrapper())
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1685
        # Create a minimal config file with the right password
5957.2.1 by Vincent Ladeuil
Tweak the http Authorization tests to make some parts easier to reuse (parametrization mostly).
1686
        _setup_authentication_config(scheme='http', port=self.server.port,
1687
                                     user=user, password=password)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1688
        # Issue a request to the server to connect
1689
        self.assertEqual('contents of a\n',t.get('a').read())
1690
        # stdin should have  been left untouched
1691
        self.assertEqual(stdin_content, ui.ui_factory.stdin.readline())
1692
        # Only one 'Authentication Required' error should occur
1693
        self.assertEqual(1, self.server.auth_required_errors)
1694
3111.1.26 by Vincent Ladeuil
Re-add a test lost in refactoring.
1695
    def test_changing_nonce(self):
4307.4.2 by Vincent Ladeuil
Handle servers proposing several authentication schemes.
1696
        if self._auth_server not in (http_utils.HTTPDigestAuthServer,
1697
                                     http_utils.ProxyDigestAuthServer):
1698
            raise tests.TestNotApplicable('HTTP/proxy auth digest only test')
3111.1.26 by Vincent Ladeuil
Re-add a test lost in refactoring.
1699
        if self._testing_pycurl():
1700
            raise tests.KnownFailure(
1701
                'pycurl does not handle a nonce change')
1702
        self.server.add_user('joe', 'foo')
1703
        t = self.get_user_transport('joe', 'foo')
1704
        self.assertEqual('contents of a\n', t.get('a').read())
1705
        self.assertEqual('contents of b\n', t.get('b').read())
1706
        # Only one 'Authentication Required' error should have
1707
        # occured so far
1708
        self.assertEqual(1, self.server.auth_required_errors)
1709
        # The server invalidates the current nonce
1710
        self.server.auth_nonce = self.server.auth_nonce + '. No, now!'
1711
        self.assertEqual('contents of a\n', t.get('a').read())
1712
        # Two 'Authentication Required' errors should occur (the
1713
        # initial 'who are you' and a second 'who are you' with the new nonce)
1714
        self.assertEqual(2, self.server.auth_required_errors)
1715
5484.2.1 by Martin Pool
Add failing test for AbstractAuthHandler and bug 654684
1716
    def test_user_from_auth_conf(self):
1717
        if self._testing_pycurl():
1718
            raise tests.TestNotApplicable(
1719
                'pycurl does not support authentication.conf')
1720
        user = 'joe'
1721
        password = 'foo'
1722
        self.server.add_user(user, password)
5957.2.1 by Vincent Ladeuil
Tweak the http Authorization tests to make some parts easier to reuse (parametrization mostly).
1723
        _setup_authentication_config(scheme='http', port=self.server.port,
1724
                                     user=user, password=password)
5484.2.1 by Martin Pool
Add failing test for AbstractAuthHandler and bug 654684
1725
        t = self.get_user_transport(None, None)
1726
        # Issue a request to the server to connect
1727
        self.assertEqual('contents of a\n', t.get('a').read())
1728
        # Only one 'Authentication Required' error should occur
1729
        self.assertEqual(1, self.server.auth_required_errors)
1730
1731
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1732
class TestProxyAuth(TestAuth):
5957.2.1 by Vincent Ladeuil
Tweak the http Authorization tests to make some parts easier to reuse (parametrization mostly).
1733
    """Test proxy authentication schemes.
1734
1735
    This inherits from TestAuth to tweak the setUp and filter some failing
1736
    tests.
1737
    """
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1738
5462.3.15 by Martin Pool
Turn variations into scenario lists
1739
    scenarios = multiply_scenarios(
1740
        vary_by_http_client_implementation(),
1741
        vary_by_http_protocol_version(),
1742
        vary_by_http_proxy_auth_scheme(),
1743
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1744
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1745
    def setUp(self):
1746
        super(TestProxyAuth, self).setUp()
1747
        # Override the contents to avoid false positives
1748
        self.build_tree_contents([('a', 'not proxied contents of a\n'),
1749
                                  ('b', 'not proxied contents of b\n'),
1750
                                  ('a-proxied', 'contents of a\n'),
1751
                                  ('b-proxied', 'contents of b\n'),
1752
                                  ])
1753
3910.2.4 by Vincent Ladeuil
Fixed as per John's review.
1754
    def get_user_transport(self, user, password):
5570.3.10 by Vincent Ladeuil
Rework the http tests with overrideEnv.
1755
        self.overrideEnv('all_proxy', self.get_user_url(user, password))
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1756
        return TestAuth.get_user_transport(self, user, password)
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
1757
1758
    def test_empty_pass(self):
1759
        if self._testing_pycurl():
1760
            import pycurl
1761
            if pycurl.version_info()[1] < '7.16.0':
1762
                raise tests.KnownFailure(
1763
                    'pycurl < 7.16.0 does not handle empty proxy passwords')
1764
        super(TestProxyAuth, self).test_empty_pass()
1765
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1766
1767
class SampleSocket(object):
1768
    """A socket-like object for use in testing the HTTP request handler."""
1769
1770
    def __init__(self, socket_read_content):
1771
        """Constructs a sample socket.
1772
1773
        :param socket_read_content: a byte sequence
1774
        """
1775
        # Use plain python StringIO so we can monkey-patch the close method to
1776
        # not discard the contents.
1777
        from StringIO import StringIO
1778
        self.readfile = StringIO(socket_read_content)
1779
        self.writefile = StringIO()
1780
        self.writefile.close = lambda: None
5247.3.18 by Vincent Ladeuil
Fix some fallouts from previous fixes, all tests passing (no more http leaks).
1781
        self.close = lambda: None
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1782
1783
    def makefile(self, mode='r', bufsize=None):
1784
        if 'r' in mode:
1785
            return self.readfile
1786
        else:
1787
            return self.writefile
1788
1789
1790
class SmartHTTPTunnellingTest(tests.TestCaseWithTransport):
1791
5462.3.15 by Martin Pool
Turn variations into scenario lists
1792
    scenarios = multiply_scenarios(
5705.1.1 by Vincent Ladeuil
Correctly parse partial range specifiers in the HTTP test server
1793
        vary_by_http_client_implementation(),
5462.3.15 by Martin Pool
Turn variations into scenario lists
1794
        vary_by_http_protocol_version(),
1795
        )
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1796
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1797
    def setUp(self):
1798
        super(SmartHTTPTunnellingTest, self).setUp()
1799
        # We use the VFS layer as part of HTTP tunnelling tests.
5570.3.6 by Vincent Ladeuil
Get rid of all _captureVar() calls, no test failures, pfew.
1800
        self.overrideEnv('BZR_NO_SMART_VFS', None)
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1801
        self.transport_readonly_server = http_utils.HTTPServerWithSmarts
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1802
        self.http_server = self.get_readonly_server()
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1803
1804
    def create_transport_readonly_server(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1805
        server = http_utils.HTTPServerWithSmarts(
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1806
            protocol_version=self._protocol_version)
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1807
        server._url_protocol = self._url_protocol
1808
        return server
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1809
3606.4.1 by Andrew Bennetts
Fix NotImplementedError when probing for smart protocol via HTTP.
1810
    def test_open_bzrdir(self):
1811
        branch = self.make_branch('relpath')
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1812
        url = self.http_server.get_url() + 'relpath'
3606.4.1 by Andrew Bennetts
Fix NotImplementedError when probing for smart protocol via HTTP.
1813
        bd = bzrdir.BzrDir.open(url)
5247.2.28 by Vincent Ladeuil
Some more cleanups spotted on windows.
1814
        self.addCleanup(bd.transport.disconnect)
3606.4.1 by Andrew Bennetts
Fix NotImplementedError when probing for smart protocol via HTTP.
1815
        self.assertIsInstance(bd, _mod_remote.RemoteBzrDir)
1816
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1817
    def test_bulk_data(self):
1818
        # We should be able to send and receive bulk data in a single message.
1819
        # The 'readv' command in the smart protocol both sends and receives
1820
        # bulk data, so we use that.
1821
        self.build_tree(['data-file'])
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1822
        http_transport = transport.get_transport(self.http_server.get_url())
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1823
        medium = http_transport.get_smart_medium()
1824
        # Since we provide the medium, the url below will be mostly ignored
1825
        # during the test, as long as the path is '/'.
1826
        remote_transport = remote.RemoteTransport('bzr://fake_host/',
1827
                                                  medium=medium)
1828
        self.assertEqual(
1829
            [(0, "c")], list(remote_transport.readv("data-file", [(0,1)])))
1830
1831
    def test_http_send_smart_request(self):
1832
1833
        post_body = 'hello\n'
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1834
        expected_reply_body = 'ok\x012\n'
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1835
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1836
        http_transport = transport.get_transport(self.http_server.get_url())
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1837
        medium = http_transport.get_smart_medium()
1838
        response = medium.send_http_smart_request(post_body)
1839
        reply_body = response.read()
1840
        self.assertEqual(expected_reply_body, reply_body)
1841
1842
    def test_smart_http_server_post_request_handler(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1843
        httpd = self.http_server.server
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1844
1845
        socket = SampleSocket(
1846
            'POST /.bzr/smart %s \r\n' % self._protocol_version
1847
            # HTTP/1.1 posts must have a Content-Length (but it doesn't hurt
1848
            # for 1.0)
1849
            + 'Content-Length: 6\r\n'
1850
            '\r\n'
1851
            'hello\n')
1852
        # Beware: the ('localhost', 80) below is the
1853
        # client_address parameter, but we don't have one because
1854
        # we have defined a socket which is not bound to an
1855
        # address. The test framework never uses this client
1856
        # address, so far...
1857
        request_handler = http_utils.SmartRequestHandler(socket,
1858
                                                         ('localhost', 80),
1859
                                                         httpd)
1860
        response = socket.writefile.getvalue()
1861
        self.assertStartsWith(response, '%s 200 ' % self._protocol_version)
1862
        # This includes the end of the HTTP headers, and all the body.
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
1863
        expected_end_of_response = '\r\n\r\nok\x012\n'
3111.1.25 by Vincent Ladeuil
Fix the smart server failing test and use it against protocol combinations.
1864
        self.assertEndsWith(response, expected_end_of_response)
1865
1866
3430.3.4 by Vincent Ladeuil
Of course we can write tests !
1867
class ForbiddenRequestHandler(http_server.TestingHTTPRequestHandler):
1868
    """No smart server here request handler."""
1869
1870
    def do_POST(self):
1871
        self.send_error(403, "Forbidden")
1872
1873
1874
class SmartClientAgainstNotSmartServer(TestSpecificRequestHandler):
1875
    """Test smart client behaviour against an http server without smarts."""
1876
1877
    _req_handler_class = ForbiddenRequestHandler
1878
1879
    def test_probe_smart_server(self):
1880
        """Test error handling against server refusing smart requests."""
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
1881
        t = self.get_readonly_transport()
3430.3.4 by Vincent Ladeuil
Of course we can write tests !
1882
        # No need to build a valid smart request here, the server will not even
1883
        # try to interpret it.
1884
        self.assertRaises(errors.SmartProtocolError,
5599.3.6 by John Arbash Meinel
Revert the medium check, since it isn't necessary, and vila is worried about confusing people.
1885
                          t.get_smart_medium().send_http_smart_request,
1886
                          'whatever')
3430.3.4 by Vincent Ladeuil
Of course we can write tests !
1887
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
1888
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1889
class Test_redirected_to(tests.TestCase):
1890
5462.3.15 by Martin Pool
Turn variations into scenario lists
1891
    scenarios = vary_by_http_client_implementation()
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
1892
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1893
    def test_redirected_to_subdir(self):
1894
        t = self._transport('http://www.example.com/foo')
3878.4.5 by Vincent Ladeuil
Don't use the exception as a parameter for _redirected_to.
1895
        r = t._redirected_to('http://www.example.com/foo',
1896
                             'http://www.example.com/foo/subdir')
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1897
        self.assertIsInstance(r, type(t))
1898
        # Both transports share the some connection
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1899
        self.assertEqual(t._get_connection(), r._get_connection())
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1900
3878.4.3 by Vincent Ladeuil
Fix bug #303959 by returning a transport based on the same url
1901
    def test_redirected_to_self_with_slash(self):
1902
        t = self._transport('http://www.example.com/foo')
3878.4.5 by Vincent Ladeuil
Don't use the exception as a parameter for _redirected_to.
1903
        r = t._redirected_to('http://www.example.com/foo',
1904
                             'http://www.example.com/foo/')
3878.4.3 by Vincent Ladeuil
Fix bug #303959 by returning a transport based on the same url
1905
        self.assertIsInstance(r, type(t))
1906
        # Both transports share the some connection (one can argue that we
1907
        # should return the exact same transport here, but that seems
1908
        # overkill).
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1909
        self.assertEqual(t._get_connection(), r._get_connection())
3878.4.3 by Vincent Ladeuil
Fix bug #303959 by returning a transport based on the same url
1910
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1911
    def test_redirected_to_host(self):
1912
        t = self._transport('http://www.example.com/foo')
3878.4.5 by Vincent Ladeuil
Don't use the exception as a parameter for _redirected_to.
1913
        r = t._redirected_to('http://www.example.com/foo',
1914
                             'http://foo.example.com/foo/subdir')
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1915
        self.assertIsInstance(r, type(t))
1916
1917
    def test_redirected_to_same_host_sibling_protocol(self):
1918
        t = self._transport('http://www.example.com/foo')
3878.4.5 by Vincent Ladeuil
Don't use the exception as a parameter for _redirected_to.
1919
        r = t._redirected_to('http://www.example.com/foo',
1920
                             'https://www.example.com/foo')
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1921
        self.assertIsInstance(r, type(t))
1922
1923
    def test_redirected_to_same_host_different_protocol(self):
1924
        t = self._transport('http://www.example.com/foo')
3878.4.5 by Vincent Ladeuil
Don't use the exception as a parameter for _redirected_to.
1925
        r = t._redirected_to('http://www.example.com/foo',
1926
                             'ftp://www.example.com/foo')
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1927
        self.assertNotEquals(type(r), type(t))
1928
1929
    def test_redirected_to_different_host_same_user(self):
1930
        t = self._transport('http://joe@www.example.com/foo')
3878.4.5 by Vincent Ladeuil
Don't use the exception as a parameter for _redirected_to.
1931
        r = t._redirected_to('http://www.example.com/foo',
1932
                             'https://foo.example.com/foo')
3878.4.2 by Vincent Ladeuil
Fix bug #265070 by providing a finer sieve for accepted redirections.
1933
        self.assertIsInstance(r, type(t))
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
1934
        self.assertEqual(t._user, r._user)
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
1935
1936
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
1937
class PredefinedRequestHandler(http_server.TestingHTTPRequestHandler):
1938
    """Request handler for a unique and pre-defined request.
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
1939
1940
    The only thing we care about here is how many bytes travel on the wire. But
1941
    since we want to measure it for a real http client, we have to send it
1942
    correct responses.
1943
1944
    We expect to receive a *single* request nothing more (and we won't even
1945
    check what request it is, we just measure the bytes read until an empty
1946
    line.
1947
    """
1948
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
1949
    def _handle_one_request(self):
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
1950
        tcs = self.server.test_case_server
1951
        requestline = self.rfile.readline()
1952
        headers = self.MessageClass(self.rfile, 0)
1953
        # We just read: the request, the headers, an empty line indicating the
1954
        # end of the headers.
1955
        bytes_read = len(requestline)
1956
        for line in headers.headers:
1957
            bytes_read += len(line)
1958
        bytes_read += len('\r\n')
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
1959
        if requestline.startswith('POST'):
1960
            # The body should be a single line (or we don't know where it ends
1961
            # and we don't want to issue a blocking read)
1962
            body = self.rfile.readline()
1963
            bytes_read += len(body)
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
1964
        tcs.bytes_read = bytes_read
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
1965
1966
        # We set the bytes written *before* issuing the write, the client is
1967
        # supposed to consume every produced byte *before* checking that value.
3945.1.7 by Vincent Ladeuil
Test against https.
1968
1969
        # Doing the oppposite may lead to test failure: we may be interrupted
1970
        # after the write but before updating the value. The client can then
1971
        # continue and read the value *before* we can update it. And yes,
1972
        # this has been observed -- vila 20090129
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
1973
        tcs.bytes_written = len(tcs.canned_response)
1974
        self.wfile.write(tcs.canned_response)
1975
1976
1977
class ActivityServerMixin(object):
1978
1979
    def __init__(self, protocol_version):
1980
        super(ActivityServerMixin, self).__init__(
1981
            request_handler=PredefinedRequestHandler,
1982
            protocol_version=protocol_version)
1983
        # Bytes read and written by the server
1984
        self.bytes_read = 0
1985
        self.bytes_written = 0
1986
        self.canned_response = None
1987
1988
1989
class ActivityHTTPServer(ActivityServerMixin, http_server.HttpServer):
1990
    pass
1991
1992
1993
if tests.HTTPSServerFeature.available():
1994
    from bzrlib.tests import https_server
1995
    class ActivityHTTPSServer(ActivityServerMixin, https_server.HTTPSServer):
1996
        pass
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
1997
1998
4776.2.1 by Vincent Ladeuil
Support no activity report on http sockets.
1999
class TestActivityMixin(object):
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
2000
    """Test socket activity reporting.
2001
2002
    We use a special purpose server to control the bytes sent and received and
2003
    be able to predict the activity on the client socket.
2004
    """
2005
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
2006
    def setUp(self):
2007
        tests.TestCase.setUp(self)
2008
        self.server = self._activity_server(self._protocol_version)
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
2009
        self.server.start_server()
5901.1.1 by John Arbash Meinel
Re-apply the bits of TestCase that I wanted, on the new bzr.dev tip.
2010
        _activities = {} # Don't close over self and create a cycle
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
2011
        def report_activity(t, bytes, direction):
5901.1.1 by John Arbash Meinel
Re-apply the bits of TestCase that I wanted, on the new bzr.dev tip.
2012
            count = _activities.get(direction, 0)
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
2013
            count += bytes
5901.1.1 by John Arbash Meinel
Re-apply the bits of TestCase that I wanted, on the new bzr.dev tip.
2014
            _activities[direction] = count
2015
        self.activities = _activities
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
2016
2017
        # We override at class level because constructors may propagate the
2018
        # bound method and render instance overriding ineffective (an
4031.3.1 by Frank Aspell
Fixing various typos
2019
        # alternative would be to define a specific ui factory instead...)
4986.2.6 by Martin Pool
Clean up test_http setUp methods
2020
        self.overrideAttr(self._transport, '_report_activity', report_activity)
2021
        self.addCleanup(self.server.stop_server)
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
2022
2023
    def get_transport(self):
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
2024
        t = self._transport(self.server.get_url())
2025
        # FIXME: Needs cleanup -- vila 20100611
2026
        return t
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
2027
2028
    def assertActivitiesMatch(self):
2029
        self.assertEqual(self.server.bytes_read,
2030
                         self.activities.get('write', 0), 'written bytes')
2031
        self.assertEqual(self.server.bytes_written,
2032
                         self.activities.get('read', 0), 'read bytes')
2033
2034
    def test_get(self):
2035
        self.server.canned_response = '''HTTP/1.1 200 OK\r
2036
Date: Tue, 11 Jul 2006 04:32:56 GMT\r
2037
Server: Apache/2.0.54 (Fedora)\r
2038
Last-Modified: Sun, 23 Apr 2006 19:35:20 GMT\r
2039
ETag: "56691-23-38e9ae00"\r
2040
Accept-Ranges: bytes\r
2041
Content-Length: 35\r
2042
Connection: close\r
2043
Content-Type: text/plain; charset=UTF-8\r
2044
\r
2045
Bazaar-NG meta directory, format 1
2046
'''
2047
        t = self.get_transport()
3945.1.5 by Vincent Ladeuil
Start implementing http activity reporting at socket level.
2048
        self.assertEqual('Bazaar-NG meta directory, format 1\n',
2049
                         t.get('foo/bar').read())
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
2050
        self.assertActivitiesMatch()
2051
2052
    def test_has(self):
2053
        self.server.canned_response = '''HTTP/1.1 200 OK\r
2054
Server: SimpleHTTP/0.6 Python/2.5.2\r
2055
Date: Thu, 29 Jan 2009 20:21:47 GMT\r
2056
Content-type: application/octet-stream\r
2057
Content-Length: 20\r
2058
Last-Modified: Thu, 29 Jan 2009 20:21:47 GMT\r
2059
\r
2060
'''
2061
        t = self.get_transport()
2062
        self.assertTrue(t.has('foo/bar'))
2063
        self.assertActivitiesMatch()
2064
2065
    def test_readv(self):
2066
        self.server.canned_response = '''HTTP/1.1 206 Partial Content\r
2067
Date: Tue, 11 Jul 2006 04:49:48 GMT\r
2068
Server: Apache/2.0.54 (Fedora)\r
2069
Last-Modified: Thu, 06 Jul 2006 20:22:05 GMT\r
2070
ETag: "238a3c-16ec2-805c5540"\r
2071
Accept-Ranges: bytes\r
2072
Content-Length: 1534\r
2073
Connection: close\r
2074
Content-Type: multipart/byteranges; boundary=418470f848b63279b\r
2075
\r
2076
\r
2077
--418470f848b63279b\r
2078
Content-type: text/plain; charset=UTF-8\r
2079
Content-range: bytes 0-254/93890\r
2080
\r
2081
mbp@sourcefrog.net-20050309040815-13242001617e4a06
2082
mbp@sourcefrog.net-20050309040929-eee0eb3e6d1e7627
2083
mbp@sourcefrog.net-20050309040957-6cad07f466bb0bb8
2084
mbp@sourcefrog.net-20050309041501-c840e09071de3b67
2085
mbp@sourcefrog.net-20050309044615-c24a3250be83220a
2086
\r
2087
--418470f848b63279b\r
2088
Content-type: text/plain; charset=UTF-8\r
2089
Content-range: bytes 1000-2049/93890\r
2090
\r
2091
40-fd4ec249b6b139ab
2092
mbp@sourcefrog.net-20050311063625-07858525021f270b
2093
mbp@sourcefrog.net-20050311231934-aa3776aff5200bb9
2094
mbp@sourcefrog.net-20050311231953-73aeb3a131c3699a
2095
mbp@sourcefrog.net-20050311232353-f5e33da490872c6a
2096
mbp@sourcefrog.net-20050312071639-0a8f59a34a024ff0
2097
mbp@sourcefrog.net-20050312073432-b2c16a55e0d6e9fb
2098
mbp@sourcefrog.net-20050312073831-a47c3335ece1920f
2099
mbp@sourcefrog.net-20050312085412-13373aa129ccbad3
2100
mbp@sourcefrog.net-20050313052251-2bf004cb96b39933
2101
mbp@sourcefrog.net-20050313052856-3edd84094687cb11
2102
mbp@sourcefrog.net-20050313053233-e30a4f28aef48f9d
2103
mbp@sourcefrog.net-20050313053853-7c64085594ff3072
2104
mbp@sourcefrog.net-20050313054757-a86c3f5871069e22
2105
mbp@sourcefrog.net-20050313061422-418f1f73b94879b9
2106
mbp@sourcefrog.net-20050313120651-497bd231b19df600
2107
mbp@sourcefrog.net-20050314024931-eae0170ef25a5d1a
2108
mbp@sourcefrog.net-20050314025438-d52099f915fe65fc
2109
mbp@sourcefrog.net-20050314025539-637a636692c055cf
2110
mbp@sourcefrog.net-20050314025737-55eb441f430ab4ba
2111
mbp@sourcefrog.net-20050314025901-d74aa93bb7ee8f62
2112
mbp@source\r
2113
--418470f848b63279b--\r
2114
'''
2115
        t = self.get_transport()
2116
        # Remember that the request is ignored and that the ranges below
2117
        # doesn't have to match the canned response.
2118
        l = list(t.readv('/foo/bar', ((0, 255), (1000, 1050))))
2119
        self.assertEqual(2, len(l))
2120
        self.assertActivitiesMatch()
2121
2122
    def test_post(self):
2123
        self.server.canned_response = '''HTTP/1.1 200 OK\r
2124
Date: Tue, 11 Jul 2006 04:32:56 GMT\r
2125
Server: Apache/2.0.54 (Fedora)\r
2126
Last-Modified: Sun, 23 Apr 2006 19:35:20 GMT\r
2127
ETag: "56691-23-38e9ae00"\r
2128
Accept-Ranges: bytes\r
2129
Content-Length: 35\r
2130
Connection: close\r
2131
Content-Type: text/plain; charset=UTF-8\r
2132
\r
2133
lalala whatever as long as itsssss
2134
'''
2135
        t = self.get_transport()
2136
        # We must send a single line of body bytes, see
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
2137
        # PredefinedRequestHandler._handle_one_request
3945.1.8 by Vincent Ladeuil
Add more tests, fix pycurl double handling, revert previous tracking.
2138
        code, f = t._post('abc def end-of-body\n')
2139
        self.assertEqual('lalala whatever as long as itsssss\n', f.read())
2140
        self.assertActivitiesMatch()
4776.2.1 by Vincent Ladeuil
Support no activity report on http sockets.
2141
2142
2143
class TestActivity(tests.TestCase, TestActivityMixin):
2144
5462.3.15 by Martin Pool
Turn variations into scenario lists
2145
    scenarios = multiply_scenarios(
2146
        vary_by_http_activity(),
2147
        vary_by_http_protocol_version(),
2148
        )
5462.3.11 by Martin Pool
Delete test_http.load_tests, and just specify variations per test
2149
4776.2.1 by Vincent Ladeuil
Support no activity report on http sockets.
2150
    def setUp(self):
4986.2.6 by Martin Pool
Clean up test_http setUp methods
2151
        TestActivityMixin.setUp(self)
4776.2.1 by Vincent Ladeuil
Support no activity report on http sockets.
2152
2153
2154
class TestNoReportActivity(tests.TestCase, TestActivityMixin):
2155
4986.2.6 by Martin Pool
Clean up test_http setUp methods
2156
    # Unlike TestActivity, we are really testing ReportingFileSocket and
2157
    # ReportingSocket, so we don't need all the parametrization. Since
2158
    # ReportingFileSocket and ReportingSocket are wrappers, it's easier to
2159
    # test them through their use by the transport than directly (that's a
2160
    # bit less clean but far more simpler and effective).
2161
    _activity_server = ActivityHTTPServer
2162
    _protocol_version = 'HTTP/1.1'
2163
4776.2.1 by Vincent Ladeuil
Support no activity report on http sockets.
2164
    def setUp(self):
4986.2.6 by Martin Pool
Clean up test_http setUp methods
2165
        self._transport =_urllib.HttpTransport_urllib
2166
        TestActivityMixin.setUp(self)
4776.2.1 by Vincent Ladeuil
Support no activity report on http sockets.
2167
2168
    def assertActivitiesMatch(self):
2169
        # Nothing to check here
2170
        pass
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2171
2172
2173
class TestAuthOnRedirected(http_utils.TestCaseWithRedirectedWebserver):
2174
    """Test authentication on the redirected http server."""
2175
5462.3.15 by Martin Pool
Turn variations into scenario lists
2176
    scenarios = vary_by_http_protocol_version()
5462.3.9 by Martin Pool
List variations within the test classes, rather than in load_tests
2177
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2178
    _auth_header = 'Authorization'
2179
    _password_prompt_prefix = ''
2180
    _username_prompt_prefix = ''
2181
    _auth_server = http_utils.HTTPBasicAuthServer
2182
    _transport = _urllib.HttpTransport_urllib
2183
2184
    def setUp(self):
2185
        super(TestAuthOnRedirected, self).setUp()
2186
        self.build_tree_contents([('a','a'),
2187
                                  ('1/',),
2188
                                  ('1/a', 'redirected once'),
2189
                                  ],)
2190
        new_prefix = 'http://%s:%s' % (self.new_server.host,
2191
                                       self.new_server.port)
2192
        self.old_server.redirections = [
2193
            ('(.*)', r'%s/1\1' % (new_prefix), 301),]
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
2194
        self.old_transport = self.get_old_transport()
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2195
        self.new_server.add_user('joe', 'foo')
5247.2.26 by Vincent Ladeuil
Fix http redirection socket leaks.
2196
        cleanup_http_redirection_connections(self)
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2197
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
2198
    def create_transport_readonly_server(self):
2199
        server = self._auth_server(protocol_version=self._protocol_version)
2200
        server._url_protocol = self._url_protocol
2201
        return server
2202
2203
    def get_a(self, t):
2204
        return t.get('a')
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2205
2206
    def test_auth_on_redirected_via_do_catching_redirections(self):
2207
        self.redirections = 0
2208
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
2209
        def redirected(t, exception, redirection_notice):
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2210
            self.redirections += 1
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
2211
            redirected_t = t._redirected_to(exception.source, exception.target)
5247.2.28 by Vincent Ladeuil
Some more cleanups spotted on windows.
2212
            self.addCleanup(redirected_t.disconnect)
5247.3.29 by Vincent Ladeuil
Fix a bunch of tests that were building transport objects explicitely instead of relying on self.get_transport() leading to many wrong http implementation objects being tested.
2213
            return redirected_t
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2214
2215
        stdout = tests.StringIOWrapper()
2216
        stderr = tests.StringIOWrapper()
2217
        ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n',
2218
                                            stdout=stdout, stderr=stderr)
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
2219
        self.assertEqual('redirected once',
2220
                         transport.do_catching_redirections(
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2221
                self.get_a, self.old_transport, redirected).read())
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
2222
        self.assertEqual(1, self.redirections)
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2223
        # stdin should be empty
2224
        self.assertEqual('', ui.ui_factory.stdin.readline())
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
2225
        # stdout should be empty, stderr will contains the prompts
2226
        self.assertEqual('', stdout.getvalue())
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2227
2228
    def test_auth_on_redirected_via_following_redirections(self):
2229
        self.new_server.add_user('joe', 'foo')
2230
        stdout = tests.StringIOWrapper()
2231
        stderr = tests.StringIOWrapper()
2232
        ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n',
2233
                                            stdout=stdout, stderr=stderr)
2234
        t = self.old_transport
2235
        req = RedirectedRequest('GET', t.abspath('a'))
2236
        new_prefix = 'http://%s:%s' % (self.new_server.host,
2237
                                       self.new_server.port)
2238
        self.old_server.redirections = [
2239
            ('(.*)', r'%s/1\1' % (new_prefix), 301),]
5247.2.28 by Vincent Ladeuil
Some more cleanups spotted on windows.
2240
        self.assertEqual('redirected once', t._perform(req).read())
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2241
        # stdin should be empty
2242
        self.assertEqual('', ui.ui_factory.stdin.readline())
4795.4.6 by Vincent Ladeuil
Fixed as per John's review.
2243
        # stdout should be empty, stderr will contains the prompts
2244
        self.assertEqual('', stdout.getvalue())
4795.4.5 by Vincent Ladeuil
Make sure all redirection code paths can handle authentication.
2245
2246