~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: Andrew Bennetts
  • Date: 2010-11-22 03:35:24 UTC
  • mto: This revision was merged to the branch mainline in revision 5547.
  • Revision ID: andrew.bennetts@canonical.com-20101122033524-ouxj0onm3gtkimx3
Remove RepositoryFormatCHK1 and RepositoryFormatCHK2.

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
 
403
354
 
404
355
    def test_abs_url(self):
405
356
        """Construction of absolute http URLs"""
406
 
        t = self._transport('http://example.com/bzr/bzr.dev/')
 
357
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
407
358
        eq = self.assertEqualDiff
408
 
        eq(t.abspath('.'), 'http://example.com/bzr/bzr.dev')
409
 
        eq(t.abspath('foo/bar'), 'http://example.com/bzr/bzr.dev/foo/bar')
410
 
        eq(t.abspath('.bzr'), 'http://example.com/bzr/bzr.dev/.bzr')
 
359
        eq(t.abspath('.'), 'http://bazaar-vcs.org/bzr/bzr.dev')
 
360
        eq(t.abspath('foo/bar'), 'http://bazaar-vcs.org/bzr/bzr.dev/foo/bar')
 
361
        eq(t.abspath('.bzr'), 'http://bazaar-vcs.org/bzr/bzr.dev/.bzr')
411
362
        eq(t.abspath('.bzr/1//2/./3'),
412
 
           'http://example.com/bzr/bzr.dev/.bzr/1/2/3')
 
363
           'http://bazaar-vcs.org/bzr/bzr.dev/.bzr/1/2/3')
413
364
 
414
365
    def test_invalid_http_urls(self):
415
366
        """Trap invalid construction of urls"""
416
 
        self._transport('http://example.com/bzr/bzr.dev/')
 
367
        self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
417
368
        self.assertRaises(errors.InvalidURL,
418
369
                          self._transport,
419
 
                          'http://http://example.com/bzr/bzr.dev/')
 
370
                          'http://http://bazaar-vcs.org/bzr/bzr.dev/')
420
371
 
421
372
    def test_http_root_urls(self):
422
373
        """Construction of URLs from server root"""
423
 
        t = self._transport('http://example.com/')
 
374
        t = self._transport('http://bzr.ozlabs.org/')
424
375
        eq = self.assertEqualDiff
425
376
        eq(t.abspath('.bzr/tree-version'),
426
 
           'http://example.com/.bzr/tree-version')
 
377
           'http://bzr.ozlabs.org/.bzr/tree-version')
427
378
 
428
379
    def test_http_impl_urls(self):
429
380
        """There are servers which ask for particular clients to connect"""
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
 
1189
1073
    Only the urllib implementation is tested here.
1190
1074
    """
1191
1075
 
 
1076
    def setUp(self):
 
1077
        tests.TestCase.setUp(self)
 
1078
        self._old_env = {}
 
1079
        self.addCleanup(self._restore_env)
 
1080
 
 
1081
    def _install_env(self, env):
 
1082
        for name, value in env.iteritems():
 
1083
            self._old_env[name] = osutils.set_or_unset_env(name, value)
 
1084
 
 
1085
    def _restore_env(self):
 
1086
        for name, value in self._old_env.iteritems():
 
1087
            osutils.set_or_unset_env(name, value)
 
1088
 
1192
1089
    def _proxied_request(self):
1193
1090
        handler = _urllib2_wrappers.ProxyHandler()
1194
 
        request = _urllib2_wrappers.Request('GET', 'http://baz/buzzle')
 
1091
        request = _urllib2_wrappers.Request('GET','http://baz/buzzle')
1195
1092
        handler.set_proxy(request, 'http')
1196
1093
        return request
1197
1094
 
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
1095
    def test_empty_user(self):
1204
 
        self.overrideEnv('http_proxy', 'http://bar.com')
1205
 
        request = self._proxied_request()
1206
 
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1207
 
 
1208
 
    def test_user_with_at(self):
1209
 
        self.overrideEnv('http_proxy',
1210
 
                         'http://username@domain:password@proxy_host:1234')
 
1096
        self._install_env({'http_proxy': 'http://bar.com'})
1211
1097
        request = self._proxied_request()
1212
1098
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1213
1099
 
1214
1100
    def test_invalid_proxy(self):
1215
1101
        """A proxy env variable without scheme"""
1216
 
        self.overrideEnv('http_proxy', 'host:1234')
 
1102
        self._install_env({'http_proxy': 'host:1234'})
1217
1103
        self.assertRaises(errors.InvalidURL, self._proxied_request)
1218
1104
 
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
1105
 
1240
1106
class TestProxyHttpServer(http_utils.TestCaseWithTwoWebservers):
1241
1107
    """Tests proxy server.
