/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
3059.2.2 by Vincent Ladeuil
Read http responses on demand without buffering the whole body
1
# Copyright (C) 2006, 2007 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
import BaseHTTPServer
18
import errno
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
19
import httplib
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
20
import os
2146.1.1 by Alexander Belchenko
fixes for test suite: forgotten imports in HttpServer.py
21
import posixpath
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
22
import random
23
import re
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
24
import SimpleHTTPServer
25
import socket
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
26
import SocketServer
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
27
import sys
28
import threading
29
import time
2146.1.1 by Alexander Belchenko
fixes for test suite: forgotten imports in HttpServer.py
30
import urllib
31
import urlparse
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
32
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
33
from bzrlib import transport
34
from bzrlib.transport import local
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
35
36
37
class WebserverNotAvailable(Exception):
38
    pass
39
40
41
class BadWebserverPath(ValueError):
42
    def __str__(self):
43
        return 'path %s is not in %s' % self.args
44
45
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
46
class TestingHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
2420.1.10 by Vincent Ladeuil
Doc fixes.
47
    """Handles one request.
48
49
    A TestingHTTPRequestHandler is instantiated for every request
2420.1.12 by Vincent Ladeuil
Cometic changes.
50
    received by the associated server.
2420.1.10 by Vincent Ladeuil
Doc fixes.
51
    """
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
52
    # The Message-like class used to parse the request headers
53
    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 :)
54
55
    def log_message(self, format, *args):
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
56
        tcs = self.server.test_case_server
57
        tcs.log('webserver - %s - - [%s] %s "%s" "%s"',
58
                self.address_string(),
59
                self.log_date_time_string(),
60
                format % args,
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
61
                self.headers.get('referrer', '-'),
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
62
                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 :)
63
64
    def handle_one_request(self):
65
        """Handle a single HTTP request.
66
2831.6.1 by Vincent Ladeuil
Remove some more noise from test suite.
67
        We catch all socket errors occurring when the client close the
68
        connection early to avoid polluting the test results.
69
        """
70
        try:
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
71
            SimpleHTTPServer.SimpleHTTPRequestHandler.handle_one_request(self)
2831.6.1 by Vincent Ladeuil
Remove some more noise from test suite.
72
        except socket.error, e:
73
            if (len(e.args) > 0
74
                and e.args[0] in (errno.EPIPE, errno.ECONNRESET,
75
                                  errno.ECONNABORTED,)):
76
                self.close_connection = 1
77
            else:
78
                raise
79
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
80
    _range_regexp = re.compile(r'^(?P<start>\d+)-(?P<end>\d+)$')
81
    _tail_regexp = re.compile(r'^-(?P<tail>\d+)$')
82
83
    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
84
        """Parse the range header value and returns ranges and tail.
85
86
        RFC2616 14.35 says that syntactically invalid range
87
        specifiers MUST be ignored. In that case, we return 0 for
88
        tail and [] for ranges.
89
        """
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
90
        tail = 0
91
        ranges = []
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
92
        if not ranges_header.startswith('bytes='):
93
            # Syntactically invalid header
94
            return 0, []
95
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
96
        ranges_header = ranges_header[len('bytes='):]
97
        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
98
            # 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 :)
99
            range_match = self._range_regexp.match(range_str)
100
            if range_match is not None:
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
101
                start = int(range_match.group('start'))
102
                end = int(range_match.group('end'))
103
                if start > end:
104
                    # Syntactically invalid range
105
                    return 0, []
106
                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 :)
107
            else:
108
                tail_match = self._tail_regexp.match(range_str)
109
                if tail_match is not None:
110
                    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
111
                else:
112
                    # Syntactically invalid range
113
                    return 0, []
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
114
        return tail, ranges
115
116
    def send_range_content(self, file, start, length):
117
        file.seek(start)
118
        self.wfile.write(file.read(length))
119
120
    def get_single_range(self, file, file_size, start, end):
121
        self.send_response(206)
122
        length = end - start + 1
123
        self.send_header('Accept-Ranges', 'bytes')
124
        self.send_header("Content-Length", "%d" % length)
125
126
        self.send_header("Content-Type", 'application/octet-stream')
127
        self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
128
                                                              end,
129
                                                              file_size))
130
        self.end_headers()
131
        self.send_range_content(file, start, length)
132
133
    def get_multiple_ranges(self, file, file_size, ranges):
134
        self.send_response(206)
135
        self.send_header('Accept-Ranges', 'bytes')
136
        boundary = "%d" % random.randint(0,0x7FFFFFFF)
137
        self.send_header("Content-Type",
138
                         "multipart/byteranges; boundary=%s" % boundary)
139
        self.end_headers()
140
        for (start, end) in ranges:
