~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: Vincent Ladeuil
  • Date: 2011-01-12 00:58:05 UTC
  • mfrom: (5582.7.1 675652-bzr-columns-0)
  • mto: This revision was merged to the branch mainline in revision 5598.
  • Revision ID: v.ladeuil+lp@free.fr-20110112005805-tzclc2wogqef8zty
Accept 0 to mean no limit for BZR_COLUMNS

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
32
32
import bzrlib
33
33
from bzrlib import (
34
34
    bzrdir,
35
 
    cethread,
36
35
    config,
37
 
    debug,
38
36
    errors,
39
37
    osutils,
40
38
    remote as _mod_remote,
41
39
    tests,
42
 
    trace,
43
40
    transport,
44
41
    ui,
45
42
    )
93
90
        ]
94
91
 
95
92
 
 
93
def vary_by_http_proxy_auth_scheme():
 
94
    return [
 
95
        ('basic', dict(_auth_server=http_utils.ProxyBasicAuthServer)),
 
96
        ('digest', dict(_auth_server=http_utils.ProxyDigestAuthServer)),
 
97
        ('basicdigest',
 
98
            dict(_auth_server=http_utils.ProxyBasicAndDigestAuthServer)),
 
99
        ]
 
100
 
 
101
 
96
102
def vary_by_http_auth_scheme():
97
 
    scenarios = [
 
103
    return [
98
104
        ('basic', dict(_auth_server=http_utils.HTTPBasicAuthServer)),
99
105
        ('digest', dict(_auth_server=http_utils.HTTPDigestAuthServer)),
100
106
        ('basicdigest',
101
107
            dict(_auth_server=http_utils.HTTPBasicAndDigestAuthServer)),
102
108
        ]
103
 
    # Add some attributes common to all scenarios
104
 
    for scenario_id, scenario_dict in scenarios:
105
 
        scenario_dict.update(_auth_header='Authorization',
106
 
                             _username_prompt_prefix='',
107
 
                             _password_prompt_prefix='')
108
 
    return scenarios
109
 
 
110
 
 
111
 
def vary_by_http_proxy_auth_scheme():
112
 
    scenarios = [
113
 
        ('proxy-basic', dict(_auth_server=http_utils.ProxyBasicAuthServer)),
114
 
        ('proxy-digest', dict(_auth_server=http_utils.ProxyDigestAuthServer)),
115
 
        ('proxy-basicdigest',
116
 
            dict(_auth_server=http_utils.ProxyBasicAndDigestAuthServer)),
117
 
        ]
118
 
    # Add some attributes common to all scenarios
119
 
    for scenario_id, scenario_dict in scenarios:
120
 
        scenario_dict.update(_auth_header='Proxy-Authorization',
121
 
                             _username_prompt_prefix='Proxy ',
122
 
                             _password_prompt_prefix='Proxy ')
123
 
    return scenarios
124
109
 
125
110
 
126
111
def vary_by_http_activity():
128
113
        ('urllib,http', dict(_activity_server=ActivityHTTPServer,
129
114
                            _transport=_urllib.HttpTransport_urllib,)),
130
115
        ]
131
 
    if features.HTTPSServerFeature.available():
 
116
    if tests.HTTPSServerFeature.available():
132
117
        activity_scenarios.append(
133
118
            ('urllib,https', dict(_activity_server=ActivityHTTPSServer,
134
119
                                _transport=_urllib.HttpTransport_urllib,)),)
136
121
        activity_scenarios.append(
137
122
            ('pycurl,http', dict(_activity_server=ActivityHTTPServer,
138
123
                                _transport=PyCurlTransport,)),)
139
 
        if features.HTTPSServerFeature.available():
 
124
        if tests.HTTPSServerFeature.available():
140
125
            from bzrlib.tests import (
141
126
                ssl_certs,
142
127
                )
193
178
        self._sock.bind(('127.0.0.1', 0))
194
179
        self.host, self.port = self._sock.getsockname()
195
180
        self._ready = threading.Event()
196
 
        self._thread = test_server.TestThread(
197
 
            sync_event=self._ready, target=self._accept_read_and_reply)
 
181
        self._thread = test_server.ThreadWithException(
 
182
            event=self._ready, target=self._accept_read_and_reply)
198
183
        self._thread.start()
199
184
        if 'threads' in tests.selftest_debug_flags:
200
185
            sys.stderr.write('Thread started: %s\n' % (self._thread.ident,))
269
254
        self.assertEqual('realm="Thou should not pass"', remainder)
270
255
 
271
256
 
272
 
class TestHTTPRangeParsing(tests.TestCase):
273
 
 
274
 
    def setUp(self):
275
 
        super(TestHTTPRangeParsing, self).setUp()
276
 
        # We focus on range  parsing here and ignore everything else
277
 
        class RequestHandler(http_server.TestingHTTPRequestHandler):
278
 
            def setup(self): pass
279
 
            def handle(self): pass
280
 
            def finish(self): pass
281
 
 
282
 
        self.req_handler = RequestHandler(None, None, None)
283
 
 
284
 
    def assertRanges(self, ranges, header, file_size):
285
 
        self.assertEquals(ranges,
286
 
                          self.req_handler._parse_ranges(header, file_size))
287
 
 
288
 
    def test_simple_range(self):
289
 
        self.assertRanges([(0,2)], 'bytes=0-2', 12)
290
 
 
291
 
    def test_tail(self):
292
 
        self.assertRanges([(8, 11)], 'bytes=-4', 12)
293
 
 
294
 
    def test_tail_bigger_than_file(self):
295
 
        self.assertRanges([(0, 11)], 'bytes=-99', 12)
296
 
 
297
 
    def test_range_without_end(self):
298
 
        self.assertRanges([(4, 11)], 'bytes=4-', 12)
299
 
 
300
 
    def test_invalid_ranges(self):
301
 
        self.assertRanges(None, 'bytes=12-22', 12)
302
 
        self.assertRanges(None, 'bytes=1-3,12-22', 12)
303
 
        self.assertRanges(None, 'bytes=-', 12)
304
 
 
305
 
 
306
257
class TestHTTPServer(tests.TestCase):
307
258
    """Test the HTTP servers implementations."""
308
259
 
476
427
    """Test the http connections."""
477
428
 
478
429
    scenarios = multiply_scenarios(
479
 
        vary_by_http_client_implementation(),
 
430
        vary_by_http_client_implementation(), 
480
431
        vary_by_http_protocol_version(),
481
432
        )
482
433
 
533
484
    scenarios = vary_by_http_client_implementation()
534
485
 
535
486
    def test_http_registered(self):
536
 
        t = transport.get_transport_from_url(
537
 
            '%s://foo.com/' % self._url_protocol)
 
487
        t = transport.get_transport('%s://foo.com/' % self._url_protocol)
538
488
        self.assertIsInstance(t, transport.Transport)
539
489
        self.assertIsInstance(t, self._transport)
540
490
 
542
492
class TestPost(tests.TestCase):
543
493
 
544
494
    scenarios = multiply_scenarios(
545
 
        vary_by_http_client_implementation(),
 
495
        vary_by_http_client_implementation(), 
546
496
        vary_by_http_protocol_version(),
547
497
        )
548
498
 
552
502
        self.start_server(server)
553
503
        url = server.get_url()
554
504
        # FIXME: needs a cleanup -- vila 20100611
555
 
        http_transport = transport.get_transport_from_url(url)
 
505
        http_transport = transport.get_transport(url)
556
506
        code, response = http_transport._post('abc def end-of-body')
557
507
        self.assertTrue(
558
508
            server.received_bytes.startswith('POST /.bzr/smart HTTP/1.'))