1247
1113
    """
1248
1114
 
1249
1115
    scenarios = multiply_scenarios(
1250
 
        vary_by_http_client_implementation(),
 
1116
        vary_by_http_client_implementation(), 
1251
1117
        vary_by_http_protocol_version(),
1252
1118
        )
1253
1119
 
1270
1136
            self.no_proxy_host = self.server_host_port
1271
1137
        # The secondary server is the proxy
1272
1138
        self.proxy_url = self.get_secondary_url()
 
1139
        self._old_env = {}
1273
1140
 
1274
1141
    def _testing_pycurl(self):
1275
1142
        # TODO: This is duplicated for lots of the classes in this file
1276
1143
        return (features.pycurl.available()
1277
1144
                and self._transport == PyCurlTransport)
1278
1145
 
1279
 
    def assertProxied(self):
1280
 
        t = self.get_readonly_transport()
1281
 
        self.assertEqual('proxied contents of foo\n', t.get('foo').read())
1282
 
 
1283
 
    def assertNotProxied(self):
1284
 
        t = self.get_readonly_transport()
1285
 
        self.assertEqual('contents of foo\n', t.get('foo').read())
 
1146
    def _install_env(self, env):
 
1147
        for name, value in env.iteritems():
 
1148
            self._old_env[name] = osutils.set_or_unset_env(name, value)
 
1149
 
 
1150
    def _restore_env(self):
 
1151
        for name, value in self._old_env.iteritems():
 
1152
            osutils.set_or_unset_env(name, value)
 
1153
 
 
1154
    def proxied_in_env(self, env):
 
1155
        self._install_env(env)
 
1156
        t = self.get_readonly_transport()
 
1157
        try:
 
1158
            self.assertEqual('proxied contents of foo\n', t.get('foo').read())
 
1159
        finally:
 
1160
            self._restore_env()
 
1161
 
 
1162
    def not_proxied_in_env(self, env):
 
1163
        self._install_env(env)
 
1164
        t = self.get_readonly_transport()
 
1165
        try:
 
1166
            self.assertEqual('contents of foo\n', t.get('foo').read())
 
1167
        finally:
 
1168
            self._restore_env()
1286
1169
 
1287
1170
    def test_http_proxy(self):
1288
 
        self.overrideEnv('http_proxy', self.proxy_url)
1289
 
        self.assertProxied()
 
1171
        self.proxied_in_env({'http_proxy': self.proxy_url})
1290
1172
 
1291
1173
    def test_HTTP_PROXY(self):
1292
1174
        if self._testing_pycurl():
1295
1177
            # about. Should we ?)
1296
1178
            raise tests.TestNotApplicable(
1297
1179
                'pycurl does not check HTTP_PROXY for security reasons')
1298
 
        self.overrideEnv('HTTP_PROXY', self.proxy_url)
1299
 
        self.assertProxied()
 
1180
        self.proxied_in_env({'HTTP_PROXY': self.proxy_url})
1300
1181
 
1301
1182
    def test_all_proxy(self):
1302
 
        self.overrideEnv('all_proxy', self.proxy_url)
1303
 
        self.assertProxied()
 
1183
        self.proxied_in_env({'all_proxy': self.proxy_url})
1304
1184
 
1305
1185
    def test_ALL_PROXY(self):
1306
 
        self.overrideEnv('ALL_PROXY', self.proxy_url)
1307
 
        self.assertProxied()
 
1186
        self.proxied_in_env({'ALL_PROXY': self.proxy_url})
1308
1187
 
1309
1188
    def test_http_proxy_with_no_proxy(self):
1310
 
        self.overrideEnv('no_proxy', self.no_proxy_host)
1311
 
        self.overrideEnv('http_proxy', self.proxy_url)
1312
 
        self.assertNotProxied()
 
1189
        self.not_proxied_in_env({'http_proxy': self.proxy_url,
 
1190
                                 'no_proxy': self.no_proxy_host})
1313
1191
 
1314
1192
    def test_HTTP_PROXY_with_NO_PROXY(self):
1315
1193
        if self._testing_pycurl():
1316
1194
            raise tests.TestNotApplicable(
1317
1195
                'pycurl does not check HTTP_PROXY for security reasons')
1318
 
        self.overrideEnv('NO_PROXY', self.no_proxy_host)
1319
 
        self.overrideEnv('HTTP_PROXY', self.proxy_url)
1320
 
        self.assertNotProxied()
 
1196
        self.not_proxied_in_env({'HTTP_PROXY': self.proxy_url,
 
1197
                                 'NO_PROXY': self.no_proxy_host})
1321
1198
 
1322
1199
    def test_all_proxy_with_no_proxy(self):
1323
 
        self.overrideEnv('no_proxy', self.no_proxy_host)
1324
 
        self.overrideEnv('all_proxy', self.proxy_url)
1325
 
        self.assertNotProxied()
 
1200
        self.not_proxied_in_env({'all_proxy': self.proxy_url,
 
1201
                                 'no_proxy': self.no_proxy_host})
1326
1202
 
1327
1203
    def test_ALL_PROXY_with_NO_PROXY(self):
1328
 
        self.overrideEnv('NO_PROXY', self.no_proxy_host)
1329
 
        self.overrideEnv('ALL_PROXY', self.proxy_url)
1330
 
        self.assertNotProxied()
 
1204
        self.not_proxied_in_env({'ALL_PROXY': self.proxy_url,
 
1205
                                 'NO_PROXY': self.no_proxy_host})
1331
1206
 
1332
1207
    def test_http_proxy_without_scheme(self):
1333
 
        self.overrideEnv('http_proxy', self.server_host_port)
1334
1208
        if self._testing_pycurl():
1335
1209
            # pycurl *ignores* invalid proxy env variables. If that ever change
1336
1210
            # in the future, this test will fail indicating that pycurl do not
1337
1211
            # ignore anymore such variables.
1338
 
            self.assertNotProxied()
 
1212
            self.not_proxied_in_env({'http_proxy': self.server_host_port})
1339
1213
        else:
1340
 
            self.assertRaises(errors.InvalidURL, self.assertProxied)
 
1214
            self.assertRaises(errors.InvalidURL,
 
1215
                              self.proxied_in_env,
 
1216
                              {'http_proxy': self.server_host_port})
1341
1217
 
1342
1218
 
1343
1219
class TestRanges(http_utils.TestCaseWithWebserver):
1344
1220
    """Test the Range header in GET methods."""
1345
1221
 
1346
1222
    scenarios = multiply_scenarios(
1347
 
        vary_by_http_client_implementation(),
 
1223
        vary_by_http_client_implementation(), 
1348
1224
        vary_by_http_protocol_version(),
1349
1225
        )
1350
1226
 
1394
1270
    """Test redirection between http servers."""
1395
1271
 
1396
1272
    scenarios = multiply_scenarios(
1397
 
        vary_by_http_client_implementation(),
 
1273
        vary_by_http_client_implementation(), 
1398
1274
        vary_by_http_protocol_version(),
1399
1275
        )
1400
1276
 
1467
1343
    """
