~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-09-01 08:02:42 UTC
  • mfrom: (5390.3.3 faster-revert-593560)
  • Revision ID: pqm@pqm.ubuntu.com-20100901080242-esg62ody4frwmy66
(spiv) Avoid repeatedly calling self.target.all_file_ids() in
 InterTree.iter_changes. (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2015 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
23
23
# TODO: Should be renamed to bzrlib.transport.http.tests?
24
24
# TODO: What about renaming to bzrlib.tests.transport.http ?
25
25
 
 
26
from cStringIO import StringIO
26
27
import httplib
 
28
import os
 
29
import select
27
30
import SimpleHTTPServer
28
31
import socket
29
32
import sys
31
34
 
32
35
import bzrlib
33
36
from bzrlib import (
 
37
    bzrdir,
34
38
    config,
35
 
    controldir,
36
 
    debug,
37
39
    errors,
38
40
    osutils,
39
41
    remote as _mod_remote,
40
42
    tests,
41
 
    trace,
42
43
    transport,
43
44
    ui,
 
45
    urlutils,
44
46
    )
45
47
from bzrlib.tests import (
46
48
    features,
48
50
    http_utils,
49
51
    test_server,
50
52
    )
51
 
from bzrlib.tests.scenarios import (
52
 
    load_tests_apply_scenarios,
53
 
    multiply_scenarios,
54
 
    )
55
53
from bzrlib.transport import (
56
54
    http,
57
55
    remote,
66
64
    from bzrlib.transport.http._pycurl import PyCurlTransport
67
65
 
68
66
 
69
 
load_tests = load_tests_apply_scenarios
70
 
 
71
 
 
72
 
def vary_by_http_client_implementation():
73
 
    """Test the two libraries we can use, pycurl and urllib."""
 
67
def load_tests(standard_tests, module, loader):
 
68
    """Multiply tests for http clients and protocol versions."""
 
69
    result = loader.suiteClass()
 
70
 
 
71
    # one for each transport implementation
 
72
    t_tests, remaining_tests = tests.split_suite_by_condition(
 
73
        standard_tests, tests.condition_isinstance((
 
74
                TestHttpTransportRegistration,
 
75
                TestHttpTransportUrls,
 
76
                Test_redirected_to,
 
77
                )))
74
78
    transport_scenarios = [
75
79
        ('urllib', dict(_transport=_urllib.HttpTransport_urllib,
76
80
                        _server=http_server.HttpServer_urllib,
81
85
            ('pycurl', dict(_transport=PyCurlTransport,
82
86
                            _server=http_server.HttpServer_PyCurl,
83
87
                            _url_protocol='http+pycurl',)))
84
 
    return transport_scenarios
85
 
 
86
 
 
87
 
def vary_by_http_protocol_version():
88
 
    """Test on http/1.0 and 1.1"""
89
 
    return [
90
 
        ('HTTP/1.0',  dict(_protocol_version='HTTP/1.0')),
91
 
        ('HTTP/1.1',  dict(_protocol_version='HTTP/1.1')),
 
88
    tests.multiply_tests(t_tests, transport_scenarios, result)
 
89
 
 
90
    protocol_scenarios = [
 
91
            ('HTTP/1.0',  dict(_protocol_version='HTTP/1.0')),
 
92
            ('HTTP/1.1',  dict(_protocol_version='HTTP/1.1')),
 
93
            ]
 
94
 
 
95
    # some tests are parametrized by the protocol version only
 
96
    p_tests, remaining_tests = tests.split_suite_by_condition(
 
97
        remaining_tests, tests.condition_isinstance((
 
98
                TestAuthOnRedirected,
 
99
                )))
 
100
    tests.multiply_tests(p_tests, protocol_scenarios, result)
 
101
 
 
102
    # each implementation tested with each HTTP version
 
103
    tp_tests, remaining_tests = tests.split_suite_by_condition(
 
104
        remaining_tests, tests.condition_isinstance((
 
105
                SmartHTTPTunnellingTest,
 
106
                TestDoCatchRedirections,
 
107
                TestHTTPConnections,
 
108
                TestHTTPRedirections,
 
109
                TestHTTPSilentRedirections,
 
110
                TestLimitedRangeRequestServer,
 
111
                TestPost,
 
112
                TestProxyHttpServer,
 
113
                TestRanges,
 
114
                TestSpecificRequestHandler,
 
115
                )))
 
116
    tp_scenarios = tests.multiply_scenarios(transport_scenarios,
 
117
                                            protocol_scenarios)
 
118
    tests.multiply_tests(tp_tests, tp_scenarios, result)
 
119
 
 
120
    # proxy auth: each auth scheme on all http versions on all implementations.
 
121
    tppa_tests, remaining_tests = tests.split_suite_by_condition(
 
122
        remaining_tests, tests.condition_isinstance((
 
123
                TestProxyAuth,
 
124
                )))
 
125
    proxy_auth_scheme_scenarios = [
 
126
        ('basic', dict(_auth_server=http_utils.ProxyBasicAuthServer)),
 
127
        ('digest', dict(_auth_server=http_utils.ProxyDigestAuthServer)),
 
128
        ('basicdigest',
 
129
         dict(_auth_server=http_utils.ProxyBasicAndDigestAuthServer)),
92
130
        ]
93
 
 
94
 
 
95
 
def vary_by_http_auth_scheme():
96
 
    scenarios = [
 
131
    tppa_scenarios = tests.multiply_scenarios(tp_scenarios,
 
132
                                              proxy_auth_scheme_scenarios)
 
133
    tests.multiply_tests(tppa_tests, tppa_scenarios, result)
 
134
 
 
135
    # auth: each auth scheme on all http versions on all implementations.
 
136
    tpa_tests, remaining_tests = tests.split_suite_by_condition(
 
137
        remaining_tests, tests.condition_isinstance((
 
138
                TestAuth,
 
139
                )))
 
140
    auth_scheme_scenarios = [
97
141
        ('basic', dict(_auth_server=http_utils.HTTPBasicAuthServer)),
98
142
        ('digest', dict(_auth_server=http_utils.HTTPDigestAuthServer)),
99
143
        ('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:
104
 
        scenario_dict.update(_auth_header='Authorization',
105
 
                             _username_prompt_prefix='',
106
 
                             _password_prompt_prefix='')
107
 
    return scenarios
108
 
 
109
 
 
110
 
def vary_by_http_proxy_auth_scheme():
111
 
    scenarios = [
112
 
        ('proxy-basic', dict(_auth_server=http_utils.ProxyBasicAuthServer)),
113
 
        ('proxy-digest', dict(_auth_server=http_utils.ProxyDigestAuthServer)),
114
 
        ('proxy-basicdigest',
115
 
            dict(_auth_server=http_utils.ProxyBasicAndDigestAuthServer)),
116
 
        ]
117
 
    # Add some attributes common to all scenarios
118
 
    for scenario_id, scenario_dict in scenarios:
119
 
        scenario_dict.update(_auth_header='Proxy-Authorization',
120
 
                             _username_prompt_prefix='Proxy ',
121
 
                             _password_prompt_prefix='Proxy ')
122
 
    return scenarios
123
 
 
124
 
 
125
 
def vary_by_http_activity():
 
144
         dict(_auth_server=http_utils.HTTPBasicAndDigestAuthServer)),
 
145
        ]
 
146
    tpa_scenarios = tests.multiply_scenarios(tp_scenarios,
 
147
                                             auth_scheme_scenarios)
 
148
    tests.multiply_tests(tpa_tests, tpa_scenarios, result)
 
149
 
 
150
    # activity: on all http[s] versions on all implementations
 
151
    tpact_tests, remaining_tests = tests.split_suite_by_condition(
 
152
        remaining_tests, tests.condition_isinstance((
 
153
                TestActivity,
 
154
                )))
126
155
    activity_scenarios = [
127
156
        ('urllib,http', dict(_activity_server=ActivityHTTPServer,
128
 
                            _transport=_urllib.HttpTransport_urllib,)),
 
157
                             _transport=_urllib.HttpTransport_urllib,)),
129
158
        ]
 
159
    if tests.HTTPSServerFeature.available():
 
160
        activity_scenarios.append(
 
161
            ('urllib,https', dict(_activity_server=ActivityHTTPSServer,
 
162
                                  _transport=_urllib.HttpTransport_urllib,)),)
130
163
    if features.pycurl.available():
131
164
        activity_scenarios.append(
132
165
            ('pycurl,http', dict(_activity_server=ActivityHTTPServer,
133
 
                                _transport=PyCurlTransport,)),)
134
 
    if features.HTTPSServerFeature.available():
135
 
        # FIXME: Until we have a better way to handle self-signed certificates
136
 
        # (like allowing them in a test specific authentication.conf for
137
 
        # example), we need some specialized pycurl/urllib transport for tests.
138
 
        # -- vila 2012-01-20
139
 
        from bzrlib.tests import (
140
 
            ssl_certs,
141
 
            )
142
 
        class HTTPS_urllib_transport(_urllib.HttpTransport_urllib):
143
 
 
144
 
            def __init__(self, base, _from_transport=None):
145
 
                super(HTTPS_urllib_transport, self).__init__(
146
 
                    base, _from_transport=_from_transport,
147
 
                    ca_certs=ssl_certs.build_path('ca.crt'))
148
 
 
149
 
        activity_scenarios.append(
150
 
            ('urllib,https', dict(_activity_server=ActivityHTTPSServer,
151
 
                                  _transport=HTTPS_urllib_transport,)),)
152
 
        if features.pycurl.available():
 
166
                                 _transport=PyCurlTransport,)),)
 
167
        if tests.HTTPSServerFeature.available():
 
168
            from bzrlib.tests import (
 
169
                ssl_certs,
 
170
                )
 
171
            # FIXME: Until we have a better way to handle self-signed
 
172
            # certificates (like allowing them in a test specific
 
173
            # authentication.conf for example), we need some specialized pycurl
 
174
            # transport for tests.
153
175
            class HTTPS_pycurl_transport(PyCurlTransport):
154
176
 
155
177
                def __init__(self, base, _from_transport=None):
159
181
 
160
182
            activity_scenarios.append(
161
183
                ('pycurl,https', dict(_activity_server=ActivityHTTPSServer,
162
 
                                    _transport=HTTPS_pycurl_transport,)),)
163
 
    return activity_scenarios
 
184
                                      _transport=HTTPS_pycurl_transport,)),)
 
