/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.15 by John Arbash Meinel
Merge bzr.dev 5597 to resolve NEWS, aka bzr-2.3.txt
1
# Copyright (C) 2006-2011 Canonical Ltd
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
16
17
import errno
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
18
import httplib
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
19
import os
2146.1.1 by Alexander Belchenko
fixes for test suite: forgotten imports in HttpServer.py
20
import posixpath
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
21
import random
22
import re
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
23
import SimpleHTTPServer
24
import socket
2146.1.1 by Alexander Belchenko
fixes for test suite: forgotten imports in HttpServer.py
25
import urllib
26
import urlparse
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
27
5017.3.23 by Vincent Ladeuil
selftest -s bt.test_bzrdir passing
28
from bzrlib.tests import test_server
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
29
30
31
class BadWebserverPath(ValueError):
32
    def __str__(self):
33
        return 'path %s is not in %s' % self.args
34
35
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
36
class TestingHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
2420.1.10 by Vincent Ladeuil
Doc fixes.
37
    """Handles one request.
38
3111.1.21 by Vincent Ladeuil
Add some comments.
39
    A TestingHTTPRequestHandler is instantiated for every request received by
40
    the associated server. Note that 'request' here is inherited from the base
41
    TCPServer class, for the HTTP server it is really a connection which itself
42
    will handle one or several HTTP requests.
2420.1.10 by Vincent Ladeuil
Doc fixes.
43
    """
3111.1.24 by Vincent Ladeuil
Cleanups.
44
    # Default protocol version
45
    protocol_version = 'HTTP/1.1'
46
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
47
    # The Message-like class used to parse the request headers
48
    MessageClass = httplib.HTTPMessage
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
49
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
50
    def setup(self):
51
        SimpleHTTPServer.SimpleHTTPRequestHandler.setup(self)
3221.11.13 by Robert Collins
Allow push --shallow to just work, and fix the testing HTTPServer to not be affected by chdir() calls.
52
        self._cwd = self.server._home_dir
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
53
        tcs = self.server.test_case_server
54
        if tcs.protocol_version is not None:
55
            # If the test server forced a protocol version, use it
56
            self.protocol_version = tcs.protocol_version
57
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
58
    def log_message(self, format, *args):
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
59
        tcs = self.server.test_case_server
60
        tcs.log('webserver - %s - - [%s] %s "%s" "%s"',
61
                self.address_string(),
62
                self.log_date_time_string(),
63
                format % args,
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
64
                self.headers.get('referer', '-'),
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
65
                self.headers.get('user-agent', '-'))
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
66
5247.3.17 by Vincent Ladeuil
Fix another python tiny bug revealed by pycurl being picky.
67
    def handle(self):
68
        SimpleHTTPServer.SimpleHTTPRequestHandler.handle(self)
69
        # Some client (pycurl, I'm looking at you) are more picky than others
5247.6.6 by Vincent Ladeuil
Closing the connection is what pycurl was waiting for.
70
        # and require that the socket itself is closed
5247.3.17 by Vincent Ladeuil
Fix another python tiny bug revealed by pycurl being picky.
71
        # (SocketServer.StreamRequestHandler only close the two associated
72
        # 'makefile' objects)
73
        self.connection.close()
74
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
75
    def handle_one_request(self):
76
        """Handle a single HTTP request.
77
2831.6.1 by Vincent Ladeuil
Remove some more noise from test suite.
78
        We catch all socket errors occurring when the client close the
79
        connection early to avoid polluting the test results.
80
        """
81
        try:
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
82
            self._handle_one_request()
2831.6.1 by Vincent Ladeuil
Remove some more noise from test suite.
83
        except socket.error, e:
3111.1.24 by Vincent Ladeuil
Cleanups.
84
            # Any socket error should close the connection, but some errors are
85
            # due to the client closing early and we don't want to pollute test
3111.1.20 by Vincent Ladeuil
Make all the test pass. Looks like we are HTTP/1.1 compliant.
86
            # results, so we raise only the others.
87
            self.close_connection = 1
88
            if (len(e.args) == 0
89
                or e.args[0] not in (errno.EPIPE, errno.ECONNRESET,
90
                                     errno.ECONNABORTED, errno.EBADF)):
2831.6.1 by Vincent Ladeuil
Remove some more noise from test suite.
91
                raise
92
5354.1.1 by Vincent Ladeuil
Set a Content-Length header on errors for HTTP/1.1.
93
    error_content_type = 'text/plain'
94
    error_message_format = '''\
95
Error code: %(code)s.
96
Message: %(message)s.
97
'''
98
99
    def send_error(self, code, message=None):