1468
1344
 
1469
1345
    scenarios = multiply_scenarios(
1470
 
        vary_by_http_client_implementation(),
 
1346
        vary_by_http_client_implementation(), 
1471
1347
        vary_by_http_protocol_version(),
1472
1348
        )
1473
1349
 
1522
1398
    """Test transport.do_catching_redirections."""
1523
1399
 
1524
1400
    scenarios = multiply_scenarios(
1525
 
        vary_by_http_client_implementation(),
 
1401
        vary_by_http_client_implementation(), 
1526
1402
        vary_by_http_protocol_version(),
1527
1403
        )
1528
1404
 
1570
1446
                          self.get_a, self.old_transport, redirected)
1571
1447
 
1572
1448
 
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
1449
class TestAuth(http_utils.TestCaseWithWebserver):
1603
1450
    """Test authentication scheme"""
1604
1451
 
1608
1455
        vary_by_http_auth_scheme(),
1609
1456
        )
1610
1457
 
 
1458
    _auth_header = 'Authorization'
 
1459
    _password_prompt_prefix = ''
 
1460
    _username_prompt_prefix = ''
 
1461
    # Set by load_tests
 
1462
    _auth_server = None
 
1463
 
1611
1464
    def setUp(self):
1612
1465
        super(TestAuth, self).setUp()