3059.2.12 by Vincent Ladeuil
Spiv review feedback.
141
            self.wfile.write("--%s\r\n" % boundary)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
142
            self.send_header("Content-type", 'application/octet-stream')
143
            self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
144
                                                                  end,
145
                                                                  file_size))
146
            self.end_headers()
147
            self.send_range_content(file, start, end - start + 1)
3059.2.12 by Vincent Ladeuil
Spiv review feedback.
148
        # Final boundary
149
        self.wfile.write("--%s\r\n" % boundary)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
150
151
    def do_GET(self):
152
        """Serve a GET request.
153
154
        Handles the Range header.
155
        """
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
156
        # Update statistics
157
        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 :)
158
159
        path = self.translate_path(self.path)
160
        ranges_header_value = self.headers.get('Range')
161
        if ranges_header_value is None or os.path.isdir(path):
162
            # Let the mother class handle most cases
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
163
            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 :)
164
165
        try:
166
            # Always read in binary mode. Opening files in text
167
            # mode may cause newline translations, making the
168
            # actual size of the content transmitted *less* than
169
            # the content-length!
170
            file = open(path, 'rb')
171
        except IOError:
172
            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 :)
173
            return
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
174
175
        file_size = os.fstat(file.fileno())[6]
176
        tail, ranges = self.parse_ranges(ranges_header_value)
177
        # Normalize tail into ranges
178
        if tail != 0:
179
            ranges.append((file_size - tail, file_size))
180
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
181
        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 :)
182
        if len(ranges) == 0:
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
183
            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 :)
184
        else:
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
185
            def check_range(range_specifier):
186
                start, end = range_specifier
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
187
                # RFC2616 14.35, ranges are invalid if start >= file_size
188
                if start >= file_size:
189
                    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
190
                    return 0, 0
191
                # RFC2616 14.35, end values should be truncated
192
                # to file_size -1 if they exceed it
193
                end = min(end, file_size - 1)
194
                return start, end
195
196
            ranges = map(check_range, ranges)
197
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
198
        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
199
            # RFC2616 14.16 and 14.35 says that when a server
200
            # encounters unsatisfiable range specifiers, it
201
            # SHOULD return a 416.
2000.3.9 by v.ladeuil+lp at free
The tests that would have help avoid bug #73948 and all that mess :)
202
            file.close()
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
203
            # FIXME: We SHOULD send a Content-Range header too,
204
            # but the implementation of send_error does not
205
            # 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 :)
206
            self.send_error(416, "Requested range not satisfiable")
207
            return
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
208
209
        if len(ranges) == 1:
210
            (start, end) = ranges[0]
211
            self.get_single_range(file, file_size, start, end)
212
        else:
213
            self.get_multiple_ranges(file, file_size, ranges)
214
        file.close()
215
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
216
    def translate_path(self, path):
217
        """Translate a /-separated PATH to the local filename syntax.
218
219
        If the server requires it, proxy the path before the usual translation
220
        """
221
        if self.server.test_case_server.proxy_requests:
222
            # We need to act as a proxy and accept absolute urls,
223
            # which SimpleHTTPRequestHandler (parent) is not
224
            # ready for. So we just drop the protocol://host:port
225
            # part in front of the request-url (because we know
226
            # we would not forward the request to *another*
227
            # proxy).
228
229
            # So we do what SimpleHTTPRequestHandler.translate_path
230
            # do beginning with python 2.4.3: abandon query
231
            # parameters, scheme, host port, etc (which ensure we
232
            # provide the right behaviour on all python versions).
233
            path = urlparse.urlparse(path)[2]
234
            # And now, we can apply *our* trick to proxy files
235
            path += '-proxied'
236
237
        return self._translate_path(path)
238
239
    def _translate_path(self, path):
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
240
        return SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(
241
            self, path)
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
242
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
243
    if sys.platform == 'win32':
244
        # On win32 you cannot access non-ascii filenames without
245
        # decoding them into unicode first.
246
        # However, under Linux, you can access bytestream paths
247
        # without any problems. If this function was always active
248
        # it would probably break tests when LANG=C was set
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
249
        def _translate_path(self, path):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
250
            """Translate a /-separated PATH to the local filename syntax.
251
252
            For bzr, all url paths are considered to be utf8 paths.
253
            On Linux, you can access these paths directly over the bytestream
254
            request, but on win32, you must decode them, and access them
255
            as Unicode files.
256
            """
257
            # abandon query parameters
258
            path = urlparse.urlparse(path)[2]
259
            path = posixpath.normpath(urllib.unquote(path))
260
            path = path.decode('utf-8')
261
            words = path.split('/')
262
            words = filter(None, words)
263
            path = os.getcwdu()
