~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_http.py

  • Committer: Patch Queue Manager
  • Date: 2014-09-22 19:42:30 UTC
  • mfrom: (6597.2.1 bzr)
  • Revision ID: pqm@pqm.ubuntu.com-20140922194230-y32j0sq621bxhp7c
(richard-wilbur) Split diff format option parser into a separate function,
 update to include all format options for GNU diff v3.2,
 and test parser.  Fixes lp:1370435 (Richard Wilbur)

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 
32
32
import bzrlib
33
33
from bzrlib import (
34
 
    bzrdir,
35
 
    cethread,
36
34
    config,
 
35
    controldir,
37
36
    debug,
38
37
    errors,
39
38
    osutils,
128
127
        ('urllib,http', dict(_activity_server=ActivityHTTPServer,
129
128
                            _transport=_urllib.HttpTransport_urllib,)),
130
129
        ]
131
 
    if tests.HTTPSServerFeature.available():
132
 
        activity_scenarios.append(
133
 
            ('urllib,https', dict(_activity_server=ActivityHTTPSServer,
134
 
                                _transport=_urllib.HttpTransport_urllib,)),)
135
130
    if features.pycurl.available():
136
131
        activity_scenarios.append(
137
132
            ('pycurl,http', dict(_activity_server=ActivityHTTPServer,
138
133
                                _transport=PyCurlTransport,)),)
139
 
        if tests.HTTPSServerFeature.available():
140
 
            from bzrlib.tests import (
141
 
                ssl_certs,
142
 
                )
143
 
            # FIXME: Until we have a better way to handle self-signed
144
 
            # certificates (like allowing them in a test specific
145
 
            # authentication.conf for example), we need some specialized pycurl
146
 
            # transport for tests.
 
134
    if features.HTTPSServerFeature.available():
 
135
        # FIXME: Until we have a better way to handle self-signed certificates
 
136
        # (like allowing them in a test specific authentication.conf for
 
137
        # example), we need some specialized pycurl/urllib transport for tests.
 
138
        # -- vila 2012-01-20
 
139
        from bzrlib.tests import (
 
140
            ssl_certs,
 
141
            )
 
142
        class HTTPS_urllib_transport(_urllib.HttpTransport_urllib):
 
143
 
 
144
            def __init__(self, base, _from_transport=None):
 
145
                super(HTTPS_urllib_transport, self).__init__(
 
146
                    base, _from_transport=_from_transport,
 
147
                    ca_certs=ssl_certs.build_path('ca.crt'))
 
148
 
 
149
        activity_scenarios.append(
 
150
            ('urllib,https', dict(_activity_server=ActivityHTTPSServer,
 
151
                                  _transport=HTTPS_urllib_transport,)),)
 
152
        if features.pycurl.available():
147
153
            class HTTPS_pycurl_transport(PyCurlTransport):
148
154
 
149
155
                def __init__(self, base, _from_transport=None):
378
384
    _transport = property(_get_pycurl_maybe)
379
385
 
380
386
 
381
 
class TestHttpUrls(tests.TestCase):
382
 
 
383
 
    # TODO: This should be moved to authorization tests once they
384
 
    # are written.
385
 
 
386
 
    def test_url_parsing(self):
387
 
        f = FakeManager()
388
 
        url = http.extract_auth('http://example.com', f)
389
 
        self.assertEqual('http://example.com', url)
390
 
        self.assertEqual(0, len(f.credentials))
391
 
        url = http.extract_auth(
392
 
            'http://user:pass@example.com/bzr/bzr.dev', f)
393
 
        self.assertEqual('http://example.com/bzr/bzr.dev', url)
394
 
        self.assertEqual(1, len(f.credentials))
395
 
        self.assertEqual([None, 'example.com', 'user', 'pass'],
396
 
                         f.credentials[0])
397
 
 
398
 
 
399
387
class TestHttpTransportUrls(tests.TestCase):
400
388
    """Test the http urls."""
401
389
 
481
469
        )
482
470
 
483
471
    def setUp(self):
484
 
        http_utils.TestCaseWithWebserver.setUp(self)
 
472
        super(TestHTTPConnections, self).setUp()
485
473
        self.build_tree(['foo/', 'foo/bar'], line_endings='binary',
486
474
                        transport=self.get_transport())
487
475
 
