/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to breezy/tests/test_http.py

  • Committer: Jelmer Vernooij
  • Date: 2017-07-23 22:06:41 UTC
  • mfrom: (6738 trunk)
  • mto: This revision was merged to the branch mainline in revision 6739.
  • Revision ID: jelmer@jelmer.uk-20170723220641-69eczax9bmv8d6kk
Merge trunk, address review comments.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
# TODO: Should be renamed to breezy.transport.http.tests?
24
24
# TODO: What about renaming to breezy.tests.transport.http ?
25
25
 
26
 
from http.client import UnknownProtocol, parse_headers
27
 
from http.server import SimpleHTTPRequestHandler
 
26
import httplib
28
27
import io
 
28
import SimpleHTTPServer
29
29
import socket
30
30
import sys
31
31
import threading
61
61
    remote,
62
62
    )
63
63
from ..transport.http import (
64
 
    HttpTransport,
 
64
    _urllib,
 
65
    _urllib2_wrappers,
65
66
    )
66
67
 
67
68
 
71
72
def vary_by_http_client_implementation():
72
73
    """Test the libraries we can use, currently just urllib."""
73
74
    transport_scenarios = [
74
 
        ('urllib', dict(_transport=HttpTransport,
75
 
                        _server=http_server.HttpServer,
76
 
                        _url_protocol='http',)),
 
75
        ('urllib', dict(_transport=_urllib.HttpTransport_urllib,
 
76
                        _server=http_server.HttpServer_urllib,
 
77
                        _url_protocol='http+urllib',)),
77
78
        ]
78
79
    return transport_scenarios
79
80
 
81
82
def vary_by_http_protocol_version():
82
83
    """Test on http/1.0 and 1.1"""
83
84
    return [
84
 
        ('HTTP/1.0', dict(_protocol_version='HTTP/1.0')),
85
 
        ('HTTP/1.1', dict(_protocol_version='HTTP/1.1')),
 
85
        ('HTTP/1.0',  dict(_protocol_version='HTTP/1.0')),
 
86
        ('HTTP/1.1',  dict(_protocol_version='HTTP/1.1')),
86
87
        ]
87
88
 
88
89
 
119
120
def vary_by_http_activity():
120
121
    activity_scenarios = [
121
122
        ('urllib,http', dict(_activity_server=ActivityHTTPServer,
122
 
                             _transport=HttpTransport,)),
 
123
                            _transport=_urllib.HttpTransport_urllib,)),
123
124
        ]
124
125
    if features.HTTPSServerFeature.available():
125
126
        # FIXME: Until we have a better way to handle self-signed certificates
129
130
        from . import (
130
131
            ssl_certs,
131
132
            )
132
 
 
133
 
        class HTTPS_transport(HttpTransport):
 
133
        class HTTPS_urllib_transport(_urllib.HttpTransport_urllib):
134
134
 
135
135
            def __init__(self, base, _from_transport=None):
136
 
                super(HTTPS_transport, self).__init__(
 
136
                super(HTTPS_urllib_transport, self).__init__(
137
137
                    base, _from_transport=_from_transport,
138
138
                    ca_certs=ssl_certs.build_path('ca.crt'))
139
139
 
140
140
        activity_scenarios.append(
141
141
            ('urllib,https', dict(_activity_server=ActivityHTTPSServer,
142
 
                                  _transport=HTTPS_transport,)),)
 
142
                                  _transport=HTTPS_urllib_transport,)),)
143
143
    return activity_scenarios
144
144
 
145
145
 
168
168
        self._expect_body_tail = expect_body_tail
169
169
        self.host = None
170
170
        self.port = None
171
 
        self.received_bytes = b''
 
171
        self.received_bytes = ''
172
172
        self.scheme = scheme
173
173
 
174
174
    def get_url(self):
193
193
        if self._expect_body_tail is not None:
194
194
            while not self.received_bytes.endswith(self._expect_body_tail):
195
195
                self.received_bytes += conn.recv(4096)
196
 
            conn.sendall(b'HTTP/1.1 200 OK\r\n')
 
196
            conn.sendall('HTTP/1.1 200 OK\r\n')
197
197
        try:
198
198
            self._sock.close()
199
199
        except socket.error:
220
220
 
221
221
    def parse_header(self, header, auth_handler_class=None):
222
222
        if auth_handler_class is None:
223
 
            auth_handler_class = http.AbstractAuthHandler
224
 
        self.auth_handler = auth_handler_class()
 
223
            auth_handler_class = _urllib2_wrappers.AbstractAuthHandler
 
224
        self.auth_handler =  auth_handler_class()
225
225
        return self.auth_handler._parse_auth_header(header)
226
226
 
227
227
    def test_empty_header(self):
241
241
        self.assertEqual('realm="Thou should not pass"', remainder)
242
242
 
243
243
    def test_build_basic_header_with_long_creds(self):
244
 
        handler = http.BasicAuthHandler()
 
244
        handler = _urllib2_wrappers.BasicAuthHandler()
245
245
        user = 'user' * 10  # length 40
246
246
        password = 'password' * 5  # length 40
247
247
        header = handler.build_auth_header(
253
253
    def test_basic_extract_realm(self):
254
254
        scheme, remainder = self.parse_header(
255
255
            'Basic realm="Thou should not pass"',
256
 
            http.BasicAuthHandler)
 
256
            _urllib2_wrappers.BasicAuthHandler)
257
257
        match, realm = self.auth_handler.extract_realm(remainder)
258
258
        self.assertTrue(match is not None)
259
 
        self.assertEqual(u'Thou should not pass', realm)
 
259
        self.assertEqual('Thou should not pass', realm)
260
260
 
261
261
    def test_digest_header(self):
262
262
        scheme, remainder = self.parse_header(
270
270
    def setUp(self):
271
271
        super(TestHTTPRangeParsing, self).setUp()
272
272
        # We focus on range  parsing here and ignore everything else
273
 
 
274
273
        class RequestHandler(http_server.TestingHTTPRequestHandler):
275
274
            def setup(self): pass
276
 
 
277
275
            def handle(self): pass
278
 
 
279
276
            def finish(self): pass
280
277
 
281
278
        self.req_handler = RequestHandler(None, None, None)
282
279
 
283
280
    def assertRanges(self, ranges, header, file_size):
284
281
        self.assertEqual(ranges,
285
 
                         self.req_handler._parse_ranges(header, file_size))
 
282
                          self.req_handler._parse_ranges(header, file_size))
286
283
 
287
284
    def test_simple_range(self):
288
 
        self.assertRanges([(0, 2)], 'bytes=0-2', 12)
 
285
        self.assertRanges([(0,2)], 'bytes=0-2', 12)
289
286
 
290
287
    def test_tail(self):
291
288
        self.assertRanges([(8, 11)], 'bytes=-4', 12)
310
307
 
311
308
            protocol_version = 'HTTP/0.1'
312
309
 
313
 
        self.assertRaises(UnknownProtocol,
 
310
        self.assertRaises(httplib.UnknownProtocol,
314
311
                          http_server.HttpServer, BogusRequestHandler)
315
312
 
316
313
    def test_force_invalid_protocol(self):
317
 
        self.assertRaises(UnknownProtocol,
 
314
        self.assertRaises(httplib.UnknownProtocol,
318
315
                          http_server.HttpServer, protocol_version='HTTP/0.1')
319
316
 
320
317
    def test_server_start_and_stop(self):
387
384
        self._transport('http://example.com/bzr/bzr.dev/')
388
385
        self.assertRaises(urlutils.InvalidURL,
389
386
                          self._transport,
390
 
                          'http://example.com:port/bzr/bzr.dev/')
 
387
                          'http://http://example.com/bzr/bzr.dev/')
391
388
 
392
389
    def test_http_root_urls(self):
393
390
        """Construction of URLs from server root"""
426
423
        self.assertEqual(t.has('foo/bar'), True)
427
424
        self.assertEqual(len(server.logs), 1)
428
425
        self.assertContainsRe(server.logs[0],
429
 
                              r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "Breezy/')
 
426
            r'"HEAD /foo/bar HTTP/1.." (200|302) - "-" "bzr/')
430
427
 
431
428
    def test_http_has_not_found(self):
432
429
        server = self.get_readonly_server()
433
430
        t = self.get_readonly_transport()
434
431
        self.assertEqual(t.has('not-found'), False)
435
432
        self.assertContainsRe(server.logs[1],
436
 
                              r'"HEAD /not-found HTTP/1.." 404 - "-" "Breezy/')
 
433
            r'"HEAD /not-found HTTP/1.." 404 - "-" "bzr/')