185
 
 
186
    tpact_scenarios = tests.multiply_scenarios(activity_scenarios,
 
187
                                               protocol_scenarios)
 
188
    tests.multiply_tests(tpact_tests, tpact_scenarios, result)
 
189
 
 
190
    # No parametrization for the remaining tests
 
191
    result.addTests(remaining_tests)
 
192
 
 
193
    return result
164
194
 
165
195
 
166
196
class FakeManager(object):
199
229
        self._sock.bind(('127.0.0.1', 0))
200
230
        self.host, self.port = self._sock.getsockname()
201
231
        self._ready = threading.Event()
202
 
        self._thread = test_server.TestThread(
203
 
            sync_event=self._ready, target=self._accept_read_and_reply)
 
232
        self._thread = test_server.ThreadWithException(
 
233
            event=self._ready, target=self._accept_read_and_reply)
204
234
        self._thread.start()
205
235
        if 'threads' in tests.selftest_debug_flags:
206
236
            sys.stderr.write('Thread started: %s\n' % (self._thread.ident,))
275
305
        self.assertEqual('realm="Thou should not pass"', remainder)
276
306
 
277
307
 
278
 
class TestHTTPRangeParsing(tests.TestCase):
279
 
 
280
 
    def setUp(self):
281
 
        super(TestHTTPRangeParsing, self).setUp()
282
 
        # We focus on range  parsing here and ignore everything else
283
 
        class RequestHandler(http_server.TestingHTTPRequestHandler):
284
 
            def setup(self): pass
285
 
            def handle(self): pass
286
 
            def finish(self): pass
287
 
 
288
 
        self.req_handler = RequestHandler(None, None, None)
289
 
 
290
 
    def assertRanges(self, ranges, header, file_size):
291
 
        self.assertEquals(ranges,
292
 
                          self.req_handler._parse_ranges(header, file_size))
293
 
 
294
 
    def test_simple_range(self):
295
 
        self.assertRanges([(0,2)], 'bytes=0-2', 12)
296
 
 
297
 
    def test_tail(self):
298
 
        self.assertRanges([(8, 11)], 'bytes=-4', 12)
299
 
 
300
 
    def test_tail_bigger_than_file(self):
301
 
        self.assertRanges([(0, 11)], 'bytes=-99', 12)
302
 
 
303
 
    def test_range_without_end(self):
304
 
        self.assertRanges([(4, 11)], 'bytes=4-', 12)
305
 
 
306
 
    def test_invalid_ranges(self):
307
 
        self.assertRanges(None, 'bytes=12-22', 12)
308
 
        self.assertRanges(None, 'bytes=1-3,12-22', 12)
309
 
        self.assertRanges(None, 'bytes=-', 12)
310
 
 
311
 
 
312
308
class TestHTTPServer(tests.TestCase):
313
309
    """Test the HTTP servers implementations."""
314
310
 
384
380
    _transport = property(_get_pycurl_maybe)
385
381
 
386
382
 
 
383
class TestHttpUrls(tests.TestCase):
 
384
 
 
385
    # TODO: This should be moved to authorization tests once they
 
386
    # are written.
 
387
 
 
388
    def test_url_parsing(self):
 
389
        f = FakeManager()
 
390
        url = http.extract_auth('http://example.com', f)
 
391
        self.assertEqual('http://example.com', url)
 
392
        self.assertEqual(0, len(f.credentials))
 
393
        url = http.extract_auth(
 
394
            'http://user:pass@example.com/bzr/bzr.dev', f)
 
395
        self.assertEqual('http://example.com/bzr/bzr.dev', url)
 
396
        self.assertEqual(1, len(f.credentials))
 
397
        self.assertEqual([None, 'example.com', 'user', 'pass'],
 
398
                         f.credentials[0])
 
399
 
 
400
 
387
401
class TestHttpTransportUrls(tests.TestCase):
388
402
    """Test the http urls."""