533
521
    scenarios = vary_by_http_client_implementation()
534
522
 
535
523
    def test_http_registered(self):
536
 
        t = transport.get_transport('%s://foo.com/' % self._url_protocol)
 
524
        t = transport.get_transport_from_url(
 
525
            '%s://foo.com/' % self._url_protocol)
537
526
        self.assertIsInstance(t, transport.Transport)
538
527
        self.assertIsInstance(t, self._transport)
539
528
 
551
540
        self.start_server(server)
552
541
        url = server.get_url()
553
542
        # FIXME: needs a cleanup -- vila 20100611
554
 
        http_transport = transport.get_transport(url)
 
543
        http_transport = transport.get_transport_from_url(url)
555
544
        code, response = http_transport._post('abc def end-of-body')
556
545
        self.assertTrue(
557
546
            server.received_bytes.startswith('POST /.bzr/smart HTTP/1.'))
1048
1037
        self.assertEqual('single', t._range_hint)
1049
1038
 
1050
1039
 
 
1040
class TruncatedBeforeBoundaryRequestHandler(
 
1041
    http_server.TestingHTTPRequestHandler):
 
1042
    """Truncation before a boundary, like in bug 198646"""
 
1043
 
 
1044
    _truncated_ranges = 1
 
1045
 
 
1046
    def get_multiple_ranges(self, file, file_size, ranges):
 
1047
        self.send_response(206)
 
1048
        self.send_header('Accept-Ranges', 'bytes')
 
1049
        boundary = 'tagada'
 
1050
        self.send_header('Content-Type',
 
1051
                         'multipart/byteranges; boundary=%s' % boundary)
 
1052
        boundary_line = '--%s\r\n' % boundary
 
1053
        # Calculate the Content-Length
 
1054
        content_length = 0
 
1055
        for (start, end) in ranges:
 
1056
            content_length += len(boundary_line)
 
1057
            content_length += self._header_line_length(
 
1058
                'Content-type', 'application/octet-stream')
 
1059
            content_length += self._header_line_length(
 
1060
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
 
1061
            content_length += len('\r\n') # end headers
 
1062
            content_length += end - start # + 1
 
1063
        content_length += len(boundary_line)
 
1064
        self.send_header('Content-length', content_length)
 
1065
        self.end_headers()
 
1066
 
 
1067
        # Send the multipart body
 
1068
        cur = 0
 
1069
        for (start, end) in ranges:
 
1070
            if cur + self._truncated_ranges >= len(ranges):
 
1071
                # Abruptly ends the response and close the connection
 
1072
                self.close_connection = 1
 
1073
                return
 
1074
            self.wfile.write(boundary_line)
 
1075
            self.send_header('Content-type', 'application/octet-stream')
 
1076
            self.send_header('Content-Range', 'bytes %d-%d/%d'
 
1077
                             % (start, end, file_size))
 
1078
            self.end_headers()
 
1079
            self.send_range_content(file, start, end - start + 1)
 
1080
            cur += 1
 
1081
        # Final boundary
 
1082
        self.wfile.write(boundary_line)
 
1083
 
 
1084
 
 
1085
class TestTruncatedBeforeBoundary(TestSpecificRequestHandler):
 
1086
    """Tests the case of bug 198646, disconnecting before a boundary."""
 
1087
 
 
1088
    _req_handler_class = TruncatedBeforeBoundaryRequestHandler
 
1089
 
 
1090
    def setUp(self):
 
1091
        super(TestTruncatedBeforeBoundary, self).setUp()
 
1092
        self.build_tree_contents([('a', '0123456789')],)
 
1093
 
 
1094
    def test_readv_with_short_reads(self):
 
1095
        server = self.get_readonly_server()
 
1096
        t = self.get_readonly_transport()
 
1097
        # Force separate ranges for each offset
 
1098
        t._bytes_to_read_before_seek = 0
 
1099
        ireadv = iter(t.readv('a', ((0, 1), (2, 1), (4, 2), (9, 1))))
 
1100
        self.assertEqual((0, '0'), ireadv.next())
 
1101
        self.assertEqual((2, '2'), ireadv.next())
 
1102
        self.assertEqual((4, '45'), ireadv.next())
 
1103
        self.assertEqual((9, '9'), ireadv.next())
 
1104
 
 
1105
 
1051
1106
class LimitedRangeRequestHandler(http_server.TestingHTTPRequestHandler):
1052
1107
    """Errors out when range specifiers exceed the limit"""
1053
1108
 
1090
1145
                                      protocol_version=self._protocol_version)