437
434
 
438
435
    def test_http_get(self):
439
436
        server = self.get_readonly_server()
441
438
        fp = t.get('foo/bar')
442
439
        self.assertEqualDiff(
443
440
            fp.read(),
444
 
            b'contents of foo/bar\n')
 
441
            'contents of foo/bar\n')
445
442
        self.assertEqual(len(server.logs), 1)
446
443
        self.assertTrue(server.logs[0].find(
447
 
            '"GET /foo/bar HTTP/1.1" 200 - "-" "Breezy/%s'
 
444
            '"GET /foo/bar HTTP/1.1" 200 - "-" "bzr/%s'
448
445
            % breezy.__version__) > -1)
449
446
 
450
447
    def test_has_on_bogus_host(self):
482
479
        )
483
480
 
484
481
    def test_post_body_is_received(self):
485
 
        server = RecordingServer(expect_body_tail=b'end-of-body',
 
482
        server = RecordingServer(expect_body_tail='end-of-body',
486
483
                                 scheme=self._url_protocol)
487
484
        self.start_server(server)
488
485
        url = server.get_url()
489
486
        # FIXME: needs a cleanup -- vila 20100611
490
487
        http_transport = transport.get_transport_from_url(url)
491
 
        code, response = http_transport._post(b'abc def end-of-body')
492
 
        self.assertTrue(
493
 
            server.received_bytes.startswith(b'POST /.bzr/smart HTTP/1.'))
494
 
        self.assertTrue(
495
 
            b'content-length: 19\r' in server.received_bytes.lower())
496
 
        self.assertTrue(b'content-type: application/octet-stream\r'
 
488
        code, response = http_transport._post('abc def end-of-body')
 
489
        self.assertTrue(
 
490
            server.received_bytes.startswith('POST /.bzr/smart HTTP/1.'))
 
491
        self.assertTrue('content-length: 19\r' in server.received_bytes.lower())
 
492
        self.assertTrue('content-type: application/octet-stream\r'
497
493
                        in server.received_bytes.lower())
498
494
        # The transport should not be assuming that the server can accept
499
495
        # chunked encoding the first time it connects, because HTTP/1.1, so we
500
496
        # check for the literal string.
501
497
        self.assertTrue(
502
 
            server.received_bytes.endswith(b'\r\n\r\nabc def end-of-body'))
 
498
            server.received_bytes.endswith('\r\n\r\nabc def end-of-body'))
503
499
 
504
500
 
505
501
class TestRangeHeader(tests.TestCase):
506
502
    """Test range_header method"""
507
503
 
508
504
    def check_header(self, value, ranges=[], tail=0):
509
 
        offsets = [(start, end - start + 1) for start, end in ranges]
 
505
        offsets = [ (start, end - start + 1) for start, end in ranges]
510
506
        coalesce = transport.Transport._coalesce_offsets
511
507
        coalesced = list(coalesce(offsets, limit=0, fudge_factor=0))
512
 
        range_header = http.HttpTransport._range_header
 
508
        range_header = http.HttpTransportBase._range_header
513
509
        self.assertEqual(value, range_header(coalesced, tail))
514
510
 
515
511
    def test_range_header_single(self):
516
 
        self.check_header('0-9', ranges=[(0, 9)])
517
 
        self.check_header('100-109', ranges=[(100, 109)])
 
512
        self.check_header('0-9', ranges=[(0,9)])
 
513
        self.check_header('100-109', ranges=[(100,109)])
518
514
 
519
515
    def test_range_header_tail(self):
520
516
        self.check_header('-10', tail=10)
522
518
 
523
519
    def test_range_header_multi(self):
524
520
        self.check_header('0-9,100-200,300-5000',
525
 
                          ranges=[(0, 9), (100, 200), (300, 5000)])
 
521
                          ranges=[(0,9), (100, 200), (300,5000)])
526
522
 
527
523
    def test_range_header_mixed(self):
528
524
        self.check_header('0-9,300-5000,-50',
529
 
                          ranges=[(0, 9), (300, 5000)],
 
525
                          ranges=[(0,9), (300,5000)],
530
526
                          tail=50)
531
527
 
532
528
 
628
624
    def parse_request(self):
629
625
        """Fakes handling a single HTTP request, returns a bad status"""
630
626
        ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
631
 
        self.wfile.write(b"Invalid status line\r\n")
 
627
        self.wfile.write("Invalid status line\r\n")
632
628
        # If we don't close the connection pycurl will hang. Since this is a
633
629
        # stress test we don't *have* to respect the protocol, but we don't
634
630
        # have to sabotage it too much either.
653
649
        ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
654
650
        # Returns an invalid protocol version, but curl just
655
651
        # ignores it and those cannot be tested.
656
 
        self.wfile.write(b"%s %d %s\r\n" % (
657
 
            b'HTTP/0.0', 404, b'Look at my protocol version'))
 
652
        self.wfile.write("%s %d %s\r\n" % ('HTTP/0.0',
 
653
                                           404,
 
654
                                           'Look at my protocol version'))
658
655
        return False
659
656
 
660
657
 
700
697
 
701
698
    def test_create(self):
702
699
        server = RecordingServer(expect_body_tail=None)
703
 
        self.assertEqual(b'', server.received_bytes)
 
700
        self.assertEqual('', server.received_bytes)
704
701
        self.assertEqual(None, server.host)
705
702
        self.assertEqual(None, server.port)
706
703
 
716
713
        self.assertEqual(None, server.port)
717
714
 
718
715
    def test_send_receive_bytes(self):
719
 
        server = RecordingServer(expect_body_tail=b'c', scheme='http')
 
716
        server = RecordingServer(expect_body_tail='c', scheme='http')
720
717
        self.start_server(server)
721
718
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
722
719
        sock.connect((server.host, server.port))
723
 
        sock.sendall(b'abc')
724
 
        self.assertEqual(b'HTTP/1.1 200 OK\r\n',
 
720
        sock.sendall('abc')
 
721
        self.assertEqual('HTTP/1.1 200 OK\r\n',
725
722
                         osutils.recv_all(sock, 4096))
726
 
        self.assertEqual(b'abc', server.received_bytes)
 
723
        self.assertEqual('abc', server.received_bytes)
727
724
 
728
725
 
729
726
class TestRangeRequestServer(TestSpecificRequestHandler):
734
731
 
735
732
    def setUp(self):
736
733
        super(TestRangeRequestServer, self).setUp()
737
 
        self.build_tree_contents([('a', b'0123456789')],)
 
734
        self.build_tree_contents([('a', '0123456789')],)
738
735
 
739
736
    def test_readv(self):
740
737
        t = self.get_readonly_transport()
741
738
        l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
742
 
        self.assertEqual(l[0], (0, b'0'))
743
 
        self.assertEqual(l[1], (1, b'1'))
744
 
        self.assertEqual(l[2], (3, b'34'))
745
 
        self.assertEqual(l[3], (9, b'9'))
 
739
        self.assertEqual(l[0], (0, '0'))
 
740
        self.assertEqual(l[1], (1, '1'))
 
741
        self.assertEqual(l[2], (3, '34'))
 
742
        self.assertEqual(l[3], (9, '9'))
746
743
 
747
744
    def test_readv_out_of_order(self):
748
745
        t = self.get_readonly_transport()
749
746
        l = list(t.readv('a', ((1, 1), (9, 1), (0, 1), (3, 2))))
750
 
        self.assertEqual(l[0], (1, b'1'))
751
 
        self.assertEqual(l[1], (9, b'9'))
752
 
        self.assertEqual(l[2], (0, b'0'))
753
 
        self.assertEqual(l[3], (3, b'34'))
 
747
        self.assertEqual(l[0], (1, '1'))
 
748
        self.assertEqual(l[1], (9, '9'))
 
749
        self.assertEqual(l[2], (0, '0'))
 
750
        self.assertEqual(l[3], (3, '34'))
754
751
 
755
752
    def test_readv_invalid_ranges(self):
756
753
        t = self.get_readonly_transport()
758
755
        # This is intentionally reading off the end of the file
759
756
        # since we are sure that it cannot get there
760
757
        self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
761
 
                              t.readv, 'a', [(1, 1), (8, 10)])
 
