/brz/remove-bazaar

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