1091
1146
 
1092
1147
    def setUp(self):
1093
 
        http_utils.TestCaseWithWebserver.setUp(self)
 
1148
        super(TestLimitedRangeRequestServer, self).setUp()
1094
1149
        # We need to manipulate ranges that correspond to real chunks in the
1095
1150
        # response, so we build a content appropriately.
1096
1151
        filler = ''.join(['abcdefghij' for x in range(102)])
1282
1337
        )
1283
1338
 
1284
1339
    def setUp(self):
1285
 
        http_utils.TestCaseWithWebserver.setUp(self)
 
1340
        super(TestRanges, self).setUp()
1286
1341
        self.build_tree_contents([('a', '0123456789')],)
1287
1342
 
1288
1343
    def create_transport_readonly_server(self):
1569
1624
        return url
1570
1625
 
1571
1626
    def get_user_transport(self, user, password):
1572
 
        t = transport.get_transport(self.get_user_url(user, password))
 
1627
        t = transport.get_transport_from_url(
 
1628
            self.get_user_url(user, password))
1573
1629
        return t
1574
1630
 
1575
1631
    def test_no_user(self):
1701
1757
                                     http_utils.ProxyDigestAuthServer):
1702
1758
            raise tests.TestNotApplicable('HTTP/proxy auth digest only test')
1703
1759
        if self._testing_pycurl():
