24
24
# TODO: What about renaming to breezy.tests.transport.http ?
27
from http.client import UnknownProtocol
27
from http.client import UnknownProtocol, parse_headers
28
28
from http.server import SimpleHTTPRequestHandler
29
29
except ImportError: # python < 3
30
30
from httplib import UnknownProtocol
260
261
_urllib2_wrappers.BasicAuthHandler)
261
262
match, realm = self.auth_handler.extract_realm(remainder)
262
263
self.assertTrue(match is not None)
263
self.assertEqual('Thou should not pass', realm)
264
self.assertEqual(u'Thou should not pass', realm)
265
266
def test_digest_header(self):
266
267
scheme, remainder = self.parse_header(
485
486
def test_post_body_is_received(self):
486
server = RecordingServer(expect_body_tail='end-of-body',
487
server = RecordingServer(expect_body_tail=b'end-of-body',
487
488
scheme=self._url_protocol)
488
489
self.start_server(server)
489
490
url = server.get_url()
490
491
# FIXME: needs a cleanup -- vila 20100611
491
492
http_transport = transport.get_transport_from_url(url)
492
code, response = http_transport._post('abc def end-of-body')
493
code, response = http_transport._post(b'abc def end-of-body')
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'
495
server.received_bytes.startswith(b'POST /.bzr/smart HTTP/1.'))
496
self.assertTrue(b'content-length: 19\r' in server.received_bytes.lower())
497
self.assertTrue(b'content-type: application/octet-stream\r'
497
498
in server.received_bytes.lower())
498
499
# The transport should not be assuming that the server can accept
499
500
# chunked encoding the first time it connects, because HTTP/1.1, so we
500
501
# check for the literal string.
502
server.received_bytes.endswith('\r\n\r\nabc def end-of-body'))
503
server.received_bytes.endswith(b'\r\n\r\nabc def end-of-body'))
505
506
class TestRangeHeader(tests.TestCase):
628
629
def parse_request(self):
629
630
"""Fakes handling a single HTTP request, returns a bad status"""
630
631
ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
631
self.wfile.write("Invalid status line\r\n")
632
self.wfile.write(b"Invalid status line\r\n")
632
633
# If we don't close the connection pycurl will hang. Since this is a
633
634
# stress test we don't *have* to respect the protocol, but we don't
634
635
# have to sabotage it too much either.
653
654
ignored = http_server.TestingHTTPRequestHandler.parse_request(self)
654
655
# Returns an invalid protocol version, but curl just
655
656
# ignores it and those cannot be tested.
656
self.wfile.write("%s %d %s\r\n" % ('HTTP/0.0',
658
'Look at my protocol version'))
657
self.wfile.write(b"%s %d %s\r\n" % (
658
b'HTTP/0.0', 404, b'Look at my protocol version'))
702
702
def test_create(self):
703
703
server = RecordingServer(expect_body_tail=None)
704
self.assertEqual('', server.received_bytes)
704
self.assertEqual(b'', server.received_bytes)
705
705
self.assertEqual(None, server.host)
706
706
self.assertEqual(None, server.port)
717
717
self.assertEqual(None, server.port)
719
719
def test_send_receive_bytes(self):
720
server = RecordingServer(expect_body_tail='c', scheme='http')
720
server = RecordingServer(expect_body_tail=b'c', scheme='http')
721
721
self.start_server(server)
722
722
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
723
723
sock.connect((server.host, server.port))
725
self.assertEqual('HTTP/1.1 200 OK\r\n',
725
self.assertEqual(b'HTTP/1.1 200 OK\r\n',
726
726
osutils.recv_all(sock, 4096))
727
self.assertEqual('abc', server.received_bytes)
727
self.assertEqual(b'abc', server.received_bytes)
730
730
class TestRangeRequestServer(TestSpecificRequestHandler):
740
740
def test_readv(self):
741
741
t = self.get_readonly_transport()
742
742
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'))
743
self.assertEqual(l[0], (0, b'0'))
744
self.assertEqual(l[1], (1, b'1'))
745
self.assertEqual(l[2], (3, b'34'))
746
self.assertEqual(l[3], (9, b'9'))
748
748
def test_readv_out_of_order(self):
749
749
t = self.get_readonly_transport()
750
750
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'))
751
self.assertEqual(l[0], (1, b'1'))
752
self.assertEqual(l[1], (9, b'9'))
753
self.assertEqual(l[2], (0, b'0'))
754
self.assertEqual(l[3], (3, b'34'))
756
756
def test_readv_invalid_ranges(self):
757
757
t = self.get_readonly_transport()
773
773
t._max_readv_combine = 1
774
774
t._max_get_ranges = 1
775
775
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'))
776
self.assertEqual(l[0], (0, b'0'))
777
self.assertEqual(l[1], (1, b'1'))
778
self.assertEqual(l[2], (3, b'34'))
779
self.assertEqual(l[3], (9, b'9'))
780
780
# The server should have issued 4 requests
781
781
self.assertEqual(4, server.GET_request_nb)
788
788
# single range will keep its size even if bigger than the limit.
789
789
t._get_max_size = 2
790
790
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'))
791
self.assertEqual(l[0], (0, b'0'))
792
self.assertEqual(l[1], (1, b'1'))
793
self.assertEqual(l[2], (2, b'2345'))
794
self.assertEqual(l[3], (6, b'6789'))
795
795
# The server should have issued 3 requests
796
796
self.assertEqual(3, server.GET_request_nb)
803
803
list(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
804
804
# The server should have issued 3 requests
805
805
self.assertEqual(3, server.GET_request_nb)
806
self.assertEqual('0123456789', t.get_bytes('a'))
806
self.assertEqual(b'0123456789', t.get_bytes('a'))
807
807
self.assertEqual(4, server.GET_request_nb)
809
809
def test_incomplete_readv_leave_pipe_clean(self):
814
814
# Don't collapse readv results into a list so that we leave unread
815
815
# bytes on the socket
816
816
ireadv = iter(t.readv('a', ((0, 1), (1, 1), (2, 4), (6, 4))))
817
self.assertEqual((0, '0'), next(ireadv))
817
self.assertEqual((0, b'0'), next(ireadv))
818
818
# The server should have issued one request so far
819
819
self.assertEqual(1, server.GET_request_nb)
820
self.assertEqual('0123456789', t.get_bytes('a'))
820
self.assertEqual(b'0123456789', t.get_bytes('a'))
821
821
# get_bytes issued an additional request, the readv pending ones are
823
823
self.assertEqual(2, server.GET_request_nb)
890
890
"multipart/byteranges; boundary=%s" % boundary)
891
891
self.end_headers()
892
892
for (start, end) in ranges:
893
self.wfile.write("--%s\r\n" % boundary)
893
self.wfile.write(b"--%s\r\n" % boundary.encode('ascii'))
894
894
self.send_header("Content-type", 'application/octet-stream')
895
895
self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
923
923
boundary = 'tagada'
924
924
self.send_header('Content-Type',
925
925
'multipart/byteranges; boundary=%s' % boundary)
926
boundary_line = '--%s\r\n' % boundary
926
boundary_line = b'--%s\r\n' % boundary.encode('ascii')
927
927
# Calculate the Content-Length
928
928
content_length = 0
929
929
for (start, end) in ranges:
970
970
# Force separate ranges for each offset
971
971
t._bytes_to_read_before_seek = 0
972
972
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))
973
self.assertEqual((0, b'0'), next(ireadv))
974
self.assertEqual((2, b'2'), next(ireadv))
975
975
# Only one request have been issued so far
976
976
self.assertEqual(1, server.GET_request_nb)
977
self.assertEqual((4, '45'), next(ireadv))
978
self.assertEqual((9, '9'), next(ireadv))
977
self.assertEqual((4, b'45'), next(ireadv))
978
self.assertEqual((9, b'9'), next(ireadv))
979
979
# We issue 3 requests: two multiple (4 ranges, then 2 ranges) then a
981
981
self.assertEqual(3, server.GET_request_nb)
996
996
boundary = 'tagada'
997
997
self.send_header('Content-Type',
998
998
'multipart/byteranges; boundary=%s' % boundary)
999
boundary_line = '--%s\r\n' % boundary
999
boundary_line = b'--%s\r\n' % boundary.encode('ascii')
1000
1000
# Calculate the Content-Length
1001
1001
content_length = 0
1002
1002
for (start, end) in ranges:
1044
1044
# Force separate ranges for each offset
1045
1045
t._bytes_to_read_before_seek = 0
1046
1046
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))
1047
self.assertEqual((0, b'0'), next(ireadv))
1048
self.assertEqual((2, b'2'), next(ireadv))
1049
self.assertEqual((4, b'45'), next(ireadv))
1050
self.assertEqual((9, b'9'), next(ireadv))
1053
1053
class LimitedRangeRequestHandler(http_server.TestingHTTPRequestHandler):
1102
1102
def test_few_ranges(self):
1103
1103
t = self.get_readonly_transport()
1104
1104
l = list(t.readv('a', ((0, 4), (1024, 4), )))
1105
self.assertEqual(l[0], (0, '0000'))
1106
self.assertEqual(l[1], (1024, '0001'))
1105
self.assertEqual(l[0], (0, b'0000'))
1106
self.assertEqual(l[1], (1024, b'0001'))
1107
1107
self.assertEqual(1, self.get_readonly_server().GET_request_nb)
1109
1109
def test_more_ranges(self):
1110
1110
t = self.get_readonly_transport()
1111
1111
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'))
1112
self.assertEqual(l[0], (0, b'0000'))
1113
self.assertEqual(l[1], (1024, b'0001'))
1114
self.assertEqual(l[2], (4096, b'0004'))
1115
self.assertEqual(l[3], (8192, b'0008'))
1116
1116
# The server will refuse to serve the first request (too much ranges),
1117
1117
# a second request will succeed.
1118
1118
self.assertEqual(2, self.get_readonly_server().GET_request_nb)
1286
1286
def test_range_header(self):
1288
1288
self.assertEqual(
1289
['0', '234'], list(self._file_contents('a', [(0, 0), (2, 4)])))
1289
[b'0', b'234'], list(self._file_contents('a', [(0, 0), (2, 4)])))
1291
1291
def test_range_header_tail(self):
1292
self.assertEqual('789', self._file_tail('a', 3))
1292
self.assertEqual(b'789', self._file_tail('a', 3))
1294
1294
def test_syntactically_invalid_range_header(self):
1295
1295
self.assertListRaises(errors.InvalidHttpRange,
1318
1318
def test_redirected(self):
1319
1319
self.assertRaises(errors.RedirectRequested,
1320
1320
self.get_old_transport().get, 'a')
1321
self.assertEqual('0123456789', self.get_new_transport().get('a').read())
1323
self.get_new_transport().get('a').read())
1324
1326
class RedirectedRequest(_urllib2_wrappers.Request):
1400
1402
self.new_server.port)
1401
1403
self.old_server.redirections = \
1402
1404
[('(.*)', r'%s/1\1' % (new_prefix), 301),]
1403
self.assertEqual('redirected once', t._perform(req).read())
1405
self.assertEqual(b'redirected once', t._perform(req).read())
1405
1407
def test_five_redirections(self):
1406
1408
t = self.get_old_transport()
1416
1418
('/4(.*)', r'%s/5\1' % (new_prefix), 301),
1417
1419
('(/[^/]+)', r'%s/1\1' % (old_prefix), 301),
1419
self.assertEqual('redirected 5 times', t._perform(req).read())
1421
self.assertEqual(b'redirected 5 times', t._perform(req).read())
1422
1424
class TestDoCatchRedirections(http_utils.TestCaseWithRedirectedWebserver):
1441
1443
t = self.get_new_transport()
1443
1445
# We use None for redirected so that we fail if redirected
1444
self.assertEqual('0123456789',
1446
self.assertEqual(b'0123456789',
1445
1447
transport.do_catching_redirections(
1446
1448
self.get_a, t, None).read())
1453
1455
redirected_t = t._redirected_to(exception.source, exception.target)
1454
1456
return redirected_t
1456
self.assertEqual('0123456789',
1458
self.assertEqual(b'0123456789',
1457
1459
transport.do_catching_redirections(
1458
1460
self.get_a, self.old_transport, redirected).read())
1459
1461
self.assertEqual(1, self.redirections)
1546
1548
def test_empty_pass(self):
1547
1549
self.server.add_user('joe', '')
1548
1550
t = self.get_user_transport('joe', '')
1549
self.assertEqual('contents of a\n', t.get('a').read())
1551
self.assertEqual(b'contents of a\n', t.get('a').read())
1550
1552
# Only one 'Authentication Required' error should occur
1551
1553
self.assertEqual(1, self.server.auth_required_errors)
1553
1555
def test_user_pass(self):
1554
1556
self.server.add_user('joe', 'foo')
1555
1557
t = self.get_user_transport('joe', 'foo')
1556
self.assertEqual('contents of a\n', t.get('a').read())
1558
self.assertEqual(b'contents of a\n', t.get('a').read())
1557
1559
# Only one 'Authentication Required' error should occur
1558
1560
self.assertEqual(1, self.server.auth_required_errors)
1579
1581
t = self.get_user_transport(None, None)
1580
1582
ui.ui_factory = tests.TestUIFactory(stdin='joe\nfoo\n')
1581
1583
stdout, stderr = ui.ui_factory.stdout, ui.ui_factory.stderr
1582
self.assertEqual('contents of a\n', t.get('a').read())
1584
self.assertEqual(b'contents of a\n', t.get('a').read())
1583
1585
# stdin should be empty
1584
1586
self.assertEqual('', ui.ui_factory.stdin.readline())
1594
1596
t = self.get_user_transport('joe', None)
1595
1597
ui.ui_factory = tests.TestUIFactory(stdin='foo\n')
1596
1598
stdout, stderr = ui.ui_factory.stdout, ui.ui_factory.stderr
1597
self.assertEqual('contents of a\n', t.get('a').read())
1599
self.assertEqual(b'contents of a\n', t.get('a').read())
1598
1600
# stdin should be empty
1599
1601
self.assertEqual('', ui.ui_factory.stdin.readline())
1600
1602
self._check_password_prompt(t._unqualified_scheme, 'joe',
1602
1604
self.assertEqual('', stdout.getvalue())
1603
1605
# And we shouldn't prompt again for a different request
1604
1606
# against the same transport.
1605
self.assertEqual('contents of b\n', t.get('b').read())
1607
self.assertEqual(b'contents of b\n', t.get('b').read())
1607
1609
# And neither against a clone
1608
self.assertEqual('contents of b\n', t2.get('b').read())
1610
self.assertEqual(b'contents of b\n', t2.get('b').read())
1609
1611
# Only one 'Authentication Required' error should occur
1610
1612
self.assertEqual(1, self.server.auth_required_errors)
1634
1636
_setup_authentication_config(scheme='http', port=self.server.port,
1635
1637
user=user, password=password)
1636
1638
# Issue a request to the server to connect
1637
self.assertEqual('contents of a\n', t.get('a').read())
1639
with t.get('a') as f:
1640
self.assertEqual(b'contents of a\n', f.read())
1638
1641
# stdin should have been left untouched
1639
1642
self.assertEqual(stdin_content, ui.ui_factory.stdin.readline())
1640
1643
# Only one 'Authentication Required' error should occur
1646
1649
raise tests.TestNotApplicable('HTTP/proxy auth digest only test')
1647
1650
self.server.add_user('joe', 'foo')
1648
1651
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())
1652
with t.get('a') as f:
1653
self.assertEqual(b'contents of a\n', f.read())
1654
with t.get('b') as f:
1655
self.assertEqual(b'contents of b\n', f.read())
1651
1656
# Only one 'Authentication Required' error should have
1652
1657
# occured so far
1653
1658
self.assertEqual(1, self.server.auth_required_errors)
1654
1659
# The server invalidates the current nonce
1655
1660
self.server.auth_nonce = self.server.auth_nonce + '. No, now!'
1656
self.assertEqual('contents of a\n', t.get('a').read())
1661
self.assertEqual(b'contents of a\n', t.get('a').read())
1657
1662
# Two 'Authentication Required' errors should occur (the
1658
1663
# initial 'who are you' and a second 'who are you' with the new nonce)
1659
1664
self.assertEqual(2, self.server.auth_required_errors)
1666
1671
user=user, password=password)
1667
1672
t = self.get_user_transport(None, None)
1668
1673
# Issue a request to the server to connect
1669
self.assertEqual('contents of a\n', t.get('a').read())
1674
with t.get('a') as f:
1675
self.assertEqual(b'contents of a\n', f.read())
1670
1676
# Only one 'Authentication Required' error should occur
1671
1677
self.assertEqual(1, self.server.auth_required_errors)
1934
1940
def _handle_one_request(self):
1935
1941
tcs = self.server.test_case_server
1936
1942
requestline = self.rfile.readline()
1937
headers = self.MessageClass(self.rfile, 0)
1938
# We just read: the request, the headers, an empty line indicating the
1939
# end of the headers.
1940
bytes_read = len(requestline)
1941
for line in headers.headers:
1942
bytes_read += len(line)
1943
bytes_read += len(b'\r\n')
1944
if requestline.startswith('POST'):
1944
headers = parse_headers(self.rfile)
1945
bytes_read = len(headers.as_bytes())
1946
bytes_read += headers.as_bytes().count(b'\n')
1947
bytes_read += len(requestline)
1949
headers = self.MessageClass(self.rfile, 0)
1950
# We just read: the request, the headers, an empty line indicating the
1951
# end of the headers.
1952
bytes_read = len(requestline)
1953
for line in headers.headers:
1954
bytes_read += len(line)
1955
bytes_read += len(b'\r\n')
1956
if requestline.startswith(b'POST'):
1945
1957
# The body should be a single line (or we don't know where it ends
1946
1958
# and we don't want to issue a blocking read)
1947
1959
body = self.rfile.readline()
2028
2040
Bazaar-NG meta directory, format 1
2030
2042
t = self.get_transport()
2031
self.assertEqual('Bazaar-NG meta directory, format 1\n',
2043
self.assertEqual(b'Bazaar-NG meta directory, format 1\n',
2032
2044
t.get('foo/bar').read())
2033
2045
self.assertActivitiesMatch()