264
            for word in words:
265
                drive, word = os.path.splitdrive(word)
266
                head, word = os.path.split(word)
267
                if word in (os.curdir, os.pardir): continue
268
                path = os.path.join(path, word)
269
            return path
270
271
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
272
class TestingHTTPServerWrapper(object):
273
    """Isolate the wrapper itself to make the server use transparent.
274
275
    Daughter classes can override any method and/or directly call the _server
276
    methods.
277
    """
278
279
    def __init__(self, server_class, test_case_server,
280
                 server_address, request_handler_class):
281
        self._server = server_class(server_address, request_handler_class)
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
282
        # 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
283
        # tests and the server (or the request handler and the
284
        # server), allowing dynamic behaviors to be defined from
285
        # the tests cases.
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
286
        self._server.test_case_server = test_case_server
287
288
    def __getattr__(self, name):
289
        return getattr(self._server, name)
290
291
    def server_bind(self):
292
        """Override server_bind to store the server name."""
293
        self._server.server_bind()
294
        host, port = self._server.socket.getsockname()[:2]
295
        self._server.server_name = socket.getfqdn(host)
296
        self._server.server_port = port
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
297
2953.2.1 by Vincent Ladeuil
Fix #158972 by not using timeout for HttpServer.
298
    def server_close(self):
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
299
         """Called to clean-up the server.
300
 
301
         Since the server may be (surely is, even) in a blocking listen, we
302
         shutdown its socket before closing it.
303
         """
304
         # Note that is this executed as part of the implicit tear down in the
305
         # main thread while the server runs in its own thread. The clean way
306
         # to tear down the server will be to instruct him to stop accepting
307
         # connections and wait for the current connection to end naturally. To
308
         # end the connection naturally, the http transports should close their
309
         # socket when they do not need to talk to the server anymore.  We
310
         # don't want to impose such a constraint on the http transports (and
311
         # we can't anyway ;). So we must tear down here, from the main thread,
312
         # when the test have ended.  Note that since the server is in a
313
         # blocking operation and since python use select internally, shutting
314
         # down the socket is reliable and relatively clean.
315
         self._server.socket.shutdown(socket.SHUT_RDWR)
316
         # Let the server properly close the socket
317
         self._server.server_close()
318
319
class TestingHTTPServer(TestingHTTPServerWrapper):
320
321
    def __init__(self, server_address, request_handler_class, test_case_server):
322
        super(TestingHTTPServer, self).__init__(
323
            SocketServer.TCPServer, test_case_server,
324
            server_address, request_handler_class)
325
326
327
class TestingThreadingHTTPServer(TestingHTTPServerWrapper):
328
    """A threading HTTP test server for HTTP 1.1.
329
330
    Since tests can initiate several concurrent connections to the same http
331
    server, we need an independent connection for each of them. We achieve that
332
    by spawning a new thread for each connection.
333
    """
334
335
    def __init__(self, server_address, request_handler_class, test_case_server):
336
        super(TestingThreadingHTTPServer, self).__init__(
337
            SocketServer.ThreadingTCPServer, test_case_server,
338
            server_address, request_handler_class)
339
        # Decides how threads will act upon termination of the main
340
        # process. This is prophylactic as we should not leave the threads
341
        # lying around.
342
        self._server.daemon_threads = True
2953.2.1 by Vincent Ladeuil
Fix #158972 by not using timeout for HttpServer.
343
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
344
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
345
class HttpServer(transport.Server):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
346
    """A test server for http transports.
347
348
    Subclasses can provide a specific request handler.
349
    """
350
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
351
    # The real servers depending on the protocol
352
    http_server_class = {'HTTP/1.0': TestingHTTPServer,
353
                         'HTTP/1.1': TestingThreadingHTTPServer,
354
                         }
355
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
356
    # Whether or not we proxy the requests (see
357
    # TestingHTTPRequestHandler.translate_path).
358
    proxy_requests = False
359
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
360
    # used to form the url that connects to this server
361
    _url_protocol = 'http'
362
363
    # Subclasses can provide a specific request handler
364
    def __init__(self, request_handler=TestingHTTPRequestHandler):
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
365
        transport.Server.__init__(self)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
366
        self.request_handler = request_handler
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
367
        self.host = 'localhost'
368
        self.port = 0
369
        self._httpd = None
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
370
        # Allows tests to verify number of GET requests issued
371
        self.GET_request_nb = 0
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
372
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
373
    def _get_httpd(self):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
374
        if self._httpd is None:
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
375
            rhandler = self.request_handler
376
            proto_vers = rhandler.protocol_version
377
            # Create the appropriate server for the required protocol
378
            serv_cls = self.http_server_class.get(proto_vers, None)
379
            if serv_cls is None:
