/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: 2020-05-06 02:13:25 UTC
  • mfrom: (7490.7.21 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200506021325-awbmmqu1zyorz7sj
Merge 3.1 branch.

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