601
551
    """
602
552
 
603
553
    scenarios = multiply_scenarios(
604
 
        vary_by_http_client_implementation(),
 
554
        vary_by_http_client_implementation(), 
605
555
        vary_by_http_protocol_version(),
606
556
        )
607
557
 
1049
999
        self.assertEqual('single', t._range_hint)
1050
1000
 
1051
1001
 
1052
 
class TruncatedBeforeBoundaryRequestHandler(
1053
 
    http_server.TestingHTTPRequestHandler):
1054
 
    """Truncation before a boundary, like in bug 198646"""
1055
 
 
1056
 
    _truncated_ranges = 1
1057
 
 
1058
 
    def get_multiple_ranges(self, file, file_size, ranges):
1059
 
        self.send_response(206)
1060
 
        self.send_header('Accept-Ranges', 'bytes')
1061
 
        boundary = 'tagada'
1062
 
        self.send_header('Content-Type',
1063
 
                         'multipart/byteranges; boundary=%s' % boundary)
1064
 
        boundary_line = '--%s\r\n' % boundary
1065
 
        # Calculate the Content-Length
1066
 
        content_length = 0
1067
 
        for (start, end) in ranges:
1068
 
            content_length += len(boundary_line)
1069
 
            content_length += self._header_line_length(
1070
 
                'Content-type', 'application/octet-stream')
1071
 
            content_length += self._header_line_length(
1072
 
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
1073
 
            content_length += len('\r\n') # end headers
1074
 
            content_length += end - start # + 1
1075
 
        content_length += len(boundary_line)
1076
 
        self.send_header('Content-length', content_length)
1077
 
        self.end_headers()
1078
 
 
1079
 
        # Send the multipart body
1080
 
        cur = 0
1081
 
        for (start, end) in ranges:
1082
 
            if cur + self._truncated_ranges >= len(ranges):
1083
 
                # Abruptly ends the response and close the connection
1084
 
                self.close_connection = 1
1085
 
                return
1086
 
            self.wfile.write(boundary_line)
1087
 
            self.send_header('Content-type', 'application/octet-stream')
1088
 
            self.send_header('Content-Range', 'bytes %d-%d/%d'
1089
 
                             % (start, end, file_size))
1090
 
            self.end_headers()
1091
 
            self.send_range_content(file, start, end - start + 1)
1092
 
            cur += 1
1093
 
        # Final boundary
1094
 
        self.wfile.write(boundary_line)
1095
 
 
1096
 
 
1097
 
class TestTruncatedBeforeBoundary(TestSpecificRequestHandler):
1098
 
    """Tests the case of bug 198646, disconnecting before a boundary."""
1099
 
 
1100
 
    _req_handler_class = TruncatedBeforeBoundaryRequestHandler
1101
 
 
1102
 
    def setUp(self):
1103
 
        super(TestTruncatedBeforeBoundary, self).setUp()
1104
 
        self.build_tree_contents([('a', '0123456789')],)
1105
 
 
1106
 
    def test_readv_with_short_reads(self):
1107
 
        server = self.get_readonly_server()
1108
 
        t = self.get_readonly_transport()
1109
 
        # Force separate ranges for each offset
1110
 
        t._bytes_to_read_before_seek = 0
1111
 
        ireadv = iter(t.readv('a', ((0, 1), (2, 1), (4, 2), (9, 1))))
1112
 
        self.assertEqual((0, '0'), ireadv.next())
1113
 
        self.assertEqual((2, '2'), ireadv.next())
1114
 
        self.assertEqual((4, '45'), ireadv.next())
1115
 
        self.assertEqual((9, '9'), ireadv.next())
1116
 
 
1117
 
 
1118
1002
class LimitedRangeRequestHandler(http_server.TestingHTTPRequestHandler):
1119
1003
    """Errors out when range specifiers exceed the limit"""
1120
1004
 
1145
1029
    """Tests readv requests against a server erroring out on too much ranges."""
1146
1030
 
1147
1031
    scenarios = multiply_scenarios(
1148
 
        vary_by_http_client_implementation(),
 
1032
        vary_by_http_client_implementation(), 
1149
1033
        vary_by_http_protocol_version(),
1150
1034
        )
1151
1035
 
1191
1075
 
1192
1076
    def _proxied_request(self):
1193
1077
        handler = _urllib2_wrappers.ProxyHandler()
1194
 
        request = _urllib2_wrappers.Request('GET', 'http://baz/buzzle')
 
1078
        request = _urllib2_wrappers.Request('GET','http://baz/buzzle')
1195
1079
        handler.set_proxy(request, 'http')
1196
1080
        return request
1197
1081
 
1198
 
    def assertEvaluateProxyBypass(self, expected, host, no_proxy):
1199
 
        handler = _urllib2_wrappers.ProxyHandler()
1200
 
        self.assertEquals(expected,
1201
 
                          handler.evaluate_proxy_bypass(host, no_proxy))
1202
 
 
1203
1082
    def test_empty_user(self):
1204
1083
        self.overrideEnv('http_proxy', 'http://bar.com')
1205
1084
        request = self._proxied_request()
1206
1085
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1207
1086
 
1208
 
    def test_user_with_at(self):
1209
 
        self.overrideEnv('http_proxy',
1210
 
                         'http://username@domain:password@proxy_host:1234')
1211
 
        request = self._proxied_request()
1212
 
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1213
 
 
1214
1087
    def test_invalid_proxy(self):
1215
1088
        """A proxy env variable without scheme"""
1216
1089
        self.overrideEnv('http_proxy', 'host:1234')
1217
1090
        self.assertRaises(errors.InvalidURL, self._proxied_request)
1218
1091
 
1219
 
    def test_evaluate_proxy_bypass_true(self):
1220
 
        """The host is not proxied"""
1221
 
        self.assertEvaluateProxyBypass(True, 'example.com', 'example.com')
1222
 
        self.assertEvaluateProxyBypass(True, 'bzr.example.com', '*example.com')
1223
 
 
1224
 
    def test_evaluate_proxy_bypass_false(self):
1225
 
        """The host is proxied"""
1226
 
        self.assertEvaluateProxyBypass(False, 'bzr.example.com', None)
1227
 
 
1228
 
    def test_evaluate_proxy_bypass_unknown(self):
1229
 
        """The host is not explicitly proxied"""
1230
 
        self.assertEvaluateProxyBypass(None, 'example.com', 'not.example.com')
1231
 
        self.assertEvaluateProxyBypass(None, 'bzr.example.com', 'example.com')
1232
 
 
1233
 
    def test_evaluate_proxy_bypass_empty_entries(self):
1234
 
        """Ignore empty entries"""
1235
 
        self.assertEvaluateProxyBypass(None, 'example.com', '')
1236
 
        self.assertEvaluateProxyBypass(None, 'example.com', ',')
1237
 
        self.assertEvaluateProxyBypass(None, 'example.com', 'foo,,bar')
1238
 
 
1239
1092
 
1240
1093
class TestProxyHttpServer(http_utils.TestCaseWithTwoWebservers):
1241
1094
    """Tests proxy server.