380
                raise httplib.UnknownProtocol(proto_vers)
381
            else:
382
                self._httpd = serv_cls((self.host, self.port), rhandler, self)
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
383
            host, self.port = self._httpd.socket.getsockname()
384
        return self._httpd
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
385
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
386
    def _http_start(self):
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
387
        """Server thread main entry point. """
388
        self._http_running = False
389
        try:
390
            try:
391
                httpd = self._get_httpd()
392
                self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
393
                                                       self.host, self.port)
394
                self._http_running = True
395
            except:
396
                # Whatever goes wrong, we save the exception for the main
397
                # thread. Note that since we are running in a thread, no signal
398
                # can be received, so we don't care about KeyboardInterrupt.
399
                self._http_exception = sys.exc_info()
400
        finally:
401
            # Release the lock or the main thread will block and the whole
402
            # process will hang.
403
            self._http_starting.release()
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
404
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
405
        # From now on, exceptions are taken care of by the
406
        # SocketServer.BaseServer or the request handler.
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
407
        while self._http_running:
408
            try:
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
409
                # Really an HTTP connection but the python framework is generic
410
                # and call them requests
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
411
                httpd.handle_request()
412
            except socket.timeout:
413
                pass
414
415
    def _get_remote_url(self, path):
416
        path_parts = path.split(os.path.sep)
417
        if os.path.isabs(path):
418
            if path_parts[:len(self._local_path_parts)] != \
419
                   self._local_path_parts:
420
                raise BadWebserverPath(path, self.test_dir)
421
            remote_path = '/'.join(path_parts[len(self._local_path_parts):])
422
        else:
423
            remote_path = '/'.join(path_parts)
424
425
        return self._http_base_url + remote_path
426
427
    def log(self, format, *args):
428
        """Capture Server log output."""
429
        self.logs.append(format % args)
430
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
431
    def setUp(self, backing_transport_server=None):
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
432
        """See bzrlib.transport.Server.setUp.
433
        
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
434
        :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 :).
435
            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.
436
            supported for HTTP.
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
437
        """
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
438
        # XXX: TODO: make the server back onto vfs_server rather than local
439
        # disk.
440
        assert backing_transport_server is None or \
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
441
            isinstance(backing_transport_server, local.LocalURLServer), \
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
442
            "HTTPServer currently assumes local transport, got %s" % \
443
            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 :)
444
        self._home_dir = os.getcwdu()
445
        self._local_path_parts = self._home_dir.split(os.path.sep)
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
446
        self._http_base_url = None
447
3111.1.6 by Vincent Ladeuil
Begin refactoring test_http.py into parameterized tests.
448
        # Create the server thread
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
449
        self._http_starting = threading.Lock()
450
        self._http_starting.acquire()
451
        self._http_thread = threading.Thread(target=self._http_start)
452
        self._http_thread.setDaemon(True)
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
453
        self._http_exception = None
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
454
        self._http_thread.start()
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
455
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
456
        # Wait for the server thread to start (i.e release the lock)
457
        self._http_starting.acquire()
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
458
459
        if self._http_exception is not None:
460
            exc_class, exc_value, exc_tb = self._http_exception
461
            raise exc_class, exc_value, exc_tb
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
462
        self._http_starting.release()
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
463
        self.logs = []
464
465
    def tearDown(self):
466
        """See bzrlib.transport.Server.tearDown."""
2825.1.1 by Vincent Ladeuil
Fix #140055 by properly closing the http and ftp test servers.
467
        self._httpd.server_close()
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
468
        self._http_running = False
469
        self._http_thread.join()
470
471
    def get_url(self):
472
        """See bzrlib.transport.Server.get_url."""
473
        return self._get_remote_url(self._home_dir)
474
475
    def get_bogus_url(self):
476
        """See bzrlib.transport.Server.get_bogus_url."""
477
        # this is chosen to try to prevent trouble with proxies, weird dns,
478
        # etc
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
479
        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 :)
480
481
482
class HttpServer_urllib(HttpServer):
483
    """Subclass of HttpServer that gives http+urllib urls.
484
485
    This is for use in testing: connections to this server will always go
486
    through urllib where possible.
487
    """
488
489
    # urls returned by this server should require the urllib client impl
490
    _url_protocol = 'http+urllib'
491
492
493
class HttpServer_PyCurl(HttpServer):
494
    """Subclass of HttpServer that gives http+pycurl urls.
495
496
    This is for use in testing: connections to this server will always go
497
    through pycurl where possible.
498
    """
499
500
    # We don't care about checking the pycurl availability as
501
    # this server will be required only when pycurl is present
502
503
    # urls returned by this server should require the pycurl client impl
504
    _url_protocol = 'http+pycurl'