100
        """Send and log an error reply.
101
102
        We redefine the python-provided version to be able to set a 
103
        ``Content-Length`` header as some http/1.1 clients complain otherwise
104
        (see bug #568421).
105
106
        :param code: The HTTP error code.
107
108
        :param message: The explanation of the error code, Defaults to a short
109
             entry.
110
        """
111
112
        if message is None:
113
            try:
114
                message = self.responses[code][0]
115
            except KeyError:
116
                message = '???'
117
        self.log_error("code %d, message %s", code, message)
118
        content = (self.error_message_format %
119
                   {'code': code, 'message': message})
120
        self.send_response(code, message)
121
        self.send_header("Content-Type", self.error_content_type)
122
        self.send_header("Content-Length", "%d" % len(content))
123
        self.send_header('Connection', 'close')
124
        self.end_headers()
125
        if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
126
            self.wfile.write(content)
127
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
128
    def _handle_one_request(self):
129
        SimpleHTTPServer.SimpleHTTPRequestHandler.handle_one_request(self)
130
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
131
    _range_regexp = re.compile(r'^(?P<start>\d+)-(?P<end>\d+)$')
132
    _tail_regexp = re.compile(r'^-(?P<tail>\d+)$')
133
134
    def parse_ranges(self, ranges_header):
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
135
        """Parse the range header value and returns ranges and tail.
136
137
        RFC2616 14.35 says that syntactically invalid range
138
        specifiers MUST be ignored. In that case, we return 0 for
139
        tail and [] for ranges.
140
        """
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
141
        tail = 0
142
        ranges = []
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
143
        if not ranges_header.startswith('bytes='):
144
            # Syntactically invalid header
145
            return 0, []
146
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
147
        ranges_header = ranges_header[len('bytes='):]
148
        for range_str in ranges_header.split(','):
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
149
            # FIXME: RFC2616 says end is optional and default to file_size
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
150
            range_match = self._range_regexp.match(range_str)
151
            if range_match is not None:
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
152
                start = int(range_match.group('start'))
153
                end = int(range_match.group('end'))
154
                if start > end:
155
                    # Syntactically invalid range
156
                    return 0, []
157
                ranges.append((start, end))
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
158
            else:
159
                tail_match = self._tail_regexp.match(range_str)
160
                if tail_match is not None:
161
                    tail = int(tail_match.group('tail'))
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
162
                else:
163
                    # Syntactically invalid range
164
                    return 0, []
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
165
        return tail, ranges
166
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
167
    def _header_line_length(self, keyword, value):
168
        header_line = '%s: %s\r\n' % (keyword, value)
169
        return len(header_line)
170
3111.1.23 by Vincent Ladeuil
Make HTTP/1.1 the default implementation reveals one more bug.
171
    def send_head(self):
172
        """Overrides base implementation to work around a bug in python2.5."""
173
        path = self.translate_path(self.path)
174
        if os.path.isdir(path) and not self.path.endswith('/'):
175
            # redirect browser - doing basically what apache does when
176
            # DirectorySlash option is On which is quite common (braindead, but
177
            # common)
178
            self.send_response(301)
179
            self.send_header("Location", self.path + "/")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
180
            # Indicates that the body is empty for HTTP/1.1 clients
3111.1.23 by Vincent Ladeuil
Make HTTP/1.1 the default implementation reveals one more bug.
181
            self.send_header('Content-Length', '0')
182
            self.end_headers()
183
            return None
184
185
        return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
186
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
187
    def send_range_content(self, file, start, length):
188
        file.seek(start)
189
        self.wfile.write(file.read(length))
190
191
    def get_single_range(self, file, file_size, start, end):
192
        self.send_response(206)
193
        length = end - start + 1
194
        self.send_header('Accept-Ranges', 'bytes')
195
        self.send_header("Content-Length", "%d" % length)
196
197
        self.send_header("Content-Type", 'application/octet-stream')
198
        self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
199
                                                              end,
200
                                                              file_size))
201
        self.end_headers()
202
        self.send_range_content(file, start, length)
203
204
    def get_multiple_ranges(self, file, file_size, ranges):
205
        self.send_response(206)
206
        self.send_header('Accept-Ranges', 'bytes')
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
207
        boundary = '%d' % random.randint(0,0x7FFFFFFF)
208
        self.send_header('Content-Type',
209
                         'multipart/byteranges; boundary=%s' % boundary)
210
        boundary_line = '--%s\r\n' % boundary
211
        # Calculate the Content-Length
212
        content_length = 0
213
        for (start, end) in ranges:
214
            content_length += len(boundary_line)