1247
1100
    """
1248
1101
 
1249
1102
    scenarios = multiply_scenarios(
1250
 
        vary_by_http_client_implementation(),
 
1103
        vary_by_http_client_implementation(), 
1251
1104
        vary_by_http_protocol_version(),
1252
1105
        )
1253
1106
 
1344
1197
    """Test the Range header in GET methods."""
1345
1198
 
1346
1199
    scenarios = multiply_scenarios(
1347
 
        vary_by_http_client_implementation(),
 
1200
        vary_by_http_client_implementation(), 
1348
1201
        vary_by_http_protocol_version(),
1349
1202
        )
1350
1203
 
1394
1247
    """Test redirection between http servers."""
1395
1248
 
1396
1249
    scenarios = multiply_scenarios(
1397
 
        vary_by_http_client_implementation(),
 
1250
        vary_by_http_client_implementation(), 
1398
1251
        vary_by_http_protocol_version(),
1399
1252
        )
1400
1253
 
1467
1320
    """
1468
1321
 
1469
1322
    scenarios = multiply_scenarios(
1470
 
        vary_by_http_client_implementation(),
 
1323
        vary_by_http_client_implementation(), 
1471
1324
        vary_by_http_protocol_version(),
1472
1325
        )
1473
1326
 
1522
1375
    """Test transport.do_catching_redirections."""
1523
1376
 
1524
1377
    scenarios = multiply_scenarios(
1525
 
        vary_by_http_client_implementation(),
 
1378
        vary_by_http_client_implementation(), 
1526
1379
        vary_by_http_protocol_version(),
1527
1380
        )
1528
1381
 
1570
1423
                          self.get_a, self.old_transport, redirected)
1571
1424
 
1572
1425
 
1573
 
def _setup_authentication_config(**kwargs):
1574
 
    conf = config.AuthenticationConfig()
1575
 
    conf._get_config().update({'httptest': kwargs})
1576
 
    conf._save()
1577
 
 
1578
 
 
1579
 
class TestUrllib2AuthHandler(tests.TestCaseWithTransport):
1580
 
    """Unit tests for glue by which urllib2 asks us for authentication"""
1581
 
 
1582
 
    def test_get_user_password_without_port(self):
1583
 
        """We cope if urllib2 doesn't tell us the port.
1584
 
 
1585
 
        See https://bugs.launchpad.net/bzr/+bug/654684
1586
 
        """