1613
1466
        self.server = self.get_readonly_server()
1636
1489
        return url
1637
1490
 
1638
1491
    def get_user_transport(self, user, password):
1639
 
        t = transport.get_transport_from_url(
1640
 
            self.get_user_url(user, password))
 
1492
        t = transport.get_transport(self.get_user_url(user, password))
1641
1493
        return t
1642
1494
 
1643
1495
    def test_no_user(self):
1755
1607
        ui.ui_factory = tests.TestUIFactory(stdin=stdin_content,
1756
1608
                                            stderr=tests.StringIOWrapper())
1757
1609
        # Create a minimal config file with the right password
1758
 
        _setup_authentication_config(scheme='http', port=self.server.port,
1759
 
                                     user=user, password=password)
 
1610
        _setup_authentication_config(
 
1611
            scheme='http', 
 
1612
            port=self.server.port,
 
1613
            user=user,
 
1614
            password=password)
1760
1615
        # Issue a request to the server to connect
1761
1616
        self.assertEqual('contents of a\n',t.get('a').read())
1762
1617
        # stdin should have  been left untouched
1769
1624
                                     http_utils.ProxyDigestAuthServer):
1770
1625
            raise tests.TestNotApplicable('HTTP/proxy auth digest only test')
1771
1626
        if self._testing_pycurl():
1772
 
            self.knownFailure(
 
1627
            raise tests.KnownFailure(
1773
1628
                'pycurl does not handle a nonce change')
1774
1629
        self.server.add_user('joe', 'foo')
1775
1630
        t = self.get_user_transport('joe', 'foo')
1792
1647
        user = 'joe'
1793
1648
        password = 'foo'
1794
1649
        self.server.add_user(user, password)
1795
 
        _setup_authentication_config(scheme='http', port=self.server.port,
1796
 
                                     user=user, password=password)
 
1650
        _setup_authentication_config(
 
1651
            scheme='http', 
 
1652
            port=self.server.port,
 
1653
            user=user,
 
1654
            password=password)
1797
1655
        t = self.get_user_transport(None, None)
1798
1656
        # Issue a request to the server to connect
1799
1657
        self.assertEqual('contents of a\n', t.get('a').read())
1800
1658
        # Only one 'Authentication Required' error should occur
1801
1659
        self.assertEqual(1, self.server.auth_required_errors)
1802
1660
 
1803
 
    def test_no_credential_leaks_in_log(self):
1804
 
        self.overrideAttr(debug, 'debug_flags', set(['http']))
 
1661
 
 
1662
def _setup_authentication_config(**kwargs):
 
1663
    conf = config.AuthenticationConfig()
 
1664
    conf._get_config().update({'httptest': kwargs})
 
1665
    conf._save()
 
1666
 
 
1667
 
 
1668
 
 
1669
class TestUrllib2AuthHandler(tests.TestCaseWithTransport):
 
1670
    """Unit tests for glue by which urllib2 asks us for authentication"""
 
1671
 
 
1672
    def test_get_user_password_without_port(self):
 
1673
        """We cope if urllib2 doesn't tell us the port.
 
1674
 
 
1675
        See https://bugs.launchpad.net/bzr/+bug/654684
 
1676
        """
1805
1677
        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,))
 