389
403
 
390
 
    scenarios = vary_by_http_client_implementation()
391
 
 
392
404
    def test_abs_url(self):
393
405
        """Construction of absolute http URLs"""
394
 
        t = self._transport('http://example.com/bzr/bzr.dev/')
 
406
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
395
407
        eq = self.assertEqualDiff
396
 
        eq(t.abspath('.'), 'http://example.com/bzr/bzr.dev')
397
 
        eq(t.abspath('foo/bar'), 'http://example.com/bzr/bzr.dev/foo/bar')
398
 
        eq(t.abspath('.bzr'), 'http://example.com/bzr/bzr.dev/.bzr')
 
408
        eq(t.abspath('.'), 'http://bazaar-vcs.org/bzr/bzr.dev')
 
409
        eq(t.abspath('foo/bar'), 'http://bazaar-vcs.org/bzr/bzr.dev/foo/bar')
 
410
        eq(t.abspath('.bzr'), 'http://bazaar-vcs.org/bzr/bzr.dev/.bzr')
399
411
        eq(t.abspath('.bzr/1//2/./3'),
400
 
           'http://example.com/bzr/bzr.dev/.bzr/1/2/3')
 
412
           'http://bazaar-vcs.org/bzr/bzr.dev/.bzr/1/2/3')
401
413
 
402
414
    def test_invalid_http_urls(self):
403
415
        """Trap invalid construction of urls"""
404
 
        self._transport('http://example.com/bzr/bzr.dev/')
 
416
        t = self._transport('http://bazaar-vcs.org/bzr/bzr.dev/')
405
417
        self.assertRaises(errors.InvalidURL,
406
418
                          self._transport,
407
 
                          'http://http://example.com/bzr/bzr.dev/')
 
419
                          'http://http://bazaar-vcs.org/bzr/bzr.dev/')
408
420
 
409
421
    def test_http_root_urls(self):
410
422
        """Construction of URLs from server root"""
411
 
        t = self._transport('http://example.com/')
 
423
        t = self._transport('http://bzr.ozlabs.org/')
412
424
        eq = self.assertEqualDiff
413
425
        eq(t.abspath('.bzr/tree-version'),
414
 
           'http://example.com/.bzr/tree-version')
 
426
           'http://bzr.ozlabs.org/.bzr/tree-version')
415
427
 
416
428
    def test_http_impl_urls(self):
417
429
        """There are servers which ask for particular clients to connect"""
463
475
class TestHTTPConnections(http_utils.TestCaseWithWebserver):
464
476
    """Test the http connections."""
465
477
 
466
 
    scenarios = multiply_scenarios(
467
 
        vary_by_http_client_implementation(),
468
 
        vary_by_http_protocol_version(),
469
 
        )
470
 
 
471
478
    def setUp(self):
472
 
        super(TestHTTPConnections, self).setUp()
 
479
        http_utils.TestCaseWithWebserver.setUp(self)
473
480
        self.build_tree(['foo/', 'foo/bar'], line_endings='binary',
474
481
                        transport=self.get_transport())
475
482
 
518
525
class TestHttpTransportRegistration(tests.TestCase):
519
526
    """Test registrations of various http implementations"""
520
527
 
521
 
    scenarios = vary_by_http_client_implementation()
522
 
 
523
528
    def test_http_registered(self):
524
 
        t = transport.get_transport_from_url(
525
 
            '%s://foo.com/' % self._url_protocol)
 
529
        t = transport.get_transport('%s://foo.com/' % self._url_protocol)
526
530
        self.assertIsInstance(t, transport.Transport)
527
531
        self.assertIsInstance(t, self._transport)
528
532
 
529
533
 
530
534
class TestPost(tests.TestCase):
531
535
 
532
 
    scenarios = multiply_scenarios(
533
 
        vary_by_http_client_implementation(),
534
 
        vary_by_http_protocol_version(),
535
 
        )
536
 
 
537
536
    def test_post_body_is_received(self):
538
537
        server = RecordingServer(expect_body_tail='end-of-body',
539
538
                                 scheme=self._url_protocol)
540
539
        self.start_server(server)
541
540
        url = server.get_url()
542
541
        # FIXME: needs a cleanup -- vila 20100611
543
 
        http_transport = transport.get_transport_from_url(url)
 
542
        http_transport = transport.get_transport(url)
544
543
        code, response = http_transport._post('abc def end-of-body')
545
544
        self.assertTrue(
546
545
            server.received_bytes.startswith('POST /.bzr/smart HTTP/1.'))
547
546
        self.assertTrue('content-length: 19\r' in server.received_bytes.lower())
548
 
        self.assertTrue('content-type: application/octet-stream\r'
549
 
                        in server.received_bytes.lower())
550
547
        # The transport should not be assuming that the server can accept
551
548
        # chunked encoding the first time it connects, because HTTP/1.1, so we
552
549
        # check for the literal string.
588
585
    Daughter classes are expected to override _req_handler_class