215
            content_length += self._header_line_length(
216
                'Content-type', 'application/octet-stream')
217
            content_length += self._header_line_length(
218
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
219
            content_length += len('\r\n') # end headers
2929.3.19 by Vincent Ladeuil
Fix 1.1 related bugs in HTTP server, add HTTPS passing tests (by temporarily disabling pycurl certificate verification).
220
            content_length += end - start + 1
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
221
        content_length += len(boundary_line)
222
        self.send_header('Content-length', content_length)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
223
        self.end_headers()
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
224
225
        # Send the multipart body
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
226
        for (start, end) in ranges:
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
227
            self.wfile.write(boundary_line)
228
            self.send_header('Content-type', 'application/octet-stream')
229
            self.send_header('Content-Range', 'bytes %d-%d/%d'
230
                             % (start, end, file_size))
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
231
            self.end_headers()
232
            self.send_range_content(file, start, end - start + 1)
3059.2.12 by Vincent Ladeuil
Spiv review feedback.
233
        # Final boundary
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
234
        self.wfile.write(boundary_line)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
235
236
    def do_GET(self):
237
        """Serve a GET request.
238
239
        Handles the Range header.
240
        """
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
241
        # Update statistics
242
        self.server.test_case_server.GET_request_nb += 1
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
243
244
        path = self.translate_path(self.path)
245
        ranges_header_value = self.headers.get('Range')
246
        if ranges_header_value is None or os.path.isdir(path):
247
            # Let the mother class handle most cases
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
248
            return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
249
250
        try:
251
            # Always read in binary mode. Opening files in text
252
            # mode may cause newline translations, making the
253
            # actual size of the content transmitted *less* than
254
            # the content-length!
5247.3.17 by Vincent Ladeuil
Fix another python tiny bug revealed by pycurl being picky.
255
            f = open(path, 'rb')
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
256
        except IOError:
257
            self.send_error(404, "File not found")
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
258
            return
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
259
5247.3.17 by Vincent Ladeuil
Fix another python tiny bug revealed by pycurl being picky.
260
        file_size = os.fstat(f.fileno())[6]
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
261
        tail, ranges = self.parse_ranges(ranges_header_value)
262
        # Normalize tail into ranges
263
        if tail != 0:
264
            ranges.append((file_size - tail, file_size))
265
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
266
        self._satisfiable_ranges = True
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
267
        if len(ranges) == 0:
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
268
            self._satisfiable_ranges = False
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
269
        else:
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
270
            def check_range(range_specifier):
271
                start, end = range_specifier
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
272
                # RFC2616 14.35, ranges are invalid if start >= file_size
273
                if start >= file_size:
274
                    self._satisfiable_ranges = False # Side-effect !
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
275
                    return 0, 0
276
                # RFC2616 14.35, end values should be truncated
277
                # to file_size -1 if they exceed it
278
                end = min(end, file_size - 1)
279
                return start, end
280
281
            ranges = map(check_range, ranges)
282
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
283
        if not self._satisfiable_ranges:
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
284
            # RFC2616 14.16 and 14.35 says that when a server
285
            # encounters unsatisfiable range specifiers, it
286
            # SHOULD return a 416.
5247.3.17 by Vincent Ladeuil
Fix another python tiny bug revealed by pycurl being picky.
287
            f.close()
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
288
            # FIXME: We SHOULD send a Content-Range header too,
289
            # but the implementation of send_error does not
290
            # allows that. So far.
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
291
            self.send_error(416, "Requested range not satisfiable")
292
            return
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
293
294
        if len(ranges) == 1:
295
            (start, end) = ranges[0]
5247.3.17 by Vincent Ladeuil
Fix another python tiny bug revealed by pycurl being picky.
296
            self.get_single_range(f, file_size, start, end)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
297
        else:
5247.3.17 by Vincent Ladeuil
Fix another python tiny bug revealed by pycurl being picky.
298
            self.get_multiple_ranges(f, file_size, ranges)
299
        f.close()
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
300
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
301
    def translate_path(self, path):
302
        """Translate a /-separated PATH to the local filename syntax.
303
304
        If the server requires it, proxy the path before the usual translation
305
        """
306
        if self.server.test_case_server.proxy_requests:
307
            # We need to act as a proxy and accept absolute urls,
308
            # which SimpleHTTPRequestHandler (parent) is not
309
            # ready for. So we just drop the protocol://host:port
310
            # part in front of the request-url (because we know
311
            # we would not forward the request to *another*
312
            # proxy).
313
314
            # So we do what SimpleHTTPRequestHandler.translate_path
315
            # do beginning with python 2.4.3: abandon query
316
            # parameters, scheme, host port, etc (which ensure we
317
            # provide the right behaviour on all python versions).
318
            path = urlparse.urlparse(path)[2]
319
            # And now, we can apply *our* trick to proxy files
320
            path += '-proxied'
321
322
        return self._translate_path(path)
323
324
    def _translate_path(self, path):
3221.11.13 by Robert Collins
Allow push --shallow to just work, and fix the testing HTTPServer to not be affected by chdir() calls.
325
        """Translate a /-separated PATH to the local filename syntax.
326
3221.9.5 by Ian Clatworthy
some tweaks from abentley's earlier review feedback
327
        Note that we're translating http URLs here, not file URLs.
328
        The URL root location is the server's startup directory.
3221.11.13 by Robert Collins
Allow push --shallow to just work, and fix the testing HTTPServer to not be affected by chdir() calls.
329
        Components that mean special things to the local file system
330
        (e.g. drive or directory names) are ignored.  (XXX They should
331
        probably be diagnosed.)
332
333
        Override from python standard library to stop it calling os.getcwd()
334
        """
335
        # abandon query parameters
336
        path = urlparse.urlparse(path)[2]
337
        path = posixpath.normpath(urllib.unquote(path))
3221.9.4 by Ian Clatworthy
fix failing unicode_paths test
338
        path = path.decode('utf-8')
3221.11.13 by Robert Collins
Allow push --shallow to just work, and fix the testing HTTPServer to not be affected by chdir() calls.
339
        words = path.split('/')
340
        words = filter(None, words)
341
        path = self._cwd
3221.9.5 by Ian Clatworthy
some tweaks from abentley's earlier review feedback
342
        for num, word in enumerate(words):
343
            if num == 0:
344
                drive, word = os.path.splitdrive(word)
3221.11.13 by Robert Collins
Allow push --shallow to just work, and fix the testing HTTPServer to not be affected by chdir() calls.
345
            head, word = os.path.split(word)
346
            if word in (os.curdir, os.pardir): continue
347
            path = os.path.join(path, word)
348
        return path
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
349
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
350
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
351
class TestingHTTPServerMixin:
352
353
    def __init__(self, test_case_server):
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
354
        # test_case_server can be used to communicate between the
2164.2.29 by Vincent Ladeuil
Test the http redirection at the request level even if it's not
355
        # tests and the server (or the request handler and the
356
        # server), allowing dynamic behaviors to be defined from
357
        # the tests cases.
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
358
        self.test_case_server = test_case_server
3221.11.13 by Robert Collins
Allow push --shallow to just work, and fix the testing HTTPServer to not be affected by chdir() calls.
359
        self._home_dir = test_case_server._home_dir
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
360
361
362
class TestingHTTPServer(test_server.TestingTCPServer, TestingHTTPServerMixin):
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
363
3111.1.30 by Vincent Ladeuil
Update NEWS. Some cosmetic changes.
364
    def __init__(self, server_address, request_handler_class,
365
                 test_case_server):
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
366
        test_server.TestingTCPServer.__init__(self, server_address,
367
                                              request_handler_class)
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
368
        TestingHTTPServerMixin.__init__(self, test_case_server)
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
369
370
371
class TestingThreadingHTTPServer(test_server.TestingThreadingTCPServer,
372
                                 TestingHTTPServerMixin):
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
373
    """A threading HTTP test server for HTTP 1.1.
374
375
    Since tests can initiate several concurrent connections to the same http
376
    server, we need an independent connection for each of them. We achieve that
377
    by spawning a new thread for each connection.
378
    """
3111.1.30 by Vincent Ladeuil
Update NEWS. Some cosmetic changes.
379
    def __init__(self, server_address, request_handler_class,
380
                 test_case_server):
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
381
        test_server.TestingThreadingTCPServer.__init__(self, server_address,
382
                                                       request_handler_class)
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
383
        TestingHTTPServerMixin.__init__(self, test_case_server)
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
384
385
386
class HttpServer(test_server.TestingTCPServerInAThread):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
387
    """A test server for http transports.
388
389
    Subclasses can provide a specific request handler.
390
    """
391
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
392
    # The real servers depending on the protocol
393
    http_server_class = {'HTTP/1.0': TestingHTTPServer,
394
                         'HTTP/1.1': TestingThreadingHTTPServer,
395
                         }
396
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
397
    # Whether or not we proxy the requests (see
398
    # TestingHTTPRequestHandler.translate_path).
399
    proxy_requests = False
400
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
401
    # used to form the url that connects to this server
402
    _url_protocol = 'http'
403
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
404
    def __init__(self, request_handler=TestingHTTPRequestHandler,
405
                 protocol_version=None):
406
        """Constructor.
407
408
        :param request_handler: a class that will be instantiated to handle an
409
            http connection (one or several requests).
410
411
        :param protocol_version: if specified, will override the protocol
412
            version of the request handler.
413
        """
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
414
        # Depending on the protocol version, we will create the approriate
415
        # server
416
        if protocol_version is None:
417
            # Use the request handler one
418
            proto_vers = request_handler.protocol_version
419
        else:
420
            # Use our own, it will be used to override the request handler
421
            # one too.
422
            proto_vers = protocol_version
423
        # Get the appropriate server class for the required protocol
424
        serv_cls = self.http_server_class.get(proto_vers, None)
425
        if serv_cls is None:
426
            raise httplib.UnknownProtocol(proto_vers)
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
427
        self.host = 'localhost'
428
        self.port = 0
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
429
        super(HttpServer, self).__init__((self.host, self.port),
430
                                         serv_cls,
431
                                         request_handler)
432
        self.protocol_version = proto_vers
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
433
        # Allows tests to verify number of GET requests issued
434
        self.GET_request_nb = 0
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
435
        self._http_base_url = None
436
        self.logs = []
437
438
    def create_server(self):
5247.3.16 by Vincent Ladeuil
All http tests passing (including https).
439
        return self.server_class(
440
            (self.host, self.port), self.request_handler_class, self)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
441
442
    def _get_remote_url(self, path):
443
        path_parts = path.split(os.path.sep)
444
        if os.path.isabs(path):
445
            if path_parts[:len(self._local_path_parts)] != \
446
                   self._local_path_parts:
447
                raise BadWebserverPath(path, self.test_dir)
448
            remote_path = '/'.join(path_parts[len(self._local_path_parts):])
449
        else:
450
            remote_path = '/'.join(path_parts)
451
452
        return self._http_base_url + remote_path
453
454
    def log(self, format, *args):
455
        """Capture Server log output."""
456
        self.logs.append(format % args)
457
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
458
    def start_server(self, backing_transport_server=None):
459
        """See bzrlib.transport.Server.start_server.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
460
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
461
        :param backing_transport_server: The transport that requests over this
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
462
            protocol should be forwarded to. Note that this is currently not
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
463
            supported for HTTP.
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
464
        """
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
465
        # XXX: TODO: make the server back onto vfs_server rather than local
466
        # disk.
4731.2.1 by Vincent Ladeuil
Don't use shutdown() to stop http servers.
467
        if not (backing_transport_server is None
5017.3.23 by Vincent Ladeuil
selftest -s bt.test_bzrdir passing
468
                or isinstance(backing_transport_server,
469
                              test_server.LocalURLServer)):
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
470
            raise AssertionError(
4731.2.1 by Vincent Ladeuil
Don't use shutdown() to stop http servers.
471
                "HTTPServer currently assumes local transport, got %s" %
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
472
                backing_transport_server)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
473
        self._home_dir = os.getcwdu()
474
        self._local_path_parts = self._home_dir.split(os.path.sep)
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
475
        self.logs = []
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
476
5247.3.15 by Vincent Ladeuil
All http tests passing, https failing.
477
        super(HttpServer, self).start_server()
478
        self._http_base_url = '%s://%s:%s/' % (
479
            self._url_protocol, self.host, self.port)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
480
481
    def get_url(self):
482
        """See bzrlib.transport.Server.get_url."""
483
        return self._get_remote_url(self._home_dir)
484
485
    def get_bogus_url(self):
486
        """See bzrlib.transport.Server.get_bogus_url."""
487
        # this is chosen to try to prevent trouble with proxies, weird dns,
488
        # etc
2929.3.10 by Vincent Ladeuil
Add a fake https server and test facilities.
489
        return self._url_protocol + '://127.0.0.1:1/'
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
490
491
492
class HttpServer_urllib(HttpServer):
493
    """Subclass of HttpServer that gives http+urllib urls.
494
495
    This is for use in testing: connections to this server will always go
496
    through urllib where possible.
497
    """
498
499
    # urls returned by this server should require the urllib client impl
500
    _url_protocol = 'http+urllib'
501
502
503
class HttpServer_PyCurl(HttpServer):
504
    """Subclass of HttpServer that gives http+pycurl urls.
505
506
    This is for use in testing: connections to this server will always go
507
    through pycurl where possible.
508
    """
509
510
    # We don't care about checking the pycurl availability as
511
    # this server will be required only when pycurl is present
512
513
    # urls returned by this server should require the pycurl client impl
514
    _url_protocol = 'http+pycurl'