758
                              t.readv, 'a', [(1,1), (8,10)])
762
759
 
763
760
        # This is trying to seek past the end of the file, it should
764
761
        # also raise a special error
765
762
        self.assertListRaises((errors.InvalidRange, errors.ShortReadvError,),
766
 
                              t.readv, 'a', [(12, 2)])
 
763
                              t.readv, 'a', [(12,2)])
767
764
 
768
765
    def test_readv_multiple_get_requests(self):
769
766
        server = self.get_readonly_server()
772
769
        t._max_readv_combine = 1
773
770
        t._max_get_ranges = 1
774
771
        l = list(t.readv('a', ((0, 1), (1, 1), (3, 2), (9, 1))))
775
 
        self.assertEqual(l[0], (0, b'0'))
776
 
        self.assertEqual(l[1], (1, b'1'))
777
 
        self.assertEqual(l[2], (3, b'34'))
778
 
        self.assertEqual(l[3], (9, b'9'))
 
772
        self.assertEqual(l[0], (0, '0'))
 
773
        self.assertEqual(l[1], (1, '1'))
 
774
        self.assertEqual(l[2], (3, '34'))
 
775
        self.assertEqual(l[3], (9, '9'))
779
776
        # The server should have issued 4 requests
780
777
        self.assertEqual(4, server.GET_request_nb)
781
778
 
787
784
        # single range will keep its size even if bigger than the limit.
788
785
        t._get_max_size = 2
789
786
        l = list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
790
 
        self.assertEqual(l[0], (0, b'0'))
791
 
        self.assertEqual(l[1], (1, b'1'))
792
 
        self.assertEqual(l[2], (2, b'2345'))
793
 
        self.assertEqual(l[3], (6, b'6789'))
 
787
        self.assertEqual(l[0], (0, '0'))
 
788
        self.assertEqual(l[1], (1, '1'))
 
789
        self.assertEqual(l[2], (2, '2345'))
 
790
        self.assertEqual(l[3], (6, '6789'))
794
791
        # The server should have issued 3 requests
795
792
        self.assertEqual(3, server.GET_request_nb)
796
793
 
802
799
        list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
803
800
        # The server should have issued 3 requests
804
801
        self.assertEqual(3, server.GET_request_nb)
805
 
        self.assertEqual(b'0123456789', t.get_bytes('a'))
 
802
        self.assertEqual('0123456789', t.get_bytes('a'))
806
803
        self.assertEqual(4, server.GET_request_nb)
807
804
 
808
805
    def test_incomplete_readv_leave_pipe_clean(self):
813
810
        # Don't collapse readv results into a list so that we leave unread
814
811
        # bytes on the socket
815
812
        ireadv = iter(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
816
 
        self.assertEqual((0, b'0'), next(ireadv))
 
813
        self.assertEqual((0, '0'), next(ireadv))
817
814
        # The server should have issued one request so far
818
815
        self.assertEqual(1, server.GET_request_nb)
819
 
        self.assertEqual(b'0123456789', t.get_bytes('a'))
 
816
        self.assertEqual('0123456789', t.get_bytes('a'))
820
817
        # get_bytes issued an additional request, the readv pending ones are
821
818
        # lost
822
819
        self.assertEqual(2, server.GET_request_nb)
866
863
        # Update the statistics
867
864
        self.server.test_case_server.GET_request_nb += 1
868
865
        # Just bypass the range handling done by TestingHTTPRequestHandler
869
 
        return SimpleHTTPRequestHandler.do_GET(self)
 
866
        return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
870
867
 
871
868
 
872
869
class TestNoRangeRequestServer(TestRangeRequestServer):
876
873
 
877
874
 
878
875
class MultipleRangeWithoutContentLengthRequestHandler(
879
 
        http_server.TestingHTTPRequestHandler):
 
876
    http_server.TestingHTTPRequestHandler):
880
877
    """Reply to multiple range requests without content length header."""
881
878
 
882
879
    def get_multiple_ranges(self, file, file_size, ranges):
884
881
        self.send_header('Accept-Ranges', 'bytes')
885
882
        # XXX: this is strange; the 'random' name below seems undefined and
886
883
        # yet the tests pass -- mbp 2010-10-11 bug 658773
887
 
        boundary = "%d" % random.randint(0, 0x7FFFFFFF)
 
884
        boundary = "%d" % random.randint(0,0x7FFFFFFF)
888
885
        self.send_header("Content-Type",
889
886
                         "multipart/byteranges; boundary=%s" % boundary)
890
887
        self.end_headers()
891
888
        for (start, end) in ranges:
892
 
            self.wfile.write(b"--%s\r\n" % boundary.encode('ascii'))
 
889
            self.wfile.write("--%s\r\n" % boundary)
893
890
            self.send_header("Content-type", 'application/octet-stream')
894
891
            self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
895
892
                                                                  end,
897
894
            self.end_headers()
898
895
            self.send_range_content(file, start, end - start + 1)
899
896
        # Final boundary
900
 
        self.wfile.write(b"--%s\r\n" % boundary)
 
897
        self.wfile.write("--%s\r\n" % boundary)
901
898
 
902
899
 
903
900
class TestMultipleRangeWithoutContentLengthServer(TestRangeRequestServer):
906
903
 
907
904
 
908
905
class TruncatedMultipleRangeRequestHandler(
909
 
        http_server.TestingHTTPRequestHandler):
 
906
    http_server.TestingHTTPRequestHandler):