589
586
    """
590
587
 
591
 
    scenarios = multiply_scenarios(
592
 
        vary_by_http_client_implementation(),
593
 
        vary_by_http_protocol_version(),
594
 
        )
595
 
 
596
588
    # Provide a useful default
597
589
    _req_handler_class = http_server.TestingHTTPRequestHandler
598
590
 
656
648
 
657
649
    _req_handler_class = BadStatusRequestHandler
658
650
 
659
 
    def setUp(self):
660
 
        super(TestBadStatusServer, self).setUp()
661
 
        # See https://bugs.launchpad.net/bzr/+bug/1451448 for details.
662
 
        # TD;LR: Running both a TCP client and server in the same process and
663
 
        # thread uncovers a race in python. The fix is to run the server in a
664
 
        # different process. Trying to fix yet another race here is not worth
665
 
        # the effort. -- vila 2015-09-06
666
 
        if 'HTTP/1.0' in self.id():
667
 
            raise tests.TestSkipped(
668
 
                'Client/Server in the same process and thread can hang')
669
 
 
670
651
    def test_http_has(self):
671
652
        t = self.get_readonly_transport()
672
 
        self.assertRaises((errors.ConnectionError, errors.ConnectionReset,
673
 
                           errors.InvalidHttpResponse),
674
 
                          t.has, 'foo/bar')
 
653
        self.assertRaises(errors.InvalidHttpResponse, t.has, 'foo/bar')
675
654
 
676
655
    def test_http_get(self):
677
656
        t = self.get_readonly_transport()
678
 
        self.assertRaises((errors.ConnectionError, errors.ConnectionReset,
679
 
                           errors.InvalidHttpResponse),
680
 
                          t.get, 'foo/bar')
 
657
        self.assertRaises(errors.InvalidHttpResponse, t.get, 'foo/bar')
681
658
 
682
659
 
683
660
class InvalidStatusRequestHandler(http_server.TestingHTTPRequestHandler):
864
841
        t = self.get_readonly_transport()
865
842
        # force transport to issue multiple requests
866
843
        t._get_max_size = 2
867
 
        list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
 
844
        l = list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
868
845
        # The server should have issued 3 requests
869
846
        self.assertEqual(3, server.GET_request_nb)
870
847
        self.assertEqual('0123456789', t.get_bytes('a'))
947
924
    def get_multiple_ranges(self, file, file_size, ranges):
948
925
        self.send_response(206)
949
926
        self.send_header('Accept-Ranges', 'bytes')
950
 
        # XXX: this is strange; the 'random' name below seems undefined and
951
 
        # yet the tests pass -- mbp 2010-10-11 bug 658773
952
927
        boundary = "%d" % random.randint(0,0x7FFFFFFF)
953
928
        self.send_header("Content-Type",
954
929
                         "multipart/byteranges; boundary=%s" % boundary)
1016
991
                return
1017
992
            self.send_range_content(file, start, end - start + 1)
1018
993
            cur += 1
1019
 
        # Final boundary
 
994
        # No final boundary
1020
995
        self.wfile.write(boundary_line)
1021
996
 
1022
997
 
1051
1026
        # that mode
1052
1027
        self.assertEqual('single', t._range_hint)
1053
1028
 
1054
 
 
1055
 
class TruncatedBeforeBoundaryRequestHandler(
1056
 
    http_server.TestingHTTPRequestHandler):
1057
 
    """Truncation before a boundary, like in bug 198646"""
1058
 
 
1059
 
    _truncated_ranges = 1
1060
 
 
1061
 
    def get_multiple_ranges(self, file, file_size, ranges):
1062
 
        self.send_response(206)
1063
 
        self.send_header('Accept-Ranges', 'bytes')
1064
 
        boundary = 'tagada'
1065
 
        self.send_header('Content-Type',
1066
 
                         'multipart/byteranges; boundary=%s' % boundary)
1067
 
        boundary_line = '--%s\r\n' % boundary
1068
 
        # Calculate the Content-Length
1069
 
        content_length = 0
1070
 
        for (start, end) in ranges:
1071
 
            content_length += len(boundary_line)
1072
 
            content_length += self._header_line_length(
1073
 
                'Content-type', 'application/octet-stream')
1074
 
            content_length += self._header_line_length(
1075
 
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
1076
 
            content_length += len('\r\n') # end headers
1077
 
            content_length += end - start # + 1
1078
 
        content_length += len(boundary_line)
1079
 
        self.send_header('Content-length', content_length)
1080
 
        self.end_headers()
1081
 
 
1082
 
        # Send the multipart body
1083
 
        cur = 0
1084
 
        for (start, end) in ranges:
1085
 
            if cur + self._truncated_ranges >= len(ranges):
1086
 
                # Abruptly ends the response and close the connection
1087
 
                self.close_connection = 1
1088
 
                return
1089
 
            self.wfile.write(boundary_line)
1090
 
            self.send_header('Content-type', 'application/octet-stream')
1091
 
            self.send_header('Content-Range', 'bytes %d-%d/%d'
1092
 
                             % (start, end, file_size))
1093
 
            self.end_headers()
1094
 
            self.send_range_content(file, start, end - start + 1)
1095
 
            cur += 1
1096
 
        # Final boundary
1097
 
        self.wfile.write(boundary_line)
1098
 
 
1099
 
 
1100
 
class TestTruncatedBeforeBoundary(TestSpecificRequestHandler):
1101
 
    """Tests the case of bug 198646, disconnecting before a boundary."""
1102
 
 
1103
 
    _req_handler_class = TruncatedBeforeBoundaryRequestHandler
1104
 
 
1105
 
    def setUp(self):
1106
 
        super(TestTruncatedBeforeBoundary, self).setUp()
1107
 
        self.build_tree_contents([('a', '0123456789')],)
1108
 
 
1109
 
    def test_readv_with_short_reads(self):
1110
 
        server = self.get_readonly_server()
1111
 
        t = self.get_readonly_transport()
1112
 
        # Force separate ranges for each offset
1113
 
        t._bytes_to_read_before_seek = 0
1114
 
        ireadv = iter(t.readv('a', ((0, 1), (2, 1), (4, 2), (9, 1))))
1115
 
        self.assertEqual((0, '0'), ireadv.next())
1116
 
        self.assertEqual((2, '2'), ireadv.next())
1117
 
        self.assertEqual((4, '45'), ireadv.next())
1118
 
        self.assertEqual((9, '9'), ireadv.next())
1119
 
 
1120
 
 
1121
1029
class LimitedRangeRequestHandler(http_server.TestingHTTPRequestHandler):
1122
1030
    """Errors out when range specifiers exceed the limit"""
1123
1031
 
1147
1055
class TestLimitedRangeRequestServer(http_utils.TestCaseWithWebserver):
1148
1056
    """Tests readv requests against a server erroring out on too much ranges."""
1149
1057
 
1150
 
    scenarios = multiply_scenarios(
1151
 
        vary_by_http_client_implementation(),
1152
 
        vary_by_http_protocol_version(),
1153
 
        )
1154
 
 
1155
1058
    # Requests with more range specifiers will error out
1156
1059
    range_limit = 3
1157
1060
 
1160
1063
                                      protocol_version=self._protocol_version)
1161
1064
 
1162
1065
    def setUp(self):
1163
 
        super(TestLimitedRangeRequestServer, self).setUp()
 
1066
        http_utils.TestCaseWithWebserver.setUp(self)
1164
1067
        # We need to manipulate ranges that correspond to real chunks in the
1165
1068
        # response, so we build a content appropriately.
1166
1069
        filler = ''.join(['abcdefghij' for x in range(102)])
1192
1095
    Only the urllib implementation is tested here.
1193
1096
    """
1194
1097
 
 
1098
    def setUp(self):
 
1099
        tests.TestCase.setUp(self)
 
1100
        self._old_env = {}
 
1101
        self.addCleanup(self._restore_env)
 
1102
 
 
1103
    def _install_env(self, env):
 
1104
        for name, value in env.iteritems():
 
1105
            self._old_env[name] = osutils.set_or_unset_env(name, value)
 
1106
 
 
1107
    def _restore_env(self):
 
1108
        for name, value in self._old_env.iteritems():
 
1109
            osutils.set_or_unset_env(name, value)
 
1110
 
1195
1111
    def _proxied_request(self):
1196
1112
        handler = _urllib2_wrappers.ProxyHandler()
1197
 
        request = _urllib2_wrappers.Request('GET', 'http://baz/buzzle')
 
1113
        request = _urllib2_wrappers.Request('GET','http://baz/buzzle')
1198
1114
        handler.set_proxy(request, 'http')
1199
1115
        return request
1200
1116
 
1201
 
    def assertEvaluateProxyBypass(self, expected, host, no_proxy):
1202
 
        handler = _urllib2_wrappers.ProxyHandler()
1203
 
        self.assertEquals(expected,
1204
 
                          handler.evaluate_proxy_bypass(host, no_proxy))
1205
 
 
1206
1117
    def test_empty_user(self):
1207
 
        self.overrideEnv('http_proxy', 'http://bar.com')
1208
 
        request = self._proxied_request()
1209
 
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1210
 
 
1211
 
    def test_user_with_at(self):
1212
 
        self.overrideEnv('http_proxy',
1213
 
                         'http://username@domain:password@proxy_host:1234')
 
1118
        self._install_env({'http_proxy': 'http://bar.com'})