1587
 
        user = 'joe'
1588
 
        password = 'foo'
1589
 
        _setup_authentication_config(scheme='http', host='localhost',
1590
 
                                     user=user, password=password)
1591
 
        handler = _urllib2_wrappers.HTTPAuthHandler()
1592
 
        got_pass = handler.get_user_password(dict(
1593
 
            user='joe',
1594
 
            protocol='http',
1595
 
            host='localhost',
1596
 
            path='/',
1597
 
            realm='Realm',
1598
 
            ))
1599
 
        self.assertEquals((user, password), got_pass)
1600
 
 
1601
 
 
1602
1426
class TestAuth(http_utils.TestCaseWithWebserver):
1603
1427
    """Test authentication scheme"""
1604
1428
 
1608
1432
        vary_by_http_auth_scheme(),
1609
1433
        )
1610
1434
 
 
1435
    _auth_header = 'Authorization'
 
1436
    _password_prompt_prefix = ''
 
1437
    _username_prompt_prefix = ''
 
1438
    # Set by load_tests
 
1439
    _auth_server = None
 
1440
 
1611
1441
    def setUp(self):
1612
1442
        super(TestAuth, self).setUp()
1613
1443
        self.server = self.get_readonly_server()
1636
1466
        return url
1637
1467
 
1638
1468
    def get_user_transport(self, user, password):
1639
 
        t = transport.get_transport_from_url(
1640
 
            self.get_user_url(user, password))
 
1469
        t = transport.get_transport(self.get_user_url(user, password))
1641
1470
        return t
1642
1471
 
1643
1472
    def test_no_user(self):
1755
1584
        ui.ui_factory = tests.TestUIFactory(stdin=stdin_content,
1756
1585
                                            stderr=tests.StringIOWrapper())
1757
1586
        # Create a minimal config file with the right password
1758
 
        _setup_authentication_config(scheme='http', port=self.server.port,
1759
 
                                     user=user, password=password)
 
1587
        _setup_authentication_config(
 
1588
            scheme='http', 
 
1589
            port=self.server.port,
 
1590
            user=user,
 
1591
            password=password)
1760
1592
        # Issue a request to the server to connect
1761
1593
        self.assertEqual('contents of a\n',t.get('a').read())
1762
1594
        # stdin should have  been left untouched
1769
1601
                                     http_utils.ProxyDigestAuthServer):
1770
1602
            raise tests.TestNotApplicable('HTTP/proxy auth digest only test')
1771
1603
        if self._testing_pycurl():