910
907
    """Reply to multiple range requests truncating the last ones.
911
908
 
912
909
    This server generates responses whose Content-Length describes all the
922
919
        boundary = 'tagada'
923
920
        self.send_header('Content-Type',
924
921
                         'multipart/byteranges; boundary=%s' % boundary)
925
 
        boundary_line = b'--%s\r\n' % boundary.encode('ascii')
 
922
        boundary_line = '--%s\r\n' % boundary
926
923
        # Calculate the Content-Length
927
924
        content_length = 0
928
925
        for (start, end) in ranges:
931
928
                'Content-type', 'application/octet-stream')
932
929
            content_length += self._header_line_length(
933
930
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
934
 
            content_length += len('\r\n')  # end headers
935
 
            content_length += end - start  # + 1
 
931
            content_length += len('\r\n') # end headers
 
932
            content_length += end - start # + 1
936
933
        content_length += len(boundary_line)
937
934
        self.send_header('Content-length', content_length)
938
935
        self.end_headers()
961
958
 
962
959
    def setUp(self):
963
960
        super(TestTruncatedMultipleRangeServer, self).setUp()
964
 
        self.build_tree_contents([('a', b'0123456789')],)
 
961
        self.build_tree_contents([('a', '0123456789')],)
965
962
 
966
963
    def test_readv_with_short_reads(self):
967
964
        server = self.get_readonly_server()
969
966
        # Force separate ranges for each offset
970
967
        t._bytes_to_read_before_seek = 0
971
968
        ireadv = iter(t.readv('a', ((0, 1), (2, 1), (4, 2), (9, 1))))
972
 
        self.assertEqual((0, b'0'), next(ireadv))
973
 
        self.assertEqual((2, b'2'), next(ireadv))
 
969
        self.assertEqual((0, '0'), next(ireadv))
 
970
        self.assertEqual((2, '2'), next(ireadv))
974
971
        # Only one request have been issued so far
975
972
        self.assertEqual(1, server.GET_request_nb)
976
 
        self.assertEqual((4, b'45'), next(ireadv))
977
 
        self.assertEqual((9, b'9'), next(ireadv))
 
973
        self.assertEqual((4, '45'), next(ireadv))
 
974
        self.assertEqual((9, '9'), next(ireadv))
978
975
        # We issue 3 requests: two multiple (4 ranges, then 2 ranges) then a
979
976
        # single range.
980
977
        self.assertEqual(3, server.GET_request_nb)
984
981
 
985
982
 
986
983
class TruncatedBeforeBoundaryRequestHandler(
987
 
        http_server.TestingHTTPRequestHandler):
 
984
    http_server.TestingHTTPRequestHandler):
988
985
    """Truncation before a boundary, like in bug 198646"""
989
986
 
990
987
    _truncated_ranges = 1
995
992
        boundary = 'tagada'
996
993
        self.send_header('Content-Type',
997
994
                         'multipart/byteranges; boundary=%s' % boundary)
998
 
        boundary_line = b'--%s\r\n' % boundary.encode('ascii')
 
995
        boundary_line = '--%s\r\n' % boundary
999
996
        # Calculate the Content-Length
1000
997
        content_length = 0
1001
998
        for (start, end) in ranges:
1004
1001
                'Content-type', 'application/octet-stream')
1005
1002
            content_length += self._header_line_length(
1006
1003
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
1007
 
            content_length += len('\r\n')  # end headers
1008
 
            content_length += end - start  # + 1
 
1004
            content_length += len('\r\n') # end headers
 
1005
            content_length += end - start # + 1
1009
1006
        content_length += len(boundary_line)
1010
1007
        self.send_header('Content-length', content_length)
1011
1008
        self.end_headers()
1035
1032
 
1036
1033
    def setUp(self):
1037
1034
        super(TestTruncatedBeforeBoundary, self).setUp()
1038
 
        self.build_tree_contents([('a', b'0123456789')],)
 
1035
        self.build_tree_contents([('a', '0123456789')],)
1039
1036
 
1040
1037
    def test_readv_with_short_reads(self):
1041
1038
        server = self.get_readonly_server()
1043
1040
        # Force separate ranges for each offset
1044
1041
        t._bytes_to_read_before_seek = 0
1045
1042
        ireadv = iter(t.readv('a', ((0, 1), (2, 1), (4, 2), (9, 1))))
1046
 
        self.assertEqual((0, b'0'), next(ireadv))
1047
 
        self.assertEqual((2, b'2'), next(ireadv))
1048
 
        self.assertEqual((4, b'45'), next(ireadv))
1049
 
        self.assertEqual((9, b'9'), next(ireadv))
 
1043
        self.assertEqual((0, '0'), next(ireadv))
 
1044
        self.assertEqual((2, '2'), next(ireadv))
 
1045
        self.assertEqual((4, '45'), next(ireadv))
 
1046
        self.assertEqual((9, '9'), next(ireadv))
1050
1047
 
1051
1048
 
1052
1049
class LimitedRangeRequestHandler(http_server.TestingHTTPRequestHandler):
1094
1091
        super(TestLimitedRangeRequestServer, self).setUp()
1095
1092
        # We need to manipulate ranges that correspond to real chunks in the
1096
1093
        # response, so we build a content appropriately.
1097
 
        filler = b''.join([b'abcdefghij' for x in range(102)])
1098
 
        content = b''.join([b'%04d' % v + filler for v in range(16)])
 
1094
        filler = ''.join(['abcdefghij' for x in range(102)])
 
1095
        content = ''.join(['%04d' % v + filler for v in range(16)])
1099
1096
        self.build_tree_contents([('a', content)],)
1100
1097
 
1101
1098
    def test_few_ranges(self):
1102
1099
        t = self.get_readonly_transport()
1103
1100
        l = list(t.readv('a', ((0, 4), (1024, 4), )))
1104
 
        self.assertEqual(l[0], (0, b'0000'))
1105
 
        self.assertEqual(l[1], (1024, b'0001'))
 
1101
        self.assertEqual(l[0], (0, '0000'))
 
1102
        self.assertEqual(l[1], (1024, '0001'))
1106
1103
        self.assertEqual(1, self.get_readonly_server().GET_request_nb)
1107
1104
 
1108
1105
    def test_more_ranges(self):
1109
1106
        t = self.get_readonly_transport()
1110
1107
        l = list(t.readv('a', ((0, 4), (1024, 4), (4096, 4), (8192, 4))))
1111
 
        self.assertEqual(l[0], (0, b'0000'))
1112
 
        self.assertEqual(l[1], (1024, b'0001'))
1113
 
        self.assertEqual(l[2], (4096, b'0004'))
1114
 
        self.assertEqual(l[3], (8192, b'0008'))
 
1108
        self.assertEqual(l[0], (0, '0000'))
 
1109
        self.assertEqual(l[1], (1024, '0001'))
 
1110
        self.assertEqual(l[2], (4096, '0004'))
 
1111
        self.assertEqual(l[3], (8192, '0008'))
1115
1112
        # The server will refuse to serve the first request (too much ranges),
1116
1113
        # a second request will succeed.
1117
1114
        self.assertEqual(2, self.get_readonly_server().GET_request_nb)
1124
1121
    """
1125
1122
 
1126
1123
    def _proxied_request(self):
1127
 
        handler = http.ProxyHandler()
1128
 
        request = http.Request('GET', 'http://baz/buzzle')
 
1124
        handler = _urllib2_wrappers.ProxyHandler()
 
1125
        request = _urllib2_wrappers.Request('GET', 'http://baz/buzzle')
1129
1126
        handler.set_proxy(request, 'http')
1130
1127
        return request
1131
1128
 
1132
1129
    def assertEvaluateProxyBypass(self, expected, host, no_proxy):
1133
 
        handler = http.ProxyHandler()
 
1130
        handler = _urllib2_wrappers.ProxyHandler()
1134
1131
        self.assertEqual(expected,
1135
 
                         handler.evaluate_proxy_bypass(host, no_proxy))
 
1132
                          handler.evaluate_proxy_bypass(host, no_proxy))
1136
1133
 
1137
1134
    def test_empty_user(self):
1138
1135
        self.overrideEnv('http_proxy', 'http://bar.com')
1191
1188
    def setUp(self):
1192
1189
        super(TestProxyHttpServer, self).setUp()
1193
1190
        self.transport_secondary_server = http_utils.ProxyServer
1194
 
        self.build_tree_contents([('foo', b'contents of foo\n'),
1195
 
                                  ('foo-proxied', b'proxied contents of foo\n')])
 
1191
        self.build_tree_contents([('foo', 'contents of foo\n'),
 
1192
                                  ('foo-proxied', 'proxied contents of foo\n')])
1196
1193
        # Let's setup some attributes for tests
1197
1194
        server = self.get_readonly_server()
1198
1195
        self.server_host_port = '%s:%d' % (server.host, server.port)
1202
1199
 
1203
1200
    def assertProxied(self):
1204
1201
        t = self.get_readonly_transport()
1205
 
        self.assertEqual(b'proxied contents of foo\n', t.get('foo').read())
 
1202
        self.assertEqual('proxied contents of foo\n', t.get('foo').read())
1206
1203
 
1207
1204
    def assertNotProxied(self):
1208
1205
        t = self.get_readonly_transport()
1209
 
        self.assertEqual(b'contents of foo\n', t.get('foo').read())
 
1206
        self.assertEqual('contents of foo\n', t.get('foo').read())
1210
1207
 
1211
1208
    def test_http_proxy(self):
1212
1209
        self.overrideEnv('http_proxy', self.proxy_url)
1259
1256
 
1260
1257
    def setUp(self):
1261
1258
        super(TestRanges, self).setUp()
1262
 
        self.build_tree_contents([('a', b'0123456789')],)
 
1259
        self.build_tree_contents([('a', '0123456789')],)
1263
1260
 
1264
1261
    def create_transport_readonly_server(self):
