/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: Vincent Ladeuil
  • Date: 2011-07-06 09:22:00 UTC
  • mfrom: (6008 +trunk)
  • mto: (6012.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6013.
  • Revision ID: v.ladeuil+lp@free.fr-20110706092200-7iai2mwzc0sqdsvf
MergingĀ inĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
import bzrlib
33
33
from bzrlib import (
34
34
    bzrdir,
 
35
    cethread,
35
36
    config,
 
37
    debug,
36
38
    errors,
37
39
    osutils,
38
40
    remote as _mod_remote,
39
41
    tests,
 
42
    trace,
40
43
    transport,
41
44
    ui,
42
45
    )
90
93
        ]
91
94
 
92
95
 
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
 
 
102
96
def vary_by_http_auth_scheme():
103
 
    return [
 
97
    scenarios = [
104
98
        ('basic', dict(_auth_server=http_utils.HTTPBasicAuthServer)),
105
99
        ('digest', dict(_auth_server=http_utils.HTTPDigestAuthServer)),
106
100
        ('basicdigest',
107
101
            dict(_auth_server=http_utils.HTTPBasicAndDigestAuthServer)),
108
102
        ]
 
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
109
124
 
110
125
 
111
126
def vary_by_http_activity():
178
193
        self._sock.bind(('127.0.0.1', 0))
179
194
        self.host, self.port = self._sock.getsockname()
180
195
        self._ready = threading.Event()
181
 
        self._thread = test_server.ThreadWithException(
182
 
            event=self._ready, target=self._accept_read_and_reply)
 
196
        self._thread = test_server.TestThread(
 
197
            sync_event=self._ready, target=self._accept_read_and_reply)
183
198
        self._thread.start()
184
199
        if 'threads' in tests.selftest_debug_flags:
185
200
            sys.stderr.write('Thread started: %s\n' % (self._thread.ident,))
254
269
        self.assertEqual('realm="Thou should not pass"', remainder)
255
270
 
256
271
 
 
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
 
257
306
class TestHTTPServer(tests.TestCase):
258
307
    """Test the HTTP servers implementations."""
259
308
 
427
476
    """Test the http connections."""
428
477
 
429
478
    scenarios = multiply_scenarios(
430
 
        vary_by_http_client_implementation(), 
 
479
        vary_by_http_client_implementation(),
431
480
        vary_by_http_protocol_version(),
432
481
        )
433
482
 
492
541
class TestPost(tests.TestCase):
493
542
 
494
543
    scenarios = multiply_scenarios(
495
 
        vary_by_http_client_implementation(), 
 
544
        vary_by_http_client_implementation(),
496
545
        vary_by_http_protocol_version(),
497
546
        )
498
547
 
551
600
    """
552
601
 
553
602
    scenarios = multiply_scenarios(
554
 
        vary_by_http_client_implementation(), 
 
603
        vary_by_http_client_implementation(),
555
604
        vary_by_http_protocol_version(),
556
605
        )
557
606
 
1029
1078
    """Tests readv requests against a server erroring out on too much ranges."""
1030
1079
 
1031
1080
    scenarios = multiply_scenarios(
1032
 
        vary_by_http_client_implementation(), 
 
1081
        vary_by_http_client_implementation(),
1033
1082
        vary_by_http_protocol_version(),
1034
1083
        )
1035
1084
 
1075
1124
 
1076
1125
    def _proxied_request(self):
1077
1126
        handler = _urllib2_wrappers.ProxyHandler()
1078
 
        request = _urllib2_wrappers.Request('GET','http://baz/buzzle')
 
1127
        request = _urllib2_wrappers.Request('GET', 'http://baz/buzzle')
1079
1128
        handler.set_proxy(request, 'http')
1080
1129
        return request
1081
1130
 
 
1131
    def assertEvaluateProxyBypass(self, expected, host, no_proxy):
 
1132
        handler = _urllib2_wrappers.ProxyHandler()
 
1133
        self.assertEquals(expected,
 
1134
                          handler.evaluate_proxy_bypass(host, no_proxy))
 
1135
 
1082
1136
    def test_empty_user(self):
1083
1137
        self.overrideEnv('http_proxy', 'http://bar.com')
1084
1138
        request = self._proxied_request()
1085
1139
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1086
1140
 
 
1141
    def test_user_with_at(self):
 
1142
        self.overrideEnv('http_proxy',
 
1143
                         'http://username@domain:password@proxy_host:1234')
 
1144
        request = self._proxied_request()
 
1145
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
 
1146
 
1087
1147
    def test_invalid_proxy(self):
1088
1148
        """A proxy env variable without scheme"""
1089
1149
        self.overrideEnv('http_proxy', 'host:1234')
1090
1150
        self.assertRaises(errors.InvalidURL, self._proxied_request)
1091
1151
 
 
1152
    def test_evaluate_proxy_bypass_true(self):
 
1153
        """The host is not proxied"""
 
1154
        self.assertEvaluateProxyBypass(True, 'example.com', 'example.com')
 
1155
        self.assertEvaluateProxyBypass(True, 'bzr.example.com', '*example.com')
 
1156
 
 
1157
    def test_evaluate_proxy_bypass_false(self):
 
1158
        """The host is proxied"""
 
1159
        self.assertEvaluateProxyBypass(False, 'bzr.example.com', None)
 
1160
 
 
1161
    def test_evaluate_proxy_bypass_unknown(self):
 
1162
        """The host is not explicitly proxied"""
 
1163
        self.assertEvaluateProxyBypass(None, 'example.com', 'not.example.com')
 
1164
        self.assertEvaluateProxyBypass(None, 'bzr.example.com', 'example.com')
 
1165
 
 
1166
    def test_evaluate_proxy_bypass_empty_entries(self):
 
1167
        """Ignore empty entries"""
 
1168
        self.assertEvaluateProxyBypass(None, 'example.com', '')
 
1169
        self.assertEvaluateProxyBypass(None, 'example.com', ',')
 
1170
        self.assertEvaluateProxyBypass(None, 'example.com', 'foo,,bar')
 
1171
 
1092
1172
 
1093
1173
class TestProxyHttpServer(http_utils.TestCaseWithTwoWebservers):
1094
1174
    """Tests proxy server.
1100
1180
    """
1101
1181
 
1102
1182
    scenarios = multiply_scenarios(
1103
 
        vary_by_http_client_implementation(), 
 
1183
        vary_by_http_client_implementation(),
1104
1184
        vary_by_http_protocol_version(),
1105
1185
        )
1106
1186
 
1197
1277
    """Test the Range header in GET methods."""
1198
1278
 
1199
1279
    scenarios = multiply_scenarios(
1200
 
        vary_by_http_client_implementation(), 
 
1280
        vary_by_http_client_implementation(),
1201
1281
        vary_by_http_protocol_version(),
1202
1282
        )
1203
1283
 
1247
1327
    """Test redirection between http servers."""
1248
1328
 
1249
1329
    scenarios = multiply_scenarios(
1250
 
        vary_by_http_client_implementation(), 
 
1330
        vary_by_http_client_implementation(),
1251
1331
        vary_by_http_protocol_version(),
1252
1332
        )
1253
1333
 
1320
1400
    """
1321
1401
 
1322
1402
    scenarios = multiply_scenarios(
1323
 
        vary_by_http_client_implementation(), 
 
1403
        vary_by_http_client_implementation(),
1324
1404
        vary_by_http_protocol_version(),
1325
1405
        )
1326
1406
 
1375
1455
    """Test transport.do_catching_redirections."""
1376
1456
 
1377
1457
    scenarios = multiply_scenarios(
1378
 
        vary_by_http_client_implementation(), 
 
1458
        vary_by_http_client_implementation(),
1379
1459
        vary_by_http_protocol_version(),
1380
1460
        )
1381
1461
 
1423
1503
                          self.get_a, self.old_transport, redirected)