1214
1119
        request = self._proxied_request()
1215
1120
        self.assertFalse(request.headers.has_key('Proxy-authorization'))
1216
1121
 
1217
1122
    def test_invalid_proxy(self):
1218
1123
        """A proxy env variable without scheme"""
1219
 
        self.overrideEnv('http_proxy', 'host:1234')
 
1124
        self._install_env({'http_proxy': 'host:1234'})
1220
1125
        self.assertRaises(errors.InvalidURL, self._proxied_request)
1221
1126
 
1222
 
    def test_evaluate_proxy_bypass_true(self):
1223
 
        """The host is not proxied"""
1224
 
        self.assertEvaluateProxyBypass(True, 'example.com', 'example.com')
1225
 
        self.assertEvaluateProxyBypass(True, 'bzr.example.com', '*example.com')
1226
 
 
1227
 
    def test_evaluate_proxy_bypass_false(self):
1228
 
        """The host is proxied"""
1229
 
        self.assertEvaluateProxyBypass(False, 'bzr.example.com', None)
1230
 
 
1231
 
    def test_evaluate_proxy_bypass_unknown(self):
1232
 
        """The host is not explicitly proxied"""
1233
 
        self.assertEvaluateProxyBypass(None, 'example.com', 'not.example.com')
1234
 
        self.assertEvaluateProxyBypass(None, 'bzr.example.com', 'example.com')
1235
 
 
1236
 
    def test_evaluate_proxy_bypass_empty_entries(self):
1237
 
        """Ignore empty entries"""
1238
 
        self.assertEvaluateProxyBypass(None, 'example.com', '')
1239
 
        self.assertEvaluateProxyBypass(None, 'example.com', ',')
1240
 
        self.assertEvaluateProxyBypass(None, 'example.com', 'foo,,bar')
1241
 
 
1242
1127
 
1243
1128
class TestProxyHttpServer(http_utils.TestCaseWithTwoWebservers):
1244
1129
    """Tests proxy server.
1249
1134
    to the file names).
1250
1135
    """
1251
1136
 
1252
 
    scenarios = multiply_scenarios(
1253
 
        vary_by_http_client_implementation(),
1254
 
        vary_by_http_protocol_version(),
1255
 
        )
1256
 
 
1257
1137
    # FIXME: We don't have an https server available, so we don't
1258
1138
    # test https connections. --vila toolongago
1259
1139
 
1273
1153
            self.no_proxy_host = self.server_host_port
1274
1154
        # The secondary server is the proxy
1275
1155
        self.proxy_url = self.get_secondary_url()
 
1156
        self._old_env = {}
1276
1157
 
1277
1158
    def _testing_pycurl(self):
1278
1159
        # TODO: This is duplicated for lots of the classes in this file
1279
1160
        return (features.pycurl.available()
1280
1161
                and self._transport == PyCurlTransport)
1281
1162
 
1282
 
    def assertProxied(self):
1283
 
        t = self.get_readonly_transport()
1284
 
        self.assertEqual('proxied contents of foo\n', t.get('foo').read())
1285
 
 
1286
 
    def assertNotProxied(self):
1287
 
        t = self.get_readonly_transport()
1288
 
        self.assertEqual('contents of foo\n', t.get('foo').read())
 
1163
    def _install_env(self, env):
 
1164
        for name, value in env.iteritems():
 
1165
            self._old_env[name] = osutils.set_or_unset_env(name, value)
 
1166
 
 
1167
    def _restore_env(self):
 
1168
        for name, value in self._old_env.iteritems():
 
1169
            osutils.set_or_unset_env(name, value)
 
1170
 
 
1171
    def proxied_in_env(self, env):
 
1172
        self._install_env(env)
 
1173
        t = self.get_readonly_transport()
 
1174
        try:
 
1175
            self.assertEqual('proxied contents of foo\n', t.get('foo').read())
 
1176
        finally:
 
1177
            self._restore_env()
 
1178
 
 
1179
    def not_proxied_in_env(self, env):
 
1180
        self._install_env(env)
 
1181
        t = self.get_readonly_transport()
 
1182
        try:
 
1183
            self.assertEqual('contents of foo\n', t.get('foo').read())
 
1184
        finally:
 
1185
            self._restore_env()
1289
1186
 
1290
1187
    def test_http_proxy(self):
1291
 
        self.overrideEnv('http_proxy', self.proxy_url)
1292
 
        self.assertProxied()
 
1188
        self.proxied_in_env({'http_proxy': self.proxy_url})
1293
1189
 
1294
1190
    def test_HTTP_PROXY(self):
1295
1191
        if self._testing_pycurl():
1298
1194
            # about. Should we ?)
1299
1195
            raise tests.TestNotApplicable(
1300
1196
                'pycurl does not check HTTP_PROXY for security reasons')
1301
 
        self.overrideEnv('HTTP_PROXY', self.proxy_url)
1302
 
        self.assertProxied()
 
1197
        self.proxied_in_env({'HTTP_PROXY': self.proxy_url})
1303
1198
 
1304
1199
    def test_all_proxy(self):
1305
 
        self.overrideEnv('all_proxy', self.proxy_url)
1306
 
        self.assertProxied()
 
1200
        self.proxied_in_env({'all_proxy': self.proxy_url})
1307
1201
 
1308
1202
    def test_ALL_PROXY(self):
1309
 
        self.overrideEnv('ALL_PROXY', self.proxy_url)
1310
 
        self.assertProxied()
 
1203
        self.proxied_in_env({'ALL_PROXY': self.proxy_url})
1311
1204
 
1312
1205
    def test_http_proxy_with_no_proxy(self):
1313
 
        self.overrideEnv('no_proxy', self.no_proxy_host)
1314
 
        self.overrideEnv('http_proxy', self.proxy_url)
1315
 
        self.assertNotProxied()
 
1206
        self.not_proxied_in_env({'http_proxy': self.proxy_url,
 
1207
                                 'no_proxy': self.no_proxy_host})
1316
1208
 
1317
1209
    def test_HTTP_PROXY_with_NO_PROXY(self):
1318
1210
        if self._testing_pycurl():
1319
1211
            raise tests.TestNotApplicable(
1320
1212
                'pycurl does not check HTTP_PROXY for security reasons')
1321
 
        self.overrideEnv('NO_PROXY', self.no_proxy_host)
1322
 
        self.overrideEnv('HTTP_PROXY', self.proxy_url)
1323
 
        self.assertNotProxied()
 
1213
        self.not_proxied_in_env({'HTTP_PROXY': self.proxy_url,
 
1214
                                 'NO_PROXY': self.no_proxy_host})
1324
1215
 
1325
1216
    def test_all_proxy_with_no_proxy(self):
1326
 
        self.overrideEnv('no_proxy', self.no_proxy_host)
1327
 
        self.overrideEnv('all_proxy', self.proxy_url)
1328
 
        self.assertNotProxied()
 
1217
        self.not_proxied_in_env({'all_proxy': self.proxy_url,
 
1218
                                 'no_proxy': self.no_proxy_host})
1329
1219
 
1330
1220
    def test_ALL_PROXY_with_NO_PROXY(self):
1331
 
        self.overrideEnv('NO_PROXY', self.no_proxy_host)