1772
 
            self.knownFailure(
 
1604
            raise tests.KnownFailure(
1773
1605
                'pycurl does not handle a nonce change')
1774
1606
        self.server.add_user('joe', 'foo')
1775
1607
        t = self.get_user_transport('joe', 'foo')
1792
1624
        user = 'joe'
1793
1625
        password = 'foo'
1794
1626
        self.server.add_user(user, password)
1795
 
        _setup_authentication_config(scheme='http', port=self.server.port,
1796
 
                                     user=user, password=password)
 
1627
        _setup_authentication_config(
 
1628
            scheme='http', 
 
1629
            port=self.server.port,
 
1630
            user=user,
 
1631
            password=password)
1797
1632
        t = self.get_user_transport(None, None)
1798
1633
        # Issue a request to the server to connect
1799
1634
        self.assertEqual('contents of a\n', t.get('a').read())
1800
1635
        # Only one 'Authentication Required' error should occur
1801
1636
        self.assertEqual(1, self.server.auth_required_errors)
1802
1637
 
1803
 
    def test_no_credential_leaks_in_log(self):
1804
 
        self.overrideAttr(debug, 'debug_flags', set(['http']))
 
1638
 
 
1639
def _setup_authentication_config(**kwargs):
 
1640
    conf = config.AuthenticationConfig()
 
1641
    conf._get_config().update({'httptest': kwargs})
 
1642
    conf._save()
 
1643
 
 
1644
 
 
1645
 
 
1646
class TestUrllib2AuthHandler(tests.TestCaseWithTransport):
 
1647
    """Unit tests for glue by which urllib2 asks us for authentication"""
 
1648
 
 
1649
    def test_get_user_password_without_port(self):
 
1650
        """We cope if urllib2 doesn't tell us the port.
 
1651
 
 
1652
        See https://bugs.launchpad.net/bzr/+bug/654684
 
1653
        """
1805
1654
        user = 'joe'
1806
 
        password = 'very-sensitive-password'
1807
 
        self.server.add_user(user, password)
1808
 
        t = self.get_user_transport(user, password)
1809
 
        # Capture the debug calls to mutter
1810
 
        self.mutters = []
1811
 
        def mutter(*args):
1812
 
            lines = args[0] % args[1:]
1813
 
            # Some calls output multiple lines, just split them now since we
1814
 
            # care about a single one later.
1815
 
            self.mutters.extend(lines.splitlines())
1816
 
        self.overrideAttr(trace, 'mutter', mutter)
1817
 
        # Issue a request to the server to connect
1818
 
        self.assertEqual(True, t.has('a'))
1819
 
        # Only one 'Authentication Required' error should occur
1820
 
        self.assertEqual(1, self.server.auth_required_errors)
1821
 
        # Since the authentification succeeded, there should be a corresponding
1822
 
        # debug line
1823
 
        sent_auth_headers = [line for line in self.mutters
1824
 
                             if line.startswith('> %s' % (self._auth_header,))]
1825
 
        self.assertLength(1, sent_auth_headers)
1826
 
        self.assertStartsWith(sent_auth_headers[0],
1827
 
                              '> %s: <masked>' % (self._auth_header,))
 
1655
        password = 'foo'
 
1656
        _setup_authentication_config(
 
1657
            scheme='http', 
 
1658
            host='localhost',
 
1659
            user=user,
 
1660
            password=password)
 
1661
        handler = _urllib2_wrappers.HTTPAuthHandler()
 
1662
        got_pass = handler.get_user_password(dict(
 
1663
            user='joe',
 
1664
            protocol='http',
 
1665
            host='localhost',
 
1666
            path='/',
 
1667
            realm='Realm',
 
1668
            ))
 
1669
        self.assertEquals((user, password), got_pass)
1828
1670
 
1829
1671
 
1830
1672
class TestProxyAuth(TestAuth):
1831
 
    """Test proxy authentication schemes.
1832
 
 
1833
 
    This inherits from TestAuth to tweak the setUp and filter some failing
1834
 
    tests.
1835
 
    """
 
1673
    """Test proxy authentication schemes."""
1836
1674
 
1837
1675
    scenarios = multiply_scenarios(
1838
1676
        vary_by_http_client_implementation(),
1840
1678
        vary_by_http_proxy_auth_scheme(),
1841
1679
        )
1842
1680
 
 
1681
    _auth_header = 'Proxy-authorization'
 
1682
    _password_prompt_prefix = 'Proxy '
 
1683
    _username_prompt_prefix = 'Proxy '
 
1684
 
1843
1685
    def setUp(self):
1844
1686
        super(TestProxyAuth, self).setUp()
1845
1687
        # Override the contents to avoid false positives
1857
1699
        if self._testing_pycurl():
1858
1700
            import pycurl
1859
1701
            if pycurl.version_info()[1] < '7.16.0':
1860
 
                self.knownFailure(
 
1702
                raise tests.KnownFailure(
1861
1703
                    'pycurl < 7.16.0 does not handle empty proxy passwords')
1862
1704
        super(TestProxyAuth, self).test_empty_pass()
1863
1705
 
1888
1730
class SmartHTTPTunnellingTest(tests.TestCaseWithTransport):
1889
1731
 
1890
1732
    scenarios = multiply_scenarios(
1891
 
        vary_by_http_client_implementation(),
 
1733
        vary_by_http_client_implementation(), 
1892
1734
        vary_by_http_protocol_version(),
1893
1735
        )
1894
1736
 
1917
1759
        # The 'readv' command in the smart protocol both sends and receives
1918
1760
        # bulk data, so we use that.
1919
1761
        self.build_tree(['data-file'])
1920
 
        http_transport = transport.get_transport_from_url(
1921
 
            self.http_server.get_url())
 
1762
        http_transport = transport.get_transport(self.http_server.get_url())
1922
1763
        medium = http_transport.get_smart_medium()
1923
1764
        # Since we provide the medium, the url below will be mostly ignored
1924
1765
        # during the test, as long as the path is '/'.
1932
1773
        post_body = 'hello\n'
1933
1774
        expected_reply_body = 'ok\x012\n'
1934
1775
 
1935
 
        http_transport = transport.get_transport_from_url(
1936
 
            self.http_server.get_url())
 
1776
        http_transport = transport.get_transport(self.http_server.get_url())
1937
1777
        medium = http_transport.get_smart_medium()
1938
1778
        response = medium.send_http_smart_request(post_body)
1939
1779
        reply_body = response.read()
1997
1837
        self.assertIsInstance(r, type(t))
1998
1838
        # Both transports share the some connection
1999
1839
        self.assertEqual(t._get_connection(), r._get_connection())
2000
 
        self.assertEquals('http://www.example.com/foo/subdir/', r.base)
2001
1840
 
2002
1841
    def test_redirected_to_self_with_slash(self):
2003
1842
        t = self._transport('http://www.example.com/foo')
2014
1853
        r = t._redirected_to('http://www.example.com/foo',
2015
1854
                             'http://foo.example.com/foo/subdir')
2016
1855
        self.assertIsInstance(r, type(t))
2017
 
        self.assertEquals('http://foo.example.com/foo/subdir/',
2018
 
            r.external_url())
2019
1856
 
2020
1857
    def test_redirected_to_same_host_sibling_protocol(self):
2021
1858
        t = self._transport('http://www.example.com/foo')
2022
1859
        r = t._redirected_to('http://www.example.com/foo',
2023
1860
                             'https://www.example.com/foo')
2024
1861
        self.assertIsInstance(r, type(t))
2025
 
        self.assertEquals('https://www.example.com/foo/',
2026
 
            r.external_url())
2027
1862
 
2028
1863
    def test_redirected_to_same_host_different_protocol(self):
2029
1864
        t = self._transport('http://www.example.com/foo')
2030
1865
        r = t._redirected_to('http://www.example.com/foo',
2031
1866
                             'ftp://www.example.com/foo')
2032
1867
        self.assertNotEquals(type(r), type(t))
2033
 
        self.assertEquals('ftp://www.example.com/foo/', r.external_url())
2034
 
 
2035
 
    def test_redirected_to_same_host_specific_implementation(self):
2036
 
        t = self._transport('http://www.example.com/foo')
2037
 
        r = t._redirected_to('http://www.example.com/foo',
2038
 
                             'https+urllib://www.example.com/foo')
2039
 
        self.assertEquals('https://www.example.com/foo/', r.external_url())
2040
1868
 
2041
1869
    def test_redirected_to_different_host_same_user(self):
2042
1870
        t = self._transport('http://joe@www.example.com/foo')
2043
1871
        r = t._redirected_to('http://www.example.com/foo',
2044
1872
                             'https://foo.example.com/foo')
2045
1873
        self.assertIsInstance(r, type(t))
2046
 
        self.assertEqual(t._parsed_url.user, r._parsed_url.user)
2047
 
        self.assertEquals('https://joe@foo.example.com/foo/', r.external_url())
 
1874
        self.assertEqual(t._user, r._user)
2048
1875
 
2049
1876
 
2050
1877
class PredefinedRequestHandler(http_server.TestingHTTPRequestHandler):
2103
1930
    pass
2104
1931
 
2105
1932
 
2106
 
if features.HTTPSServerFeature.available():
 
1933
if tests.HTTPSServerFeature.available():
2107
1934
    from bzrlib.tests import https_server
2108
1935
    class ActivityHTTPSServer(ActivityServerMixin, https_server.HTTPSServer):
2109
1936
        pass
2120
1947
        tests.TestCase.setUp(self)
2121
1948
        self.server = self._activity_server(self._protocol_version)
2122
1949
        self.server.start_server()
2123
 
        _activities = {} # Don't close over self and create a cycle
 
1950
        self.activities = {}
2124
1951
        def report_activity(t, bytes, direction):
2125
 
            count = _activities.get(direction, 0)
 
1952
            count = self.activities.get(direction, 0)
2126
1953
            count += bytes
2127
 
            _activities[direction] = count
2128
 
        self.activities = _activities
 
1954
            self.activities[direction] = count
2129
1955
 
2130
1956
        # We override at class level because constructors may propagate the
2131
1957
        # bound method and render instance overriding ineffective (an
2356
2182
        # stdout should be empty, stderr will contains the prompts
2357
2183
        self.assertEqual('', stdout.getvalue())
2358
2184
 
 
2185