1424
1504
 
1425
1505
 
 
1506
def _setup_authentication_config(**kwargs):
 
1507
    conf = config.AuthenticationConfig()
 
1508
    conf._get_config().update({'httptest': kwargs})
 
1509
    conf._save()
 
1510
 
 
1511
 
 
1512
class TestUrllib2AuthHandler(tests.TestCaseWithTransport):
 
1513
    """Unit tests for glue by which urllib2 asks us for authentication"""
 
1514
 
 
1515
    def test_get_user_password_without_port(self):
 
1516
        """We cope if urllib2 doesn't tell us the port.
 
1517
 
 
1518
        See https://bugs.launchpad.net/bzr/+bug/654684
 
1519
        """
 
1520
        user = 'joe'
 
1521
        password = 'foo'
 
1522
        _setup_authentication_config(scheme='http', host='localhost',
 
1523
                                     user=user, password=password)
 
1524
        handler = _urllib2_wrappers.HTTPAuthHandler()
 
1525
        got_pass = handler.get_user_password(dict(
 
1526
            user='joe',
 
1527
            protocol='http',
 
1528
            host='localhost',
 
1529
            path='/',
 
1530
            realm='Realm',
 
1531
            ))
 
1532
        self.assertEquals((user, password), got_pass)
 
1533
 
 
1534
 
1426
1535
class TestAuth(http_utils.TestCaseWithWebserver):
1427
1536
    """Test authentication scheme"""
1428
1537
 
1432
1541
        vary_by_http_auth_scheme(),
1433
1542
        )
1434
1543
 
1435
 
    _auth_header = 'Authorization'
1436
 
    _password_prompt_prefix = ''
1437
 
    _username_prompt_prefix = ''
1438
 
    # Set by load_tests
1439
 
    _auth_server = None
1440
 
 
1441
1544
    def setUp(self):
1442
1545
        super(TestAuth, self).setUp()
1443
1546
        self.server = self.get_readonly_server()
1584
1687
        ui.ui_factory = tests.TestUIFactory(stdin=stdin_content,
1585
1688
                                            stderr=tests.StringIOWrapper())