1332
 
        self.overrideEnv('ALL_PROXY', self.proxy_url)
1333
 
        self.assertNotProxied()
 
1221
        self.not_proxied_in_env({'ALL_PROXY': self.proxy_url,
 
1222
                                 'NO_PROXY': self.no_proxy_host})
1334
1223
 
1335
1224
    def test_http_proxy_without_scheme(self):
1336
 
        self.overrideEnv('http_proxy', self.server_host_port)
1337
1225
        if self._testing_pycurl():
1338
1226
            # pycurl *ignores* invalid proxy env variables. If that ever change
1339
1227
            # in the future, this test will fail indicating that pycurl do not
1340
1228
            # ignore anymore such variables.
1341
 
            self.assertNotProxied()
 
1229
            self.not_proxied_in_env({'http_proxy': self.server_host_port})
1342
1230
        else:
1343
 
            self.assertRaises(errors.InvalidURL, self.assertProxied)
 
1231
            self.assertRaises(errors.InvalidURL,
 
1232
                              self.proxied_in_env,
 
1233
                              {'http_proxy': self.server_host_port})
1344
1234
 
1345
1235
 
1346
1236
class TestRanges(http_utils.TestCaseWithWebserver):
1347
1237
    """Test the Range header in GET methods."""
1348
1238
 
1349
 
    scenarios = multiply_scenarios(
1350
 
        vary_by_http_client_implementation(),
1351
 
        vary_by_http_protocol_version(),
1352
 
        )
1353
 
 
1354
1239
    def setUp(self):
1355
 
        super(TestRanges, self).setUp()
 
1240
        http_utils.TestCaseWithWebserver.setUp(self)
1356
1241
        self.build_tree_contents([('a', '0123456789')],)
1357
1242
 
1358
1243
    def create_transport_readonly_server(self):
1396
1281
class TestHTTPRedirections(http_utils.TestCaseWithRedirectedWebserver):
1397
1282
    """Test redirection between http servers."""
1398
1283
 
1399
 
    scenarios = multiply_scenarios(
1400
 
        vary_by_http_client_implementation(),
1401
 
        vary_by_http_protocol_version(),
1402
 
        )
1403
 
 
1404
1284
    def setUp(self):
1405
1285
        super(TestHTTPRedirections, self).setUp()