1265
1262
        return http_server.HttpServer(protocol_version=self._protocol_version)
1266
1263
 
1267
1264
    def _file_contents(self, relpath, ranges):
1268
1265
        t = self.get_readonly_transport()
1269
 
        offsets = [(start, end - start + 1) for start, end in ranges]
 
1266
        offsets = [ (start, end - start + 1) for start, end in ranges]
1270
1267
        coalesce = t._coalesce_offsets
1271
1268
        coalesced = list(coalesce(offsets, limit=0, fudge_factor=0))
1272
1269
        code, data = t._get(relpath, coalesced)
1273
 
        self.assertTrue(code in (200, 206), '_get returns: %d' % code)
 
1270
        self.assertTrue(code in (200, 206),'_get returns: %d' % code)
1274
1271
        for start, end in ranges:
1275
1272
            data.seek(start)
1276
1273
            yield data.read(end - start + 1)
1278
1275
    def _file_tail(self, relpath, tail_amount):
1279
1276
        t = self.get_readonly_transport()
1280
1277
        code, data = t._get(relpath, [], tail_amount)
1281
 
        self.assertTrue(code in (200, 206), '_get returns: %d' % code)
 
1278
        self.assertTrue(code in (200, 206),'_get returns: %d' % code)
1282
1279
        data.seek(-tail_amount, 2)
1283
1280
        return data.read(tail_amount)
1284
1281
 
1285
1282
    def test_range_header(self):
1286
1283
        # Valid ranges
1287
1284
        self.assertEqual(
1288
 
            [b'0', b'234'], list(self._file_contents('a', [(0, 0), (2, 4)])))
 
1285
            ['0', '234'], list(self._file_contents('a', [(0,0), (2,4)])))
1289
1286
 
1290
1287
    def test_range_header_tail(self):
1291
 
        self.assertEqual(b'789', self._file_tail('a', 3))
 
1288
        self.assertEqual('789', self._file_tail('a', 3))
1292
1289
 
1293
1290
    def test_syntactically_invalid_range_header(self):
1294
1291
        self.assertListRaises(errors.InvalidHttpRange,
1295
 
                              self._file_contents, 'a', [(4, 3)])
 
1292
                          self._file_contents, 'a', [(4, 3)])
1296
1293
 
1297
1294
    def test_semantically_invalid_range_header(self):
1298
1295
        self.assertListRaises(errors.InvalidHttpRange,
1299
 
                              self._file_contents, 'a', [(42, 128)])
 
1296
                          self._file_contents, 'a', [(42, 128)])
1300
1297
 
1301
1298
 
1302
1299
class TestHTTPRedirections(http_utils.TestCaseWithRedirectedWebserver):
1309
1306
 
1310
1307
    def setUp(self):
1311
1308
        super(TestHTTPRedirections, self).setUp()
1312
 
        self.build_tree_contents([('a', b'0123456789'),
 
1309
        self.build_tree_contents([('a', '0123456789'),
1313
1310
                                  ('bundle',
1314
 
                                   b'# Bazaar revision bundle v0.9\n#\n')
 
1311
                                  '# Bazaar revision bundle v0.9\n#\n')
1315
1312
                                  ],)
1316
1313
 
1317
1314
    def test_redirected(self):
1318
1315
        self.assertRaises(errors.RedirectRequested,
1319
1316
                          self.get_old_transport().get, 'a')
1320
 
        self.assertEqual(
1321
 
            b'0123456789',
1322
 
            self.get_new_transport().get('a').read())
1323
 
 
1324
 
 
1325
 
class RedirectedRequest(http.Request):
 
1317
        self.assertEqual('0123456789', self.get_new_transport().get('a').read())
 
1318
 
 
1319
 
 
1320
class RedirectedRequest(_urllib2_wrappers.Request):
1326
1321
    """Request following redirections. """
1327
1322
 
1328
 
    init_orig = http.Request.__init__
 
1323
    init_orig = _urllib2_wrappers.Request.__init__
1329
1324
 
1330
1325
    def __init__(self, method, url, *args, **kwargs):
1331
1326
        """Constructor.
1332
1327
 
1333
1328
        """
1334
1329
        # Since the tests using this class will replace
1335
 
        # http.Request, we can't just call the base class __init__
 
1330
        # _urllib2_wrappers.Request, we can't just call the base class __init__
1336
1331
        # or we'll loop.
1337
1332
        RedirectedRequest.init_orig(self, method, url, *args, **kwargs)
1338
1333
        self.follow_redirections = True
1339
1334
 
1340
1335
 
1341
1336
def install_redirected_request(test):
1342
 
    test.overrideAttr(http, 'Request', RedirectedRequest)
 
1337
    test.overrideAttr(_urllib2_wrappers, 'Request', RedirectedRequest)
1343
1338
 
1344
1339
 
1345
1340
def cleanup_http_redirection_connections(test):
1346
1341
    # Some sockets are opened but never seen by _urllib, so we trap them at
1347
 
    # the http level to be able to clean them up.
 
1342
    # the _urllib2_wrappers level to be able to clean them up.
1348
1343
    def socket_disconnect(sock):
1349
1344
        try:
1350
1345
            sock.shutdown(socket.SHUT_RDWR)
1351
1346
            sock.close()
1352
1347
        except socket.error:
1353
1348
            pass
1354
 
 
1355
1349
    def connect(connection):
1356
1350
        test.http_connect_orig(connection)
1357
1351
        test.addCleanup(socket_disconnect, connection.sock)
1358
1352
    test.http_connect_orig = test.overrideAttr(
1359
 
        http.HTTPConnection, 'connect', connect)
1360
 
 
 
1353
        _urllib2_wrappers.HTTPConnection, 'connect', connect)
1361
1354
    def connect(connection):
1362
1355
        test.https_connect_orig(connection)
1363
1356
        test.addCleanup(socket_disconnect, connection.sock)
1364
1357
    test.https_connect_orig = test.overrideAttr(
1365
 
        http.HTTPSConnection, 'connect', connect)
 
1358
        _urllib2_wrappers.HTTPSConnection, 'connect', connect)
1366
1359
 
1367
1360
 
1368
1361
class TestHTTPSilentRedirections(http_utils.TestCaseWithRedirectedWebserver):
1370
1363
 
1371
1364
    http implementations do not redirect silently anymore (they
1372
1365
    do not redirect at all in fact). The mechanism is still in
1373
 
    place at the http.Request level and these tests
 
1366
    place at the _urllib2_wrappers.Request level and these tests
1374
1367
    exercise it.