1586
1689
        # Create a minimal config file with the right password
1587
 
        _setup_authentication_config(
1588
 
            scheme='http', 
1589
 
            port=self.server.port,
1590
 
            user=user,
1591
 
            password=password)
 
1690
        _setup_authentication_config(scheme='http', port=self.server.port,
 
1691
                                     user=user, password=password)
1592
1692
        # Issue a request to the server to connect
1593
1693
        self.assertEqual('contents of a\n',t.get('a').read())
1594
1694
        # stdin should have  been left untouched
1624
1724
        user = 'joe'
1625
1725
        password = 'foo'
1626
1726
        self.server.add_user(user, password)
1627
 
        _setup_authentication_config(
1628
 
            scheme='http', 
1629
 
            port=self.server.port,
1630
 
            user=user,
1631
 
            password=password)
 
1727
        _setup_authentication_config(scheme='http', port=self.server.port,
 
1728
                                     user=user, password=password)
1632
1729
        t = self.get_user_transport(None, None)
1633
1730
        # Issue a request to the server to connect
1634
1731
        self.assertEqual('contents of a\n', t.get('a').read())
1635
1732
        # Only one 'Authentication Required' error should occur
1636
1733
        self.assertEqual(1, self.server.auth_required_errors)
1637
1734
 
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
 
        """
 
1735
    def test_no_credential_leaks_in_log(self):
 
1736
        self.overrideAttr(debug, 'debug_flags', set(['http']))
1654
1737
        user = 'joe'
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)
 
1738
        password = 'very-sensitive-password'
 
1739
        self.server.add_user(user, password)
 
1740
        t = self.get_user_transport(user, password)
 
1741
        # Capture the debug calls to mutter
 
1742
        self.mutters = []
 
1743
        def mutter(*args):
 
1744
            lines = args[0] % args[1:]
 
1745
            # Some calls output multiple lines, just split them now since we
 
1746
            # care about a single one later.
 
1747
            self.mutters.extend(lines.splitlines())
 
1748
        self.overrideAttr(trace, 'mutter', mutter)
 
1749
        # Issue a request to the server to connect
 
1750
        self.assertEqual(True, t.has('a'))
 
1751
        # Only one 'Authentication Required' error should occur
 
1752
        self.assertEqual(1, self.server.auth_required_errors)
 
1753
        # Since the authentification succeeded, there should be a corresponding
 
1754
        # debug line
 
1755
        sent_auth_headers = [line for line in self.mutters
 
1756
                             if line.startswith('> %s' % (self._auth_header,))]
 
1757
        self.assertLength(1, sent_auth_headers)
 
1758
        self.assertStartsWith(sent_auth_headers[0],
 
1759
                              '> %s: <masked>' % (self._auth_header,))
1670
1760
 
1671
1761
 
1672
1762
class TestProxyAuth(TestAuth):
1673
 
    """Test proxy authentication schemes."""
 
1763
    """Test proxy authentication schemes.
 
1764
 
 
1765
    This inherits from TestAuth to tweak the setUp and filter some failing
 
1766
    tests.
 
1767
    """
1674
1768
 
1675
1769
    scenarios = multiply_scenarios(
1676
1770
        vary_by_http_client_implementation(),
1678
1772
        vary_by_http_proxy_auth_scheme(),
1679
1773
        )
1680
1774
 
1681
 
    _auth_header = 'Proxy-authorization'
1682
 
    _password_prompt_prefix = 'Proxy '
1683
 
    _username_prompt_prefix = 'Proxy '
1684
 
 
1685
1775
    def setUp(self):
1686
1776
        super(TestProxyAuth, self).setUp()
1687
1777
        # Override the contents to avoid false positives
1730
1820
class SmartHTTPTunnellingTest(tests.TestCaseWithTransport):
1731
1821
 
1732
1822
    scenarios = multiply_scenarios(
1733
 
        vary_by_http_client_implementation(), 
 
1823
        vary_by_http_client_implementation(),
1734
1824
        vary_by_http_protocol_version(),
1735
1825
        )
1736
1826
 
1947
2037
        tests.TestCase.setUp(self)
1948
2038
        self.server = self._activity_server(self._protocol_version)
1949
2039
        self.server.start_server()
1950
 
        self.activities = {}
 
2040
        _activities = {} # Don't close over self and create a cycle
1951
2041
        def report_activity(t, bytes, direction):
1952
 
            count = self.activities.get(direction, 0)
 
2042
            count = _activities.get(direction, 0)
1953
2043
            count += bytes
1954
 
            self.activities[direction] = count
 
2044
            _activities[direction] = count
 
2045
        self.activities = _activities
1955
2046
 
1956
2047
        # We override at class level because constructors may propagate the
1957
2048
        # bound method and render instance overriding ineffective (an
2182
2273
        # stdout should be empty, stderr will contains the prompts
2183
2274
        self.assertEqual('', stdout.getvalue())
2184
2275
 
2185