1678
        password = 'foo'
 
1679
        _setup_authentication_config(
 
1680
            scheme='http', 
 
1681
            host='localhost',
 
1682
            user=user,
 
1683
            password=password)
 
1684
        handler = _urllib2_wrappers.HTTPAuthHandler()
 
1685
        got_pass = handler.get_user_password(dict(
 
1686
            user='joe',
 
1687
            protocol='http',
 
1688
            host='localhost',
 
1689
            path='/',
 
1690
            realm='Realm',
 
1691
            ))
 
1692
        self.assertEquals((user, password), got_pass)
1828
1693
 
1829
1694
 
1830
1695
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
 
    """
 
1696
    """Test proxy authentication schemes."""
1836
1697
 
1837
1698
    scenarios = multiply_scenarios(
1838
1699
        vary_by_http_client_implementation(),
1840
1701
        vary_by_http_proxy_auth_scheme(),
1841
1702
        )
1842
1703
 
 
1704
    _auth_header = 'Proxy-authorization'
 
1705
    _password_prompt_prefix = 'Proxy '
 
1706
    _username_prompt_prefix = 'Proxy '
 
1707
 
1843
1708
    def setUp(self):
1844
1709
        super(TestProxyAuth, self).setUp()
 
1710
        self._old_env = {}
 
1711
        self.addCleanup(self._restore_env)
1845
1712
        # Override the contents to avoid false positives
1846
1713
        self.build_tree_contents([('a', 'not proxied contents of a\n'),
1847
1714
                                  ('b', 'not proxied contents of b\n'),
1850
1717
                                  ])
1851
1718
 
1852
1719
    def get_user_transport(self, user, password):
1853
 
        self.overrideEnv('all_proxy', self.get_user_url(user, password))
 
1720
        self._install_env({'all_proxy': self.get_user_url(user, password)})
1854
1721
        return TestAuth.get_user_transport(self, user, password)
1855
1722
 
 
1723
    def _install_env(self, env):
 
1724
        for name, value in env.iteritems():
 
1725
            self._old_env[name] = osutils.set_or_unset_env(name, value)
 
1726
 
 
1727
    def _restore_env(self):
 
1728
        for name, value in self._old_env.iteritems():
 
1729
            osutils.set_or_unset_env(name, value)
 
1730
 
1856
1731
    def test_empty_pass(self):
1857
1732
        if self._testing_pycurl():
1858
1733
            import pycurl
1859
1734
            if pycurl.version_info()[1] < '7.16.0':
1860
 
                self.knownFailure(
 
1735
                raise tests.KnownFailure(
1861
1736
                    'pycurl < 7.16.0 does not handle empty proxy passwords')
1862
1737
        super(TestProxyAuth, self).test_empty_pass()
1863
1738
 
1888
1763
class SmartHTTPTunnellingTest(tests.TestCaseWithTransport):
1889
1764
 
1890
1765
    scenarios = multiply_scenarios(
1891
 
        vary_by_http_client_implementation(),
 
1766
        vary_by_http_client_implementation(), 
1892
1767
        vary_by_http_protocol_version(),
1893
1768
        )
1894
1769
 
1895
1770
    def setUp(self):
1896
1771
        super(SmartHTTPTunnellingTest, self).setUp()
1897
1772
        # We use the VFS layer as part of HTTP tunnelling tests.
1898
 
        self.overrideEnv('BZR_NO_SMART_VFS', None)
 
1773
        self._captureVar('BZR_NO_SMART_VFS', None)
1899
1774
        self.transport_readonly_server = http_utils.HTTPServerWithSmarts
1900
1775
        self.http_server = self.get_readonly_server()
1901
1776
 
1917
1792
        # The 'readv' command in the smart protocol both sends and receives
1918
1793
        # bulk data, so we use that.
1919
1794
        self.build_tree(['data-file'])
1920
 
        http_transport = transport.get_transport_from_url(
1921
 
            self.http_server.get_url())
 
1795
        http_transport = transport.get_transport(self.http_server.get_url())
1922
1796
        medium = http_transport.get_smart_medium()
1923
1797
        # Since we provide the medium, the url below will be mostly ignored
1924
1798
        # during the test, as long as the path is '/'.
1932
1806
        post_body = 'hello\n'
1933
1807
        expected_reply_body = 'ok\x012\n'
1934
1808
 
1935
 
        http_transport = transport.get_transport_from_url(
1936
 
            self.http_server.get_url())
 
1809
        http_transport = transport.get_transport(self.http_server.get_url())
1937
1810
        medium = http_transport.get_smart_medium()
1938
1811
        response = medium.send_http_smart_request(post_body)
1939
1812
        reply_body = response.read()
1997
1870
        self.assertIsInstance(r, type(t))
1998
1871
        # Both transports share the some connection
1999
1872
        self.assertEqual(t._get_connection(), r._get_connection())
2000
 
        self.assertEquals('http://www.example.com/foo/subdir/', r.base)
2001
1873
 
2002
1874
    def test_redirected_to_self_with_slash(self):
2003
1875
        t = self._transport('http://www.example.com/foo')
2014
1886
        r = t._redirected_to('http://www.example.com/foo',
2015
1887
                             'http://foo.example.com/foo/subdir')
2016
1888
        self.assertIsInstance(r, type(t))
2017
 
        self.assertEquals('http://foo.example.com/foo/subdir/',
2018
 
            r.external_url())
2019
1889
 
2020
1890
    def test_redirected_to_same_host_sibling_protocol(self):
2021
1891
        t = self._transport('http://www.example.com/foo')
2022
1892
        r = t._redirected_to('http://www.example.com/foo',
2023
1893
                             'https://www.example.com/foo')
2024
1894
        self.assertIsInstance(r, type(t))
2025
 
        self.assertEquals('https://www.example.com/foo/',
2026
 
            r.external_url())
2027
1895
 
2028
1896
    def test_redirected_to_same_host_different_protocol(self):
2029
1897
        t = self._transport('http://www.example.com/foo')
2030
1898
        r = t._redirected_to('http://www.example.com/foo',
2031
1899
                             'ftp://www.example.com/foo')
2032
1900
        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
1901
 
2041
1902
    def test_redirected_to_different_host_same_user(self):
2042
1903
        t = self._transport('http://joe@www.example.com/foo')
2043
1904
        r = t._redirected_to('http://www.example.com/foo',
2044
1905
                             'https://foo.example.com/foo')
2045
1906
        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())
 
1907
        self.assertEqual(t._user, r._user)
2048
1908
 
2049
1909
 
2050
1910
class PredefinedRequestHandler(http_server.TestingHTTPRequestHandler):
2103
1963
    pass
2104
1964
 
2105
1965
 
2106
 
if features.HTTPSServerFeature.available():
 
1966
if tests.HTTPSServerFeature.available():
2107
1967
    from bzrlib.tests import https_server
2108
1968
    class ActivityHTTPSServer(ActivityServerMixin, https_server.HTTPSServer):
2109
1969
        pass
2120
1980
        tests.TestCase.setUp(self)
2121
1981
        self.server = self._activity_server(self._protocol_version)
2122
1982
        self.server.start_server()
2123
 
        _activities = {} # Don't close over self and create a cycle
 
1983
        self.activities = {}
2124
1984
        def report_activity(t, bytes, direction):
2125
 
            count = _activities.get(direction, 0)
 
1985
            count = self.activities.get(direction, 0)
2126
1986
            count += bytes
2127
 
            _activities[direction] = count
2128
 
        self.activities = _activities
 
1987
            self.activities[direction] = count
2129
1988
 
2130
1989
        # We override at class level because constructors may propagate the
2131
1990
        # bound method and render instance overriding ineffective (an
2356
2215
        # stdout should be empty, stderr will contains the prompts
2357
2216
        self.assertEqual('', stdout.getvalue())
2358
2217
 
 
2218