1704
 
            raise tests.KnownFailure(
 
1760
            self.knownFailure(
1705
1761
                'pycurl does not handle a nonce change')
1706
1762
        self.server.add_user('joe', 'foo')
1707
1763
        t = self.get_user_transport('joe', 'foo')
1789
1845
        if self._testing_pycurl():
1790
1846
            import pycurl
1791
1847
            if pycurl.version_info()[1] < '7.16.0':
1792
 
                raise tests.KnownFailure(
 
1848
                self.knownFailure(
1793
1849
                    'pycurl < 7.16.0 does not handle empty proxy passwords')
1794
1850
        super(TestProxyAuth, self).test_empty_pass()
1795
1851
 
1837
1893
        server._url_protocol = self._url_protocol
1838
1894
        return server
1839
1895
 
1840
 
    def test_open_bzrdir(self):
 
1896
    def test_open_controldir(self):
1841
1897
        branch = self.make_branch('relpath')
1842
1898
        url = self.http_server.get_url() + 'relpath'
1843
 
        bd = bzrdir.BzrDir.open(url)
 
1899
        bd = controldir.ControlDir.open(url)
1844
1900
        self.addCleanup(bd.transport.disconnect)
1845
1901
        self.assertIsInstance(bd, _mod_remote.RemoteBzrDir)
1846
1902
 
1849
1905
        # The 'readv' command in the smart protocol both sends and receives
1850
1906
        # bulk data, so we use that.
1851
1907
        self.build_tree(['data-file'])
1852
 
        http_transport = transport.get_transport(self.http_server.get_url())
 
1908
        http_transport = transport.get_transport_from_url(
 
1909
            self.http_server.get_url())
1853
1910
        medium = http_transport.get_smart_medium()
1854
1911
        # Since we provide the medium, the url below will be mostly ignored
1855
1912
        # during the test, as long as the path is '/'.
1863
1920
        post_body = 'hello\n'
1864
1921
        expected_reply_body = 'ok\x012\n'
1865
1922
 
1866
 
        http_transport = transport.get_transport(self.http_server.get_url())
 
1923
        http_transport = transport.get_transport_from_url(
 
1924
            self.http_server.get_url())
1867
1925
        medium = http_transport.get_smart_medium()
1868
1926
        response = medium.send_http_smart_request(post_body)
1869
1927
        reply_body = response.read()
1927
1985
        self.assertIsInstance(r, type(t))
1928
1986
        # Both transports share the some connection
1929
1987
        self.assertEqual(t._get_connection(), r._get_connection())
 
1988
        self.assertEquals('http://www.example.com/foo/subdir/', r.base)
1930
1989
 
1931
1990
    def test_redirected_to_self_with_slash(self):
1932
1991
        t = self._transport('http://www.example.com/foo')
1943
2002
        r = t._redirected_to('http://www.example.com/foo',
1944
2003
                             'http://foo.example.com/foo/subdir')
1945
2004
        self.assertIsInstance(r, type(t))
 
2005
        self.assertEquals('http://foo.example.com/foo/subdir/',
 
2006
            r.external_url())
1946
2007
 
1947
2008
    def test_redirected_to_same_host_sibling_protocol(self):
1948
2009
        t = self._transport('http://www.example.com/foo')
1949
2010
        r = t._redirected_to('http://www.example.com/foo',
1950
2011
                             'https://www.example.com/foo')
1951
2012
        self.assertIsInstance(r, type(t))
 
2013
        self.assertEquals('https://www.example.com/foo/',
 
2014
            r.external_url())
1952
2015
 
1953
2016
    def test_redirected_to_same_host_different_protocol(self):
1954
2017
        t = self._transport('http://www.example.com/foo')
1955
2018
        r = t._redirected_to('http://www.example.com/foo',
1956
2019
                             'ftp://www.example.com/foo')
1957
2020
        self.assertNotEquals(type(r), type(t))
 
2021
        self.assertEquals('ftp://www.example.com/foo/', r.external_url())
 
2022
 
 
2023
    def test_redirected_to_same_host_specific_implementation(self):
 
2024
        t = self._transport('http://www.example.com/foo')
 
2025
        r = t._redirected_to('http://www.example.com/foo',
 
2026
                             'https+urllib://www.example.com/foo')
 
2027
        self.assertEquals('https://www.example.com/foo/', r.external_url())
1958
2028
 
1959
2029
    def test_redirected_to_different_host_same_user(self):
1960
2030
        t = self._transport('http://joe@www.example.com/foo')
1961
2031
        r = t._redirected_to('http://www.example.com/foo',
1962
2032
                             'https://foo.example.com/foo')
1963
2033
        self.assertIsInstance(r, type(t))
1964
 
        self.assertEqual(t._user, r._user)
 
2034
        self.assertEqual(t._parsed_url.user, r._parsed_url.user)
 
2035
        self.assertEquals('https://joe@foo.example.com/foo/', r.external_url())
1965
2036
 
1966
2037
 
1967
2038
class PredefinedRequestHandler(http_server.TestingHTTPRequestHandler):
2020
2091
    pass
2021
2092
 
2022
2093
 
2023
 
if tests.HTTPSServerFeature.available():
 
2094
if features.HTTPSServerFeature.available():
2024
2095
    from bzrlib.tests import https_server
2025
2096
    class ActivityHTTPSServer(ActivityServerMixin, https_server.HTTPSServer):
2026
2097
        pass
2034
2105
    """
2035
2106
 
2036
2107
    def setUp(self):
2037
 
        tests.TestCase.setUp(self)
2038
2108
        self.server = self._activity_server(self._protocol_version)
2039
2109
        self.server.start_server()
 
2110
        self.addCleanup(self.server.stop_server)
2040
2111
        _activities = {} # Don't close over self and create a cycle
2041
2112
        def report_activity(t, bytes, direction):
2042
2113
            count = _activities.get(direction, 0)
2043
2114
            count += bytes
2044
2115
            _activities[direction] = count
2045
2116
        self.activities = _activities
2046
 
 
2047
2117
        # We override at class level because constructors may propagate the
2048
2118
        # bound method and render instance overriding ineffective (an
2049
2119
        # alternative would be to define a specific ui factory instead...)
2050
2120
        self.overrideAttr(self._transport, '_report_activity', report_activity)
2051
 
        self.addCleanup(self.server.stop_server)
2052
2121
 
2053
2122
    def get_transport(self):
2054
2123
        t = self._transport(self.server.get_url())
2178
2247
        )
2179
2248
 
2180
2249
    def setUp(self):
 
2250
        super(TestActivity, self).setUp()
2181
2251
        TestActivityMixin.setUp(self)
2182
2252
 
2183
2253
 
2192
2262
    _protocol_version = 'HTTP/1.1'
2193
2263
 
2194
2264
    def setUp(self):
 
2265
        super(TestNoReportActivity, self).setUp()
2195
2266
        self._transport =_urllib.HttpTransport_urllib
2196
2267
        TestActivityMixin.setUp(self)
2197
2268