1406
1286
        self.build_tree_contents([('a', '0123456789'),
1469
1349
    -- vila 20070212
1470
1350
    """
1471
1351
 
1472
 
    scenarios = multiply_scenarios(
1473
 
        vary_by_http_client_implementation(),
1474
 
        vary_by_http_protocol_version(),
1475
 
        )
1476
 
 
1477
1352
    def setUp(self):
1478
1353
        if (features.pycurl.available()
1479
1354
            and self._transport == PyCurlTransport):
1524
1399
class TestDoCatchRedirections(http_utils.TestCaseWithRedirectedWebserver):
1525
1400
    """Test transport.do_catching_redirections."""
1526
1401
 
1527
 
    scenarios = multiply_scenarios(
1528
 
        vary_by_http_client_implementation(),
1529
 
        vary_by_http_protocol_version(),
1530
 
        )
1531
 
 
1532
1402
    def setUp(self):
1533
1403
        super(TestDoCatchRedirections, self).setUp()
1534
1404
        self.build_tree_contents([('a', '0123456789'),],)
1573
1443
                          self.get_a, self.old_transport, redirected)
1574
1444
 
1575
1445
 
1576
 
def _setup_authentication_config(**kwargs):
1577
 
    conf = config.AuthenticationConfig()
1578
 
    conf._get_config().update({'httptest': kwargs})
1579
 
    conf._save()
1580
 
 
1581
 
 
1582
 
class TestUrllib2AuthHandler(tests.TestCaseWithTransport):
1583
 
    """Unit tests for glue by which urllib2 asks us for authentication"""
1584
 
 
1585
 
    def test_get_user_password_without_port(self):
1586
 
        """We cope if urllib2 doesn't tell us the port.
1587
 
 
1588
 
        See https://bugs.launchpad.net/bzr/+bug/654684
1589
 
        """
1590
 
        user = 'joe'
1591
 
        password = 'foo'
1592
 
        _setup_authentication_config(scheme='http', host='localhost',
1593
 
                                     user=user, password=password)
1594
 
        handler = _urllib2_wrappers.HTTPAuthHandler()
1595
 
        got_pass = handler.get_user_password(dict(
1596
 
            user='joe',
1597
 
            protocol='http',
1598
 
            host='localhost',
1599
 
            path='/',
1600
 
            realm='Realm',
1601
 
            ))
1602
 
        self.assertEquals((user, password), got_pass)
1603
 
 
1604
 
 
1605
1446
class TestAuth(http_utils.TestCaseWithWebserver):
1606
1447
    """Test authentication scheme"""
1607
1448
 
1608
 
    scenarios = multiply_scenarios(
1609
 
        vary_by_http_client_implementation(),
1610
 
        vary_by_http_protocol_version(),
1611
 
        vary_by_http_auth_scheme(),
1612
 
        )
 
1449
    _auth_header = 'Authorization'
 
1450
    _password_prompt_prefix = ''
 
1451
    _username_prompt_prefix = ''
 
1452
    # Set by load_tests
 
1453
    _auth_server = None
1613
1454
 
1614
1455
    def setUp(self):
1615
1456
        super(TestAuth, self).setUp()
1639
1480
        return url
1640
1481
 
1641
1482
    def get_user_transport(self, user, password):
1642
 
        t = transport.get_transport_from_url(
1643
 
            self.get_user_url(user, password))
 
1483
        t = transport.get_transport(self.get_user_url(user, password))
1644
1484
        return t
1645
1485
 
1646
1486
    def test_no_user(self):
1758
1598
        ui.ui_factory = tests.TestUIFactory(stdin=stdin_content,
1759
1599
                                            stderr=tests.StringIOWrapper())
1760
1600
        # Create a minimal config file with the right password
1761
 
        _setup_authentication_config(scheme='http', port=self.server.port,
1762
 
                                     user=user, password=password)
 
1601
        conf = config.AuthenticationConfig()
 
1602
        conf._get_config().update(
 
1603
            {'httptest': {'scheme': 'http', 'port': self.server.port,
 
1604
                          'user': user, 'password': password}})
 
1605
        conf._save()
1763
1606
        # Issue a request to the server to connect
1764
1607
        self.assertEqual('contents of a\n',t.get('a').read())
1765
1608
        # stdin should have  been left untouched
1767
1610
        # Only one 'Authentication Required' error should occur
1768
1611
        self.assertEqual(1, self.server.auth_required_errors)
1769
1612
 
 
1613
    def test_user_from_auth_conf(self):
 
1614
        if self._testing_pycurl():
 
1615
            raise tests.TestNotApplicable(
 
1616
                'pycurl does not support authentication.conf')
 
1617
        user = 'joe'
 
1618
        password = 'foo'
 
1619
        self.server.add_user(user, password)
 
1620
        # Create a minimal config file with the right password
 
1621
        conf = config.AuthenticationConfig()
 
1622
        conf._get_config().update(
 
1623
            {'httptest': {'scheme': 'http', 'port': self.server.port,
 
1624
                          'user': user, 'password': password}})
 
1625
        conf._save()
 
1626
        t = self.get_user_transport(None, None)
 
1627
        # Issue a request to the server to connect
 
1628
        self.assertEqual('contents of a\n', t.get('a').read())
 
1629
        # Only one 'Authentication Required' error should occur
 
1630
        self.assertEqual(1, self.server.auth_required_errors)
 
1631
 
1770
1632
    def test_changing_nonce(self):
1771
1633
        if self._auth_server not in (http_utils.HTTPDigestAuthServer,
1772
1634
                                     http_utils.ProxyDigestAuthServer):
1773
1635
            raise tests.TestNotApplicable('HTTP/proxy auth digest only test')
1774
1636
        if self._testing_pycurl():
1775
 
            self.knownFailure(
 
1637
            raise tests.KnownFailure(
1776
1638
                'pycurl does not handle a nonce change')
1777
1639
        self.server.add_user('joe', 'foo')
1778
1640
        t = self.get_user_transport('joe', 'foo')
1788
1650
        # initial 'who are you' and a second 'who are you' with the new nonce)
1789
1651
        self.assertEqual(2, self.server.auth_required_errors)
1790
1652
 
1791
 
    def test_user_from_auth_conf(self):
1792
 
        if self._testing_pycurl():
1793
 
            raise tests.TestNotApplicable(
1794
 
                'pycurl does not support authentication.conf')
1795
 
        user = 'joe'
1796
 
        password = 'foo'
1797
 
        self.server.add_user(user, password)
1798
 
        _setup_authentication_config(scheme='http', port=self.server.port,
1799
 
                                     user=user, password=password)
1800
 
        t = self.get_user_transport(None, None)
1801
 
        # Issue a request to the server to connect
1802
 
        self.assertEqual('contents of a\n', t.get('a').read())
1803
 
        # Only one 'Authentication Required' error should occur
1804
 
        self.assertEqual(1, self.server.auth_required_errors)
1805
 
 
1806
 
    def test_no_credential_leaks_in_log(self):
1807
 
        self.overrideAttr(debug, 'debug_flags', set(['http']))
1808
 
        user = 'joe'
1809
 
        password = 'very-sensitive-password'
1810
 
        self.server.add_user(user, password)
1811
 
        t = self.get_user_transport(user, password)
1812
 
        # Capture the debug calls to mutter
1813
 
        self.mutters = []
1814
 
        def mutter(*args):
1815
 
            lines = args[0] % args[1:]
1816
 
            # Some calls output multiple lines, just split them now since we
1817
 
            # care about a single one later.
1818
 
            self.mutters.extend(lines.splitlines())
1819
 
        self.overrideAttr(trace, 'mutter', mutter)
1820
 
        # Issue a request to the server to connect
1821
 
        self.assertEqual(True, t.has('a'))
1822
 
        # Only one 'Authentication Required' error should occur
1823
 
        self.assertEqual(1, self.server.auth_required_errors)
1824
 
        # Since the authentification succeeded, there should be a corresponding
1825
 
        # debug line
1826
 
        sent_auth_headers = [line for line in self.mutters
1827
 
                             if line.startswith('> %s' % (self._auth_header,))]
1828
 
        self.assertLength(1, sent_auth_headers)
1829
 
        self.assertStartsWith(sent_auth_headers[0],
1830
 
                              '> %s: <masked>' % (self._auth_header,))
1831
1653
 
1832
1654
 
1833
1655
class TestProxyAuth(TestAuth):
1834
 
    """Test proxy authentication schemes.
1835
 
 
1836
 
    This inherits from TestAuth to tweak the setUp and filter some failing
1837
 
    tests.
1838
 
    """
1839
 
 
1840
 
    scenarios = multiply_scenarios(
1841
 
        vary_by_http_client_implementation(),
1842
 
        vary_by_http_protocol_version(),
1843
 
        vary_by_http_proxy_auth_scheme(),
1844
 
        )
 
1656
    """Test proxy authentication schemes."""
 
1657
 
 
1658
    _auth_header = 'Proxy-authorization'
 
1659
    _password_prompt_prefix = 'Proxy '
 
1660
    _username_prompt_prefix = 'Proxy '
1845
1661
 
1846
1662
    def setUp(self):
1847
1663
        super(TestProxyAuth, self).setUp()
 
1664
        self._old_env = {}
 
1665
        self.addCleanup(self._restore_env)
1848
1666
        # Override the contents to avoid false positives
1849
1667
        self.build_tree_contents([('a', 'not proxied contents of a\n'),
1850
1668
                                  ('b', 'not proxied contents of b\n'),
1853
1671
                                  ])
1854
1672
 
1855
1673
    def get_user_transport(self, user, password):
1856
 
        self.overrideEnv('all_proxy', self.get_user_url(user, password))
 
1674
        self._install_env({'all_proxy': self.get_user_url(user, password)})
1857
1675
        return TestAuth.get_user_transport(self, user, password)
1858
1676
 
 
1677
    def _install_env(self, env):
 
1678
        for name, value in env.iteritems():
 
1679
            self._old_env[name] = osutils.set_or_unset_env(name, value)
 
1680
 
 
1681
    def _restore_env(self):
 
1682
        for name, value in self._old_env.iteritems():
 
1683
            osutils.set_or_unset_env(name, value)
 
1684
 
1859
1685
    def test_empty_pass(self):
1860
1686
        if self._testing_pycurl():
1861
1687
            import pycurl
1862
1688
            if pycurl.version_info()[1] < '7.16.0':
1863
 
                self.knownFailure(
 
1689
                raise tests.KnownFailure(
1864
1690
                    'pycurl < 7.16.0 does not handle empty proxy passwords')
1865
1691
        super(TestProxyAuth, self).test_empty_pass()
1866
1692
 
1890
1716
 
1891
1717
class SmartHTTPTunnellingTest(tests.TestCaseWithTransport):
1892
1718
 
1893
 
    scenarios = multiply_scenarios(
1894
 
        vary_by_http_client_implementation(),
1895
 
        vary_by_http_protocol_version(),
1896
 
        )
1897
 
 
1898
1719
    def setUp(self):
1899
1720
        super(SmartHTTPTunnellingTest, self).setUp()
1900
1721
        # We use the VFS layer as part of HTTP tunnelling tests.
1901
 
        self.overrideEnv('BZR_NO_SMART_VFS', None)
 
1722
        self._captureVar('BZR_NO_SMART_VFS', None)
1902
1723
        self.transport_readonly_server = http_utils.HTTPServerWithSmarts
1903
1724
        self.http_server = self.get_readonly_server()
1904
1725
 
1908
1729
        server._url_protocol = self._url_protocol
1909
1730
        return server
1910
1731
 
1911
 
    def test_open_controldir(self):
 
1732
    def test_open_bzrdir(self):
1912
1733
        branch = self.make_branch('relpath')
1913
1734
        url = self.http_server.get_url() + 'relpath'
1914
 
        bd = controldir.ControlDir.open(url)
 
1735
        bd = bzrdir.BzrDir.open(url)
1915
1736
        self.addCleanup(bd.transport.disconnect)
1916
1737
        self.assertIsInstance(bd, _mod_remote.RemoteBzrDir)
1917
1738
 
1920
1741
        # The 'readv' command in the smart protocol both sends and receives
1921
1742
        # bulk data, so we use that.
1922
1743
        self.build_tree(['data-file'])
1923
 
        http_transport = transport.get_transport_from_url(
1924
 
            self.http_server.get_url())
 
1744
        http_transport = transport.get_transport(self.http_server.get_url())
1925
1745
        medium = http_transport.get_smart_medium()
1926
1746
        # Since we provide the medium, the url below will be mostly ignored
1927
1747
        # during the test, as long as the path is '/'.
1935
1755
        post_body = 'hello\n'
1936
1756
        expected_reply_body = 'ok\x012\n'
1937
1757
 
1938
 
        http_transport = transport.get_transport_from_url(
1939
 
            self.http_server.get_url())
 
1758
        http_transport = transport.get_transport(self.http_server.get_url())
1940
1759
        medium = http_transport.get_smart_medium()
1941
1760
        response = medium.send_http_smart_request(post_body)
1942
1761
        reply_body = response.read()
1991
1810
 
1992
1811
class Test_redirected_to(tests.TestCase):
1993
1812
 
1994
 
    scenarios = vary_by_http_client_implementation()
1995
 
 
1996
1813
    def test_redirected_to_subdir(self):
1997
1814
        t = self._transport('http://www.example.com/foo')
1998
1815
        r = t._redirected_to('http://www.example.com/foo',
2000
1817
        self.assertIsInstance(r, type(t))
2001
1818
        # Both transports share the some connection
2002
1819
        self.assertEqual(t._get_connection(), r._get_connection())
2003
 
        self.assertEquals('http://www.example.com/foo/subdir/', r.base)
2004
1820
 
2005
1821
    def test_redirected_to_self_with_slash(self):
2006
1822
        t = self._transport('http://www.example.com/foo')
2017
1833
        r = t._redirected_to('http://www.example.com/foo',
2018
1834
                             'http://foo.example.com/foo/subdir')
2019
1835
        self.assertIsInstance(r, type(t))
2020
 
        self.assertEquals('http://foo.example.com/foo/subdir/',
2021
 
            r.external_url())
2022
1836
 
2023
1837
    def test_redirected_to_same_host_sibling_protocol(self):
2024
1838
        t = self._transport('http://www.example.com/foo')
2025
1839
        r = t._redirected_to('http://www.example.com/foo',
2026
1840
                             'https://www.example.com/foo')
2027
1841
        self.assertIsInstance(r, type(t))
2028
 
        self.assertEquals('https://www.example.com/foo/',
2029
 
            r.external_url())
2030
1842
 
2031
1843
    def test_redirected_to_same_host_different_protocol(self):
2032
1844
        t = self._transport('http://www.example.com/foo')
2033
1845
        r = t._redirected_to('http://www.example.com/foo',
2034
1846
                             'ftp://www.example.com/foo')
2035
1847
        self.assertNotEquals(type(r), type(t))
2036
 
        self.assertEquals('ftp://www.example.com/foo/', r.external_url())
2037
 
 
2038
 
    def test_redirected_to_same_host_specific_implementation(self):
2039
 
        t = self._transport('http://www.example.com/foo')
2040
 
        r = t._redirected_to('http://www.example.com/foo',
2041
 
                             'https+urllib://www.example.com/foo')
2042
 
        self.assertEquals('https://www.example.com/foo/', r.external_url())
2043
1848
 
2044
1849
    def test_redirected_to_different_host_same_user(self):
2045
1850
        t = self._transport('http://joe@www.example.com/foo')
2046
1851
        r = t._redirected_to('http://www.example.com/foo',
2047
1852
                             'https://foo.example.com/foo')
2048
1853
        self.assertIsInstance(r, type(t))
2049
 
        self.assertEqual(t._parsed_url.user, r._parsed_url.user)
2050
 
        self.assertEquals('https://joe@foo.example.com/foo/', r.external_url())
 
1854
        self.assertEqual(t._user, r._user)
2051
1855
 
2052
1856
 
2053
1857
class PredefinedRequestHandler(http_server.TestingHTTPRequestHandler):
2106
1910
    pass
2107
1911
 
2108
1912
 
2109
 
if features.HTTPSServerFeature.available():
 
1913
if tests.HTTPSServerFeature.available():
2110
1914
    from bzrlib.tests import https_server
2111
1915
    class ActivityHTTPSServer(ActivityServerMixin, https_server.HTTPSServer):
2112
1916
        pass
2120
1924
    """
2121
1925
 
2122
1926
    def setUp(self):
 
1927
        tests.TestCase.setUp(self)
2123
1928
        self.server = self._activity_server(self._protocol_version)
2124
1929
        self.server.start_server()
2125
 
        self.addCleanup(self.server.stop_server)
2126
 
        _activities = {} # Don't close over self and create a cycle
 
1930
        self.activities = {}
2127
1931
        def report_activity(t, bytes, direction):
2128
 
            count = _activities.get(direction, 0)
 
1932
            count = self.activities.get(direction, 0)
2129
1933
            count += bytes
2130
 
            _activities[direction] = count
2131
 
        self.activities = _activities
 
1934
            self.activities[direction] = count
 
1935
 
2132
1936
        # We override at class level because constructors may propagate the
2133
1937
        # bound method and render instance overriding ineffective (an
2134
1938
        # alternative would be to define a specific ui factory instead...)
2135
1939
        self.overrideAttr(self._transport, '_report_activity', report_activity)
 
1940
        self.addCleanup(self.server.stop_server)
2136
1941
 
2137
1942
    def get_transport(self):
2138
1943
        t = self._transport(self.server.get_url())
2256
2061
 
2257
2062
class TestActivity(tests.TestCase, TestActivityMixin):
2258
2063
 
2259
 
    scenarios = multiply_scenarios(
2260
 
        vary_by_http_activity(),
2261
 
        vary_by_http_protocol_version(),
2262
 
        )
2263
 
 
2264
2064
    def setUp(self):
2265
 
        super(TestActivity, self).setUp()
2266
2065
        TestActivityMixin.setUp(self)
2267
2066
 
2268
2067
 
2277
2076
    _protocol_version = 'HTTP/1.1'
2278
2077
 
2279
2078
    def setUp(self):
2280
 
        super(TestNoReportActivity, self).setUp()
2281
2079
        self._transport =_urllib.HttpTransport_urllib
2282
2080
        TestActivityMixin.setUp(self)
2283
2081
 
2289
2087
class TestAuthOnRedirected(http_utils.TestCaseWithRedirectedWebserver):
2290
2088
    """Test authentication on the redirected http server."""
2291
2089
 
2292
 
    scenarios = vary_by_http_protocol_version()
2293
 
 
2294
2090
    _auth_header = 'Authorization'
2295
2091
    _password_prompt_prefix = ''
2296
2092
    _username_prompt_prefix = ''
2359
2155
        # stdout should be empty, stderr will contains the prompts
2360
2156
        self.assertEqual('', stdout.getvalue())
2361
2157
 
 
2158