1375
1368
    """
1376
1369
 
1383
1376
        super(TestHTTPSilentRedirections, self).setUp()
1384
1377
        install_redirected_request(self)
1385
1378
        cleanup_http_redirection_connections(self)
1386
 
        self.build_tree_contents([('a', b'a'),
 
1379
        self.build_tree_contents([('a','a'),
1387
1380
                                  ('1/',),
1388
 
                                  ('1/a', b'redirected once'),
 
1381
                                  ('1/a', 'redirected once'),
1389
1382
                                  ('2/',),
1390
 
                                  ('2/a', b'redirected twice'),
 
1383
                                  ('2/a', 'redirected twice'),
1391
1384
                                  ('3/',),
1392
 
                                  ('3/a', b'redirected thrice'),
 
1385
                                  ('3/a', 'redirected thrice'),
1393
1386
                                  ('4/',),
1394
 
                                  ('4/a', b'redirected 4 times'),
 
1387
                                  ('4/a', 'redirected 4 times'),
1395
1388
                                  ('5/',),
1396
 
                                  ('5/a', b'redirected 5 times'),
 
1389
                                  ('5/a', 'redirected 5 times'),
1397
1390
                                  ],)
1398
1391
 
1399
1392
    def test_one_redirection(self):
1400
1393
        t = self.get_old_transport()
 
1394
        req = RedirectedRequest('GET', t._remote_path('a'))
1401
1395
        new_prefix = 'http://%s:%s' % (self.new_server.host,
1402
1396
                                       self.new_server.port)
1403
1397
        self.old_server.redirections = \
1404
 
            [('(.*)', r'%s/1\1' % (new_prefix), 301), ]
1405
 
        self.assertEqual(
1406
 
            b'redirected once',
1407
 
            t.request('GET', t._remote_path('a'), retries=1).read())
 
1398
            [('(.*)', r'%s/1\1' % (new_prefix), 301),]
 
1399
        self.assertEqual('redirected once', t._perform(req).read())
1408
1400
 
1409
1401
    def test_five_redirections(self):
1410
1402
        t = self.get_old_transport()
 
1403
        req = RedirectedRequest('GET', t._remote_path('a'))
1411
1404
        old_prefix = 'http://%s:%s' % (self.old_server.host,
1412
1405
                                       self.old_server.port)
1413
1406
        new_prefix = 'http://%s:%s' % (self.new_server.host,
1419
1412
            ('/4(.*)', r'%s/5\1' % (new_prefix), 301),
1420
1413
            ('(/[^/]+)', r'%s/1\1' % (old_prefix), 301),
1421
1414
            ]
1422
 
        self.assertEqual(
1423
 
            b'redirected 5 times',
1424
 
            t.request('GET', t._remote_path('a'), retries=6).read())
 
1415
        self.assertEqual('redirected 5 times', t._perform(req).read())
1425
1416
 
1426
1417
 
1427
1418
class TestDoCatchRedirections(http_utils.TestCaseWithRedirectedWebserver):
1434
1425
 
1435
1426
    def setUp(self):
1436
1427
        super(TestDoCatchRedirections, self).setUp()
1437
 
        self.build_tree_contents([('a', b'0123456789'), ],)
 
1428
        self.build_tree_contents([('a', '0123456789'),],)
1438
1429
        cleanup_http_redirection_connections(self)
1439
1430
 
1440
1431
        self.old_transport = self.get_old_transport()
1446
1437
        t = self.get_new_transport()
1447
1438
 
1448
1439
        # We use None for redirected so that we fail if redirected
1449
 
        self.assertEqual(b'0123456789',
 
1440
        self.assertEqual('0123456789',
1450
1441
                         transport.do_catching_redirections(
1451
 
                             self.get_a, t, None).read())
 
1442
                self.get_a, t, None).read())
1452
1443
 
1453
1444
    def test_one_redirection(self):
1454
1445
        self.redirections = 0
1458
1449
            redirected_t = t._redirected_to(exception.source, exception.target)
1459
1450
            return redirected_t
1460
1451
 
1461
 
        self.assertEqual(b'0123456789',
 
1452
        self.assertEqual('0123456789',
1462
1453
                         transport.do_catching_redirections(
1463
 
                             self.get_a, self.old_transport, redirected).read())
 
1454
                self.get_a, self.old_transport, redirected).read())
1464
1455
        self.assertEqual(1, self.redirections)
1465
1456
 
1466
1457
    def test_redirection_loop(self):
1494
1485
        password = 'foo'
1495
1486
        _setup_authentication_config(scheme='http', host='localhost',
1496
1487
                                     user=user, password=password)
1497
 
        handler = http.HTTPAuthHandler()
 
1488
        handler = _urllib2_wrappers.HTTPAuthHandler()
1498
1489
        got_pass = handler.get_user_password(dict(
1499
1490
            user='joe',
1500
1491
            protocol='http',
1501
1492
            host='localhost',
1502
1493
            path='/',
1503
 
            realm=u'Realm',
 
1494
            realm='Realm',
1504
1495
            ))
1505
1496
        self.assertEqual((user, password), got_pass)
1506
1497
 
1517
1508
    def setUp(self):
1518
1509
        super(TestAuth, self).setUp()
1519
1510
        self.server = self.get_readonly_server()
1520
 
        self.build_tree_contents([('a', b'contents of a\n'),
1521
 
                                  ('b', b'contents of b\n'), ])
 
1511
        self.build_tree_contents([('a', 'contents of a\n'),
 
1512
                                  ('b', 'contents of b\n'),])
1522
1513
 
1523
1514
    def create_transport_readonly_server(self):
1524
1515
        server = self._auth_server(protocol_version=self._protocol_version)
1551
1542
    def test_empty_pass(self):
1552
1543
        self.server.add_user('joe', '')
1553
1544
        t = self.get_user_transport('joe', '')
1554
 
        self.assertEqual(b'contents of a\n', t.get('a').read())
 
1545
        self.assertEqual('contents of a\n', t.get('a').read())
1555
1546
        # Only one 'Authentication Required' error should occur
1556
1547
        self.assertEqual(1, self.server.auth_required_errors)
1557
1548
 
1558
1549
    def test_user_pass(self):
1559
1550
        self.server.add_user('joe', 'foo')
1560
1551
        t = self.get_user_transport('joe', 'foo')
1561
 
        self.assertEqual(b'contents of a\n', t.get('a').read())
 
1552
        self.assertEqual('contents of a\n', t.get('a').read())
1562
1553
        # Only one 'Authentication Required' error should occur
1563
1554
        self.assertEqual(1, self.server.auth_required_errors)
1564
1555
 
1584
1575
        t = self.get_user_transport(None, None)
1585
1576
        ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n')
1586
1577
        stdout, stderr = ui.ui_factory.stdout, ui.ui_factory.stderr
1587
 
        self.assertEqual(b'contents of a\n', t.get('a').read())
 
1578
        self.assertEqual('contents of a\n',t.get('a').read())
1588
1579
        # stdin should be empty
1589
1580
        self.assertEqual('', ui.ui_factory.stdin.readline())
1590
1581
        stderr.seek(0)
1599
1590
        t = self.get_user_transport('joe', None)
1600
1591
        ui.ui_factory = tests.TestUIFactory(stdin='foo\n')
1601
1592
        stdout, stderr = ui.ui_factory.stdout, ui.ui_factory.stderr
1602
 
        self.assertEqual(b'contents of a\n', t.get('a').read())
 
1593
        self.assertEqual('contents of a\n', t.get('a').read())
1603
1594
        # stdin should be empty
1604
1595
        self.assertEqual('', ui.ui_factory.stdin.readline())
1605
1596
        self._check_password_prompt(t._unqualified_scheme, 'joe',
1607
1598
        self.assertEqual('', stdout.getvalue())
1608
1599
        # And we shouldn't prompt again for a different request
1609
1600
        # against the same transport.
1610
 
        self.assertEqual(b'contents of b\n', t.get('b').read())
 
1601
        self.assertEqual('contents of b\n',t.get('b').read())
1611
1602
        t2 = t.clone()
1612
1603
        # And neither against a clone
1613
 
        self.assertEqual(b'contents of b\n', t2.get('b').read())
 
1604
        self.assertEqual('contents of b\n',t2.get('b').read())
1614
1605
        # Only one 'Authentication Required' error should occur
1615
1606
        self.assertEqual(1, self.server.auth_required_errors)
1616
1607
 
1625
1616
    def _expected_username_prompt(self, scheme):
1626
1617
        return (self._username_prompt_prefix
1627
1618
                + "%s %s:%d, Realm: '%s' username: " % (scheme.upper(),
1628
 
                                                        self.server.host, self.server.port,
1629
 
                                                        self.server.auth_realm))
 
1619
                                 self.server.host, self.server.port,
 
1620
                                 self.server.auth_realm))
1630
1621
 
1631
1622
    def test_no_prompt_for_password_when_using_auth_config(self):
1632
 
        user = ' joe'
 
1623
        user =' joe'
1633
1624
        password = 'foo'
1634
1625
        stdin_content = 'bar\n'  # Not the right password
1635
1626
        self.server.add_user(user, password)
1639
1630
        _setup_authentication_config(scheme='http', port=self.server.port,
1640
1631
                                     user=user, password=password)
1641
1632
        # Issue a request to the server to connect
1642
 
        with t.get('a') as f:
1643
 
            self.assertEqual(b'contents of a\n', f.read())
 
1633
        self.assertEqual('contents of a\n',t.get('a').read())
1644
1634
        # stdin should have  been left untouched
1645
1635
        self.assertEqual(stdin_content, ui.ui_factory.stdin.readline())
1646
1636
        # Only one 'Authentication Required' error should occur
1652
1642
            raise tests.TestNotApplicable('HTTP/proxy auth digest only test')
1653
1643
        self.server.add_user('joe', 'foo')
1654
1644
        t = self.get_user_transport('joe', 'foo')
1655
 
        with t.get('a') as f:
1656
 
            self.assertEqual(b'contents of a\n', f.read())
1657
 
        with t.get('b') as f:
1658
 
            self.assertEqual(b'contents of b\n', f.read())
 
1645
        self.assertEqual('contents of a\n', t.get('a').read())
 
1646
        self.assertEqual('contents of b\n', t.get('b').read())
1659
1647
        # Only one 'Authentication Required' error should have
1660
1648
        # occured so far
1661
1649
        self.assertEqual(1, self.server.auth_required_errors)
1662
1650
        # The server invalidates the current nonce
1663
1651
        self.server.auth_nonce = self.server.auth_nonce + '. No, now!'
1664
 
        self.assertEqual(b'contents of a\n', t.get('a').read())
 
1652
        self.assertEqual('contents of a\n', t.get('a').read())
1665
1653
        # Two 'Authentication Required' errors should occur (the
1666
1654
        # initial 'who are you' and a second 'who are you' with the new nonce)
1667
1655
        self.assertEqual(2, self.server.auth_required_errors)
1674
1662
                                     user=user, password=password)
1675
1663
        t = self.get_user_transport(None, None)
1676
1664
        # Issue a request to the server to connect
1677
 
        with t.get('a') as f:
1678
 
            self.assertEqual(b'contents of a\n', f.read())
 
1665
        self.assertEqual('contents of a\n', t.get('a').read())
1679
1666
        # Only one 'Authentication Required' error should occur
1680
1667
        self.assertEqual(1, self.server.auth_required_errors)
1681
1668
 
1687
1674
        t = self.get_user_transport(user, password)
1688
1675
        # Capture the debug calls to mutter
1689
1676
        self.mutters = []
1690
 
 
1691
1677
        def mutter(*args):
1692
1678
            lines = args[0] % args[1:]
1693
1679
            # Some calls output multiple lines, just split them now since we
1723
1709
    def setUp(self):
1724
1710
        super(TestProxyAuth, self).setUp()
1725
1711
        # Override the contents to avoid false positives
1726
 
        self.build_tree_contents([('a', b'not proxied contents of a\n'),
1727
 
                                  ('b', b'not proxied contents of b\n'),
1728
 
                                  ('a-proxied', b'contents of a\n'),
1729
 
                                  ('b-proxied', b'contents of b\n'),
 
1712
        self.build_tree_contents([('a', 'not proxied contents of a\n'),
 
1713
                                  ('b', 'not proxied contents of b\n'),
 
1714
                                  ('a-proxied', 'contents of a\n'),
 
1715
                                  ('b-proxied', 'contents of b\n'),
1730
1716
                                  ])
1731
1717
 
1732
1718
    def get_user_transport(self, user, password):
1755
1741
    def close(self):
1756
1742
        """Ignore and leave files alone."""
1757
1743
 
1758
 
    def sendall(self, bytes):
1759
 
        self.writefile.write(bytes)
1760
 
 
1761
1744
    def makefile(self, mode='r', bufsize=None):
1762
1745
        if 'r' in mode:
1763
1746
            return self.readfile
1805
1788
        remote_transport = remote.RemoteTransport('bzr://fake_host/',
1806
1789
                                                  medium=medium)
1807
1790
        self.assertEqual(
1808
 
            [(0, b"c")], list(remote_transport.readv("data-file", [(0, 1)])))
 
1791
            [(0, "c")], list(remote_transport.readv("data-file", [(0,1)])))
1809
1792
 
1810
1793
    def test_http_send_smart_request(self):
1811
1794
 
1812
 
        post_body = b'hello\n'
1813
 
        expected_reply_body = b'ok\x012\n'
 
1795
        post_body = 'hello\n'
 
1796
        expected_reply_body = 'ok\x012\n'
1814
1797
 
1815
1798
        http_transport = transport.get_transport_from_url(
1816
1799
            self.http_server.get_url())
1823
1806
        httpd = self.http_server.server
1824
1807
 
1825
1808
        socket = SampleSocket(
1826
 
            b'POST /.bzr/smart %s \r\n' % self._protocol_version.encode('ascii') +
 
1809
            'POST /.bzr/smart %s \r\n' % self._protocol_version
1827
1810
            # HTTP/1.1 posts must have a Content-Length (but it doesn't hurt
1828
1811
            # for 1.0)
1829
 
            b'Content-Length: 6\r\n'
1830
 
            b'\r\n'
1831
 
            b'hello\n')
 
1812
            + 'Content-Length: 6\r\n'
 
1813
            '\r\n'
 
1814
            'hello\n')
1832
1815
        # Beware: the ('localhost', 80) below is the
1833
1816
        # client_address parameter, but we don't have one because
1834
1817
        # we have defined a socket which is not bound to an
1838
1821
                                                         ('localhost', 80),
1839
1822
                                                         httpd)
1840
1823
        response = socket.writefile.getvalue()
1841
 
        self.assertStartsWith(
1842
 
            response,
1843
 
            b'%s 200 ' % self._protocol_version.encode('ascii'))
 
1824
        self.assertStartsWith(response, '%s 200 ' % self._protocol_version)
1844
1825
        # This includes the end of the HTTP headers, and all the body.
1845
 
        expected_end_of_response = b'\r\n\r\nok\x012\n'
 
1826
        expected_end_of_response = '\r\n\r\nok\x012\n'
1846
1827
        self.assertEndsWith(response, expected_end_of_response)
1847
1828
 
1848
1829
 
1865
1846
        # try to interpret it.
1866
1847
        self.assertRaises(errors.SmartProtocolError,
1867
1848
                          t.get_smart_medium().send_http_smart_request,
1868
 
                          b'whatever')
 
1849
                          'whatever')
1869
1850
 
1870
1851
 
1871
1852
class Test_redirected_to(tests.TestCase):
1897
1878
                             'http://foo.example.com/foo/subdir')
1898
1879
        self.assertIsInstance(r, type(t))
1899
1880
        self.assertEqual('http://foo.example.com/foo/subdir/',
1900
 
                         r.external_url())
 
1881
            r.external_url())
1901
1882
 
1902
1883
    def test_redirected_to_same_host_sibling_protocol(self):
1903
1884
        t = self._transport('http://www.example.com/foo')
1905
1886
                             'https://www.example.com/foo')
1906
1887
        self.assertIsInstance(r, type(t))
1907
1888
        self.assertEqual('https://www.example.com/foo/',
1908
 
                         r.external_url())
 
1889
            r.external_url())
1909
1890
 
1910
1891
    def test_redirected_to_same_host_different_protocol(self):
1911
1892
        t = self._transport('http://www.example.com/foo')
1912
1893
        r = t._redirected_to('http://www.example.com/foo',
1913
 
                             'bzr://www.example.com/foo')
 
1894
                             'ftp://www.example.com/foo')
1914
1895
        self.assertNotEqual(type(r), type(t))
1915
 
        self.assertEqual('bzr://www.example.com/foo/', r.external_url())
 
1896
        self.assertEqual('ftp://www.example.com/foo/', r.external_url())
1916
1897
 
1917
1898
    def test_redirected_to_same_host_specific_implementation(self):
1918
1899
        t = self._transport('http://www.example.com/foo')
1944
1925
    def _handle_one_request(self):
1945
1926
        tcs = self.server.test_case_server
1946
1927
        requestline = self.rfile.readline()
1947
 
        headers = parse_headers(self.rfile)
1948
 
        bytes_read = len(headers.as_bytes())
1949
 
        bytes_read += headers.as_bytes().count(b'\n')
1950
 
        bytes_read += len(requestline)
1951
 
        if requestline.startswith(b'POST'):
 
1928
        headers = self.MessageClass(self.rfile, 0)
 
1929
        # We just read: the request, the headers, an empty line indicating the
 
1930
        # end of the headers.
 
1931
        bytes_read = len(requestline)
 
1932
        for line in headers.headers:
 
1933
            bytes_read += len(line)
 
1934
        bytes_read += len('\r\n')
 
1935
        if requestline.startswith('POST'):
1952
1936
            # The body should be a single line (or we don't know where it ends
1953
1937
            # and we don't want to issue a blocking read)
1954
1938
            body = self.rfile.readline()
1984
1968
 
1985
1969
if features.HTTPSServerFeature.available():
1986
1970
    from . import https_server
1987
 
 
1988
1971
    class ActivityHTTPSServer(ActivityServerMixin, https_server.HTTPSServer):
1989
1972
        pass
1990
1973
 
2000
1983
        self.server = self._activity_server(self._protocol_version)
2001
1984
        self.server.start_server()
2002
1985
        self.addCleanup(self.server.stop_server)
2003
 
        _activities = {}  # Don't close over self and create a cycle
2004
 
 
 
1986
        _activities = {} # Don't close over self and create a cycle
2005
1987
        def report_activity(t, bytes, direction):
2006
1988
            count = _activities.get(direction, 0)
2007
1989
            count += bytes
2024
2006
                         self.activities.get('read', 0), 'read bytes')
2025
2007
 
2026
2008
    def test_get(self):
2027
 
        self.server.canned_response = b'''HTTP/1.1 200 OK\r
 
2009
        self.server.canned_response = '''HTTP/1.1 200 OK\r
2028
2010
Date: Tue, 11 Jul 2006 04:32:56 GMT\r
2029
2011
Server: Apache/2.0.54 (Fedora)\r
2030
2012
Last-Modified: Sun, 23 Apr 2006 19:35:20 GMT\r
2037
2019
Bazaar-NG meta directory, format 1
2038
2020
'''
2039
2021
        t = self.get_transport()
2040
 
        self.assertEqual(b'Bazaar-NG meta directory, format 1\n',
 
2022
        self.assertEqual('Bazaar-NG meta directory, format 1\n',
2041
2023
                         t.get('foo/bar').read())
2042
2024
        self.assertActivitiesMatch()
2043
2025
 
2044
2026
    def test_has(self):
2045
 
        self.server.canned_response = b'''HTTP/1.1 200 OK\r
 
2027
        self.server.canned_response = '''HTTP/1.1 200 OK\r
2046
2028
Server: SimpleHTTP/0.6 Python/2.5.2\r
2047
2029
Date: Thu, 29 Jan 2009 20:21:47 GMT\r
2048
2030
Content-type: application/octet-stream\r
2055
2037
        self.assertActivitiesMatch()
2056
2038
 
2057
2039
    def test_readv(self):
2058
 
        self.server.canned_response = b'''HTTP/1.1 206 Partial Content\r
 
2040
        self.server.canned_response = '''HTTP/1.1 206 Partial Content\r
2059
2041
Date: Tue, 11 Jul 2006 04:49:48 GMT\r
2060
2042
Server: Apache/2.0.54 (Fedora)\r
2061
2043
Last-Modified: Thu, 06 Jul 2006 20:22:05 GMT\r
2108
2090
        # Remember that the request is ignored and that the ranges below
2109
2091
        # doesn't have to match the canned response.
2110
2092
        l = list(t.readv('/foo/bar', ((0, 255), (1000, 1050))))
2111
 
        # Force consumption of the last bytesrange boundary
2112
 
        t._get_connection().cleanup_pipe()
2113
2093
        self.assertEqual(2, len(l))
2114
2094
        self.assertActivitiesMatch()
2115
2095
 
2116
2096
    def test_post(self):
2117
 
        self.server.canned_response = b'''HTTP/1.1 200 OK\r
 
2097
        self.server.canned_response = '''HTTP/1.1 200 OK\r
2118
2098
Date: Tue, 11 Jul 2006 04:32:56 GMT\r
2119
2099
Server: Apache/2.0.54 (Fedora)\r
2120
2100
Last-Modified: Sun, 23 Apr 2006 19:35:20 GMT\r
2129
2109
        t = self.get_transport()
2130
2110
        # We must send a single line of body bytes, see
2131
2111
        # PredefinedRequestHandler._handle_one_request
2132
 
        code, f = t._post(b'abc def end-of-body\n')
2133
 
        self.assertEqual(b'lalala whatever as long as itsssss\n', f.read())
 
2112
        code, f = t._post('abc def end-of-body\n')
 
2113
        self.assertEqual('lalala whatever as long as itsssss\n', f.read())
2134
2114
        self.assertActivitiesMatch()
2135
2115
 
2136
2116
 
2158
2138
 
2159
2139
    def setUp(self):
2160
2140
        super(TestNoReportActivity, self).setUp()
2161
 
        self._transport = HttpTransport
 
2141
        self._transport =_urllib.HttpTransport_urllib
2162
2142
        TestActivityMixin.setUp(self)
2163
2143
 
2164
2144
    def assertActivitiesMatch(self):
2175
2155
    _password_prompt_prefix = ''
2176
2156
    _username_prompt_prefix = ''
2177
2157
    _auth_server = http_utils.HTTPBasicAuthServer
2178
 
    _transport = HttpTransport
 
2158
    _transport = _urllib.HttpTransport_urllib
2179
2159
 
2180
2160
    def setUp(self):
2181
2161
        super(TestAuthOnRedirected, self).setUp()
2182
 
        self.build_tree_contents([('a', b'a'),
 
2162
        self.build_tree_contents([('a','a'),
2183
2163
                                  ('1/',),
2184
 
                                  ('1/a', b'redirected once'),
 
2164
                                  ('1/a', 'redirected once'),
2185
2165
                                  ],)
2186
2166
        new_prefix = 'http://%s:%s' % (self.new_server.host,
2187
2167
                                       self.new_server.port)
2188
2168
        self.old_server.redirections = [
2189
 
            ('(.*)', r'%s/1\1' % (new_prefix), 301), ]
 
2169
            ('(.*)', r'%s/1\1' % (new_prefix), 301),]
2190
2170
        self.old_transport = self.get_old_transport()
2191
2171
        self.new_server.add_user('joe', 'foo')
2192
2172
        cleanup_http_redirection_connections(self)
2209
2189
            return redirected_t
2210
2190
 
2211
2191
        ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n')
2212
 
        self.assertEqual(b'redirected once',
 
2192
        self.assertEqual('redirected once',
2213
2193
                         transport.do_catching_redirections(
2214
 
                             self.get_a, self.old_transport, redirected).read())
 
2194
                self.get_a, self.old_transport, redirected).read())
2215
2195
        self.assertEqual(1, self.redirections)
2216
2196
        # stdin should be empty
2217
2197
        self.assertEqual('', ui.ui_factory.stdin.readline())
2222
2202
        self.new_server.add_user('joe', 'foo')
2223
2203
        ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n')
2224
2204
        t = self.old_transport
 
2205
        req = RedirectedRequest('GET', t.abspath('a'))
2225
2206
        new_prefix = 'http://%s:%s' % (self.new_server.host,
2226
2207
                                       self.new_server.port)
2227
2208
        self.old_server.redirections = [
2228
 
            ('(.*)', r'%s/1\1' % (new_prefix), 301), ]
2229
 
        self.assertEqual(
2230
 
            b'redirected once',
2231
 
            t.request('GET', t.abspath('a'), retries=3).read())
 
2209
            ('(.*)', r'%s/1\1' % (new_prefix), 301),]
 
2210
        self.assertEqual('redirected once', t._perform(req).read())
2232
2211
        # stdin should be empty
2233
2212
        self.assertEqual('', ui.ui_factory.stdin.readline())
2234
2213
        # stdout should be empty, stderr will contains the prompts
2235
2214
        self.assertEqual('', ui.ui_factory.stdout.getvalue())
 
2215