/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2006-2010 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
3734.2.8 by Vincent Ladeuil
Catch spurious exceptions (python-2.6) when SocketServer is shut down.
23
import select
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
4731.2.9 by Vincent Ladeuil
Implement a new -Ethreads to better track the leaks.
33
from bzrlib import (
34
    tests,
35
    transport,
36
    )
5017.3.23 by Vincent Ladeuil
selftest -s bt.test_bzrdir passing
37
from bzrlib.tests import test_server
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
38
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 :)
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
3111.1.21 by Vincent Ladeuil
Add some comments.
49
    A TestingHTTPRequestHandler is instantiated for every request received by
50
    the associated server. Note that 'request' here is inherited from the base
51
    TCPServer class, for the HTTP server it is really a connection which itself
52
    will handle one or several HTTP requests.
2420.1.10 by Vincent Ladeuil
Doc fixes.
53
    """
3111.1.24 by Vincent Ladeuil
Cleanups.
54
    # Default protocol version
55
    protocol_version = 'HTTP/1.1'
56
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
57
    # The Message-like class used to parse the request headers
58
    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 :)
59
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
60
    def setup(self):
61
        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.
62
        self._cwd = self.server._home_dir
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
63
        tcs = self.server.test_case_server
64
        if tcs.protocol_version is not None:
65
            # If the test server forced a protocol version, use it
66
            self.protocol_version = tcs.protocol_version
67
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
68
    def log_message(self, format, *args):
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
69
        tcs = self.server.test_case_server
70
        tcs.log('webserver - %s - - [%s] %s "%s" "%s"',
71
                self.address_string(),
72
                self.log_date_time_string(),
73
                format % args,
3111.1.19 by Vincent Ladeuil
Merge back test_http_implementations.pc into test_http.py.
74
                self.headers.get('referer', '-'),
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
75
                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 :)
76
77
    def handle_one_request(self):
78
        """Handle a single HTTP request.
79
2831.6.1 by Vincent Ladeuil
Remove some more noise from test suite.
80
        We catch all socket errors occurring when the client close the
81
        connection early to avoid polluting the test results.
82
        """
83
        try:
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
84
            self._handle_one_request()
2831.6.1 by Vincent Ladeuil
Remove some more noise from test suite.
85
        except socket.error, e:
3111.1.24 by Vincent Ladeuil
Cleanups.
86
            # Any socket error should close the connection, but some errors are
87
            # 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.
88
            # results, so we raise only the others.
89
            self.close_connection = 1
90
            if (len(e.args) == 0
91
                or e.args[0] not in (errno.EPIPE, errno.ECONNRESET,
92
                                     errno.ECONNABORTED, errno.EBADF)):
2831.6.1 by Vincent Ladeuil
Remove some more noise from test suite.
93
                raise
94
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
95
    def _handle_one_request(self):
96
        SimpleHTTPServer.SimpleHTTPRequestHandler.handle_one_request(self)
97
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
98
    _range_regexp = re.compile(r'^(?P<start>\d+)-(?P<end>\d+)$')
99
    _tail_regexp = re.compile(r'^-(?P<tail>\d+)$')
100
101
    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
102
        """Parse the range header value and returns ranges and tail.
103
104
        RFC2616 14.35 says that syntactically invalid range
105
        specifiers MUST be ignored. In that case, we return 0 for
106
        tail and [] for ranges.
107
        """
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
108
        tail = 0
109
        ranges = []
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
110
        if not ranges_header.startswith('bytes='):
111
            # Syntactically invalid header
112
            return 0, []
113
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
114
        ranges_header = ranges_header[len('bytes='):]
115
        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
116
            # 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 :)
117
            range_match = self._range_regexp.match(range_str)
118
            if range_match is not None:
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
119
                start = int(range_match.group('start'))
120
                end = int(range_match.group('end'))
121
                if start > end:
122
                    # Syntactically invalid range
123
                    return 0, []
124
                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 :)
125
            else:
126
                tail_match = self._tail_regexp.match(range_str)
127
                if tail_match is not None:
128
                    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
129
                else:
130
                    # Syntactically invalid range
131
                    return 0, []
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
132
        return tail, ranges
133
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
134
    def _header_line_length(self, keyword, value):
135
        header_line = '%s: %s\r\n' % (keyword, value)
136
        return len(header_line)
137
3111.1.23 by Vincent Ladeuil
Make HTTP/1.1 the default implementation reveals one more bug.
138
    def send_head(self):
139
        """Overrides base implementation to work around a bug in python2.5."""
140
        path = self.translate_path(self.path)
141
        if os.path.isdir(path) and not self.path.endswith('/'):
142
            # redirect browser - doing basically what apache does when
143
            # DirectorySlash option is On which is quite common (braindead, but
144
            # common)
145
            self.send_response(301)
146
            self.send_header("Location", self.path + "/")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
147
            # 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.
148
            self.send_header('Content-Length', '0')
149
            self.end_headers()
150
            return None
151
152
        return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
153
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
154
    def send_range_content(self, file, start, length):
155
        file.seek(start)
156
        self.wfile.write(file.read(length))
157
158
    def get_single_range(self, file, file_size, start, end):
159
        self.send_response(206)
160
        length = end - start + 1
161
        self.send_header('Accept-Ranges', 'bytes')
162
        self.send_header("Content-Length", "%d" % length)
163
164
        self.send_header("Content-Type", 'application/octet-stream')
165
        self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
166
                                                              end,
167
                                                              file_size))
168
        self.end_headers()
169
        self.send_range_content(file, start, length)
170
171
    def get_multiple_ranges(self, file, file_size, ranges):
172
        self.send_response(206)
173
        self.send_header('Accept-Ranges', 'bytes')
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
174
        boundary = '%d' % random.randint(0,0x7FFFFFFF)
175
        self.send_header('Content-Type',
176
                         'multipart/byteranges; boundary=%s' % boundary)
177
        boundary_line = '--%s\r\n' % boundary
178
        # Calculate the Content-Length
179
        content_length = 0
180
        for (start, end) in ranges:
181
            content_length += len(boundary_line)
182
            content_length += self._header_line_length(
183
                'Content-type', 'application/octet-stream')
184
            content_length += self._header_line_length(
185
                'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
186
            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).
187
            content_length += end - start + 1
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
188
        content_length += len(boundary_line)
189
        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 :)
190
        self.end_headers()
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
191
192
        # 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 :)
193
        for (start, end) in ranges:
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
194
            self.wfile.write(boundary_line)
195
            self.send_header('Content-type', 'application/octet-stream')
196
            self.send_header('Content-Range', 'bytes %d-%d/%d'
197
                             % (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 :)
198
            self.end_headers()
199
            self.send_range_content(file, start, end - start + 1)
3059.2.12 by Vincent Ladeuil
Spiv review feedback.
200
        # Final boundary
3111.1.28 by Vincent Ladeuil
Fix the multi-ranges http server and add tests.
201
        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 :)
202
203
    def do_GET(self):
204
        """Serve a GET request.
205
206
        Handles the Range header.
207
        """
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
208
        # Update statistics
209
        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 :)
210
211
        path = self.translate_path(self.path)
212
        ranges_header_value = self.headers.get('Range')
213
        if ranges_header_value is None or os.path.isdir(path):
214
            # Let the mother class handle most cases
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
215
            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 :)
216
217
        try:
218
            # Always read in binary mode. Opening files in text
219
            # mode may cause newline translations, making the
220
            # actual size of the content transmitted *less* than
221
            # the content-length!
222
            file = open(path, 'rb')
223
        except IOError:
224
            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 :)
225
            return
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
226
227
        file_size = os.fstat(file.fileno())[6]
228
        tail, ranges = self.parse_ranges(ranges_header_value)
229
        # Normalize tail into ranges
230
        if tail != 0:
231
            ranges.append((file_size - tail, file_size))
232
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
233
        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 :)
234
        if len(ranges) == 0:
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
235
            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 :)
236
        else:
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
237
            def check_range(range_specifier):
238
                start, end = range_specifier
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
239
                # RFC2616 14.35, ranges are invalid if start >= file_size
240
                if start >= file_size:
241
                    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
242
                    return 0, 0
243
                # RFC2616 14.35, end values should be truncated
244
                # to file_size -1 if they exceed it
245
                end = min(end, file_size - 1)
246
                return start, end
247
248
            ranges = map(check_range, ranges)
249
2182.2.2 by v.ladeuil+lp at free
Thanks again to Aaron, the http server RFC2616 compliance
250
        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
251
            # RFC2616 14.16 and 14.35 says that when a server
252
            # encounters unsatisfiable range specifiers, it
253
            # 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 :)
254
            file.close()
2182.2.1 by v.ladeuil+lp at free
Aaron was right. Thanks to him, the http server RFC2616 compliance
255
            # FIXME: We SHOULD send a Content-Range header too,
256
            # but the implementation of send_error does not
257
            # 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 :)
258
            self.send_error(416, "Requested range not satisfiable")
259
            return
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
260
261
        if len(ranges) == 1:
262
            (start, end) = ranges[0]
263
            self.get_single_range(file, file_size, start, end)
264
        else:
265
            self.get_multiple_ranges(file, file_size, ranges)
266
        file.close()
267
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
268
    def translate_path(self, path):
269
        """Translate a /-separated PATH to the local filename syntax.
270
271
        If the server requires it, proxy the path before the usual translation
272
        """
273
        if self.server.test_case_server.proxy_requests:
274
            # We need to act as a proxy and accept absolute urls,
275
            # which SimpleHTTPRequestHandler (parent) is not
276
            # ready for. So we just drop the protocol://host:port
277
            # part in front of the request-url (because we know
278
            # we would not forward the request to *another*
279
            # proxy).
280
281
            # So we do what SimpleHTTPRequestHandler.translate_path
282
            # do beginning with python 2.4.3: abandon query
283
            # parameters, scheme, host port, etc (which ensure we
284
            # provide the right behaviour on all python versions).
285
            path = urlparse.urlparse(path)[2]
286
            # And now, we can apply *our* trick to proxy files
287
            path += '-proxied'
288
289
        return self._translate_path(path)
290
291
    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.
292
        """Translate a /-separated PATH to the local filename syntax.
293
3221.9.5 by Ian Clatworthy
some tweaks from abentley's earlier review feedback
294
        Note that we're translating http URLs here, not file URLs.
295
        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.
296
        Components that mean special things to the local file system
297
        (e.g. drive or directory names) are ignored.  (XXX They should
298
        probably be diagnosed.)
299
300
        Override from python standard library to stop it calling os.getcwd()
301
        """
302
        # abandon query parameters
303
        path = urlparse.urlparse(path)[2]
304
        path = posixpath.normpath(urllib.unquote(path))
3221.9.4 by Ian Clatworthy
fix failing unicode_paths test
305
        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.
306
        words = path.split('/')
307
        words = filter(None, words)
308
        path = self._cwd
3221.9.5 by Ian Clatworthy
some tweaks from abentley's earlier review feedback
309
        for num, word in enumerate(words):
310
            if num == 0:
311
                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.
312
            head, word = os.path.split(word)
313
            if word in (os.curdir, os.pardir): continue
314
            path = os.path.join(path, word)
315
        return path
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
316
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
317
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
318
class TestingHTTPServerMixin:
319
320
    def __init__(self, test_case_server):
2164.2.28 by Vincent Ladeuil
TestingHTTPServer.test_case_server renamed from test_case to avoid confusions.
321
        # 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
322
        # tests and the server (or the request handler and the
323
        # server), allowing dynamic behaviors to be defined from
324
        # the tests cases.
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
325
        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.
326
        self._home_dir = test_case_server._home_dir
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
327
        self.serving = None
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
328
        self.is_shut_down = threading.Event()
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
329
        # We collect the sockets/threads used by the clients so we can
330
        # close/join them when shutting down
331
        self.clients = []
332
333
    def get_request (self):
334
        """Get the request and client address from the socket.
335
        """
336
        sock, addr = self._get_request()
337
        self.clients.append([sock, addr])
338
        return sock, addr
339
340
    def verify_request(self, request, client_address):
341
        """Verify the request.
342
343
        Return True if we should proceed with this request, False if we should
344
        not even touch a single byte in the socket !
345
        """
346
        return self.serving is not None and self.serving.isSet()
347
348
    def handle_request(self):
349
        request, client_address = self.get_request()
350
        try:
351
            if self.verify_request(request, client_address):
352
                self.process_request(request, client_address)
353
        except:
354
            if self.serving is not None and self.serving.isSet():
355
                self.handle_error(request, client_address)
356
            else:
357
                # Exceptions raised while we shut down are just noise, but feel
358
                # free to put a breakpoint here if you suspect something
359
                # else. Such an example is the SSL handshake: it's automatic
360
                # once we start processing the request but the last connection
361
                # will close immediately and will not be able to correctly
362
                # reply.
363
                pass
364
            self.close_request(request)
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
365
4731.2.7 by Vincent Ladeuil
Refactor compatibility code for python-2.[45].
366
    def server_bind(self):
367
        # The following has been fixed in 2.5 so we need to provide it for
368
        # older python versions.
369
        if sys.version < (2, 5):
370
            self.server_address = self.socket.getsockname()
371
4731.2.13 by Vincent Ladeuil
We're back at full test suite passing under all circumstances.
372
    def serve(self, started):
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
373
        self.serving  = threading.Event()
374
        self.serving.set()
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
375
        self.is_shut_down.clear()
4731.2.11 by Vincent Ladeuil
More thread leak tracking help.
376
        if 'threads' in tests.selftest_debug_flags:
377
            print 'Starting %r' % (self.server_address,)
4731.2.13 by Vincent Ladeuil
We're back at full test suite passing under all circumstances.
378
        # We are listening and ready to accept connections
379
        started.set()
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
380
        while self.serving.isSet():
4731.2.14 by Vincent Ladeuil
We don't need timeout here.
381
            if 'threads' in tests.selftest_debug_flags:
382
                print 'Accepting on %r' % (self.server_address,)
383
            # Really a connection but the python framework is generic and
384
            # call them requests
385
            self.handle_request()
4731.2.11 by Vincent Ladeuil
More thread leak tracking help.
386
        if 'threads' in tests.selftest_debug_flags:
387
            print 'Closing  %r' % (self.server_address,)
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
388
        # Let's close the listening socket
389
        self.server_close()
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
390
        if 'threads' in tests.selftest_debug_flags:
391
            print 'Closed   %r' % (self.server_address,)
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
392
        self.is_shut_down.set()
393
4731.3.2 by Vincent Ladeuil
Reduce patch for review purposes.
394
    def connect_socket(self):
4731.3.3 by Vincent Ladeuil
Fixed as per Andrew's review.
395
        err = socket.error('getaddrinfo returns an empty list')
4731.3.2 by Vincent Ladeuil
Reduce patch for review purposes.
396
        for res in socket.getaddrinfo(*self.server_address):
397
            af, socktype, proto, canonname, sa = res
398
            sock = None
399
            try:
400
                sock = socket.socket(af, socktype, proto)
401
                sock.connect(sa)
402
                return sock
403
4731.3.3 by Vincent Ladeuil
Fixed as per Andrew's review.
404
            except socket.error, err:
405
                # 'err' is now the most recent error
4731.3.2 by Vincent Ladeuil
Reduce patch for review purposes.
406
                if sock is not None:
407
                    sock.close()
4731.3.3 by Vincent Ladeuil
Fixed as per Andrew's review.
408
        raise err
4731.3.2 by Vincent Ladeuil
Reduce patch for review purposes.
409
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
410
    def join_thread(self, thread, timeout=2):
411
        thread.join(timeout)
412
        if thread.isAlive():
413
            # The timeout expired without joining the thread, the thread is
414
            # therefore stucked and that's a failure as far as the test is
415
            # concerned. We used to hang here.
416
            raise AssertionError('thread %s hung' % (thread.name,))
417
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
418
    def shutdown(self):
419
        """Stops the serve() loop.
420
421
        Blocks until the loop has finished. This must be called while serve()
422
        is running in another thread, or it will deadlock.
423
        """
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
424
        if self.serving is None:
425
            # If the server wasn't properly started, there is nothing to
426
            # shutdown.
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
427
            return
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
428
        # As soon as we stop serving, no more connection are accepted except
429
        # one to get out of the blocking listen.
430
        self.serving.clear()
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
431
        # The server is listening for a last connection, let's give it:
4731.2.13 by Vincent Ladeuil
We're back at full test suite passing under all circumstances.
432
        last_conn = None
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
433
        try:
4731.2.18 by Vincent Ladeuil
Tweak some more but we now hang in a new way on BSD variants :-/
434
            last_conn = self.connect_socket()
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
435
        except socket.error, e:
436
            # But ignore connection errors as the point is to unblock the
437
            # server thread, it may happen that it's not blocked or even not
438
            # started (when something went wrong during test case setup
439
            # leading to self.setUp() *not* being called but self.tearDown()
440
            # still being called)
441
            pass
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
442
        # We don't have to wait for the server to shut down to start shutting
4731.2.14 by Vincent Ladeuil
We don't need timeout here.
443
        # down the clients, so let's start now.
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
444
        for c in self.clients:
445
            self.shutdown_client(c)
446
        self.clients = []
447
        # Now we wait for the thread running serve() to finish
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
448
        self.is_shut_down.wait()
4731.2.13 by Vincent Ladeuil
We're back at full test suite passing under all circumstances.
449
        if last_conn is not None:
450
            # Close the last connection without trying to use it. The server
451
            # will not process a single byte on that socket to avoid
452
            # complications (SSL starts with a handshake for example).
453
            last_conn.close()
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
454
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
455
    def shutdown_client(self, client):
456
        sock, addr = client[:2]
457
        self.shutdown_client_socket(sock)
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
458
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
459
    def shutdown_client_socket(self, sock):
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
460
        """Properly shutdown a client socket.
461
462
        Under some circumstances (as in bug #383920), we need to force the
463
        shutdown as python delays it until gc occur otherwise and the client
464
        may hang.
465
466
        This should be called only when no other thread is trying to use the
467
        socket.
468
        """
469
        try:
470
            # The request process has been completed, the thread is about to
471
            # die, let's shutdown the socket if we can.
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
472
            sock.shutdown(socket.SHUT_RDWR)
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
473
        except (socket.error, select.error), e:
474
            if e[0] in (errno.EBADF, errno.ENOTCONN):
475
                # Right, the socket is already down
476
                pass
477
            else:
5247.2.5 by Vincent Ladeuil
Some cleanups.
478
                print 'exception in shutdown_client_socket: %r' % (e,)
4731.2.3 by Vincent Ladeuil
Reduce the leaking http tests from ~200 to ~5.
479
                raise
480
481
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
482
class TestingHTTPServer(TestingHTTPServerMixin, SocketServer.TCPServer):
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
483
3111.1.30 by Vincent Ladeuil
Update NEWS. Some cosmetic changes.
484
    def __init__(self, server_address, request_handler_class,
485
                 test_case_server):
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
486
        TestingHTTPServerMixin.__init__(self, test_case_server)
487
        SocketServer.TCPServer.__init__(self, server_address,
488
                                        request_handler_class)
489
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
490
    def _get_request (self):
491
        return SocketServer.TCPServer.get_request(self)
492
4731.3.1 by Vincent Ladeuil
Fix python-2.4 compatibility.
493
    def server_bind(self):
494
        SocketServer.TCPServer.server_bind(self)
4731.2.7 by Vincent Ladeuil
Refactor compatibility code for python-2.[45].
495
        TestingHTTPServerMixin.server_bind(self)
4731.3.1 by Vincent Ladeuil
Fix python-2.4 compatibility.
496
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
497
4731.2.2 by Vincent Ladeuil
Cleanup and refactor the server shutdown.
498
class TestingThreadingHTTPServer(TestingHTTPServerMixin,
499
                                 SocketServer.ThreadingTCPServer,
500
                                 ):
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
501
    """A threading HTTP test server for HTTP 1.1.
502
503
    Since tests can initiate several concurrent connections to the same http
504
    server, we need an independent connection for each of them. We achieve that
505
    by spawning a new thread for each connection.
506
    """
507
3111.1.30 by Vincent Ladeuil
Update NEWS. Some cosmetic changes.
508
    def __init__(self, server_address, request_handler_class,
509
                 test_case_server):
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
510
        TestingHTTPServerMixin.__init__(self, test_case_server)
511
        SocketServer.ThreadingTCPServer.__init__(self, server_address,
512
                                                 request_handler_class)
3111.1.3 by Vincent Ladeuil
Rework http test servers classes. Both 1.0 and 1.1 passing tests (1.1 forced manually).
513
        # Decides how threads will act upon termination of the main
514
        # process. This is prophylactic as we should not leave the threads
515
        # lying around.
3111.1.22 by Vincent Ladeuil
Rework TestingHTTPServer classes, fix test bug.
516
        self.daemon_threads = True
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
517
518
    def _get_request (self):
519
        return SocketServer.ThreadingTCPServer.get_request(self)
520
521
    def process_request_thread(self, started, request, client_address):
4731.2.13 by Vincent Ladeuil
We're back at full test suite passing under all circumstances.
522
        if 'threads' in tests.selftest_debug_flags:
523
            print 'Processing: %s' % (threading.currentThread().name,)
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
524
        started.set()
4731.2.8 by Vincent Ladeuil
Collect and shutdown clients for SmartTCPServer_for_testing.
525
        SocketServer.ThreadingTCPServer.process_request_thread(
526
            self, request, client_address)
527
        # Shutdown the socket as soon as possible, the thread will be joined
528
        # later if needed during server shutdown thread.
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
529
        self.shutdown_client_socket(request)
530
531
    def process_request(self, request, client_address):
532
        """Start a new thread to process the request."""
533
        client = self.clients.pop()
534
        started = threading.Event()
535
        t = threading.Thread(target = self.process_request_thread,
536
                             args = (started, request, client_address))
537
        t.name = '%s -> %s' % (client_address, self.server_address)
538
        client.append(t)
539
        self.clients.append(client)
540
        if self.daemon_threads:
541
            t.setDaemon (1)
542
        t.start()
543
        started.wait()
544
545
    def shutdown_client(self, client):
546
        TestingHTTPServerMixin.shutdown_client(self, client)
547
        if len(client) == 3:
548
            # The thread has been created only if the request is processed but
549
            # after the connection is inited. This could happne when the server
550
            # is shut down.
551
            sock, addr, thread = client
4731.2.18 by Vincent Ladeuil
Tweak some more but we now hang in a new way on BSD variants :-/
552
            if 'threads' in tests.selftest_debug_flags:
553
                print 'Try    joining: %s' % (thread.name,)
554
            self.join_thread(thread)
4512.1.2 by Vincent Ladeuil
lifeless said: try harder :)
555
4731.3.1 by Vincent Ladeuil
Fix python-2.4 compatibility.
556
    def server_bind(self):
557
        SocketServer.ThreadingTCPServer.server_bind(self)
4731.2.7 by Vincent Ladeuil
Refactor compatibility code for python-2.[45].
558
        TestingHTTPServerMixin.server_bind(self)
4731.3.1 by Vincent Ladeuil
Fix python-2.4 compatibility.
559
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
560
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
561
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 :)
562
    """A test server for http transports.
563
564
    Subclasses can provide a specific request handler.
565
    """
566
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
567
    # The real servers depending on the protocol
568
    http_server_class = {'HTTP/1.0': TestingHTTPServer,
569
                         'HTTP/1.1': TestingThreadingHTTPServer,
570
                         }
571
2420.1.9 by Vincent Ladeuil
Refactor proxy and auth test classes. Tests failing for digest auth.
572
    # Whether or not we proxy the requests (see
573
    # TestingHTTPRequestHandler.translate_path).
574
    proxy_requests = False
575
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
576
    # used to form the url that connects to this server
577
    _url_protocol = 'http'
578
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
579
    def __init__(self, request_handler=TestingHTTPRequestHandler,
580
                 protocol_version=None):
581
        """Constructor.
582
583
        :param request_handler: a class that will be instantiated to handle an
584
            http connection (one or several requests).
585
586
        :param protocol_version: if specified, will override the protocol
587
            version of the request handler.
588
        """
3111.1.2 by Vincent Ladeuil
Preparatory cleanup.
589
        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 :)
590
        self.request_handler = request_handler
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
591
        self.host = 'localhost'
592
        self.port = 0
593
        self._httpd = None
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
594
        self.protocol_version = protocol_version
3052.3.2 by Vincent Ladeuil
Add tests and fix trivial bugs and other typos.
595
        # Allows tests to verify number of GET requests issued
596
        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 :)
597
2929.3.19 by Vincent Ladeuil
Fix 1.1 related bugs in HTTP server, add HTTPS passing tests (by temporarily disabling pycurl certificate verification).
598
    def create_httpd(self, serv_cls, rhandler_cls):
599
        return serv_cls((self.host, self.port), self.request_handler, self)
2929.3.12 by Vincent Ladeuil
Implement an https server passing the same tests than http. Except
600
3734.2.8 by Vincent Ladeuil
Catch spurious exceptions (python-2.6) when SocketServer is shut down.
601
    def __repr__(self):
602
        return "%s(%s:%s)" % \
603
            (self.__class__.__name__, self.host, self.port)
604
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
605
    def _get_httpd(self):
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
606
        if self._httpd is None:
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
607
            rhandler = self.request_handler
3111.1.21 by Vincent Ladeuil
Add some comments.
608
            # Depending on the protocol version, we will create the approriate
609
            # server
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
610
            if self.protocol_version is None:
3111.1.21 by Vincent Ladeuil
Add some comments.
611
                # Use the request handler one
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
612
                proto_vers = rhandler.protocol_version
613
            else:
3111.1.21 by Vincent Ladeuil
Add some comments.
614
                # Use our own, it will be used to override the request handler
615
                # one too.
3111.1.15 by Vincent Ladeuil
Provide a way to specify the protocol version at the server layer.
616
                proto_vers = self.protocol_version
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
617
            # Create the appropriate server for the required protocol
618
            serv_cls = self.http_server_class.get(proto_vers, None)
619
            if serv_cls is None:
620
                raise httplib.UnknownProtocol(proto_vers)
621
            else:
2929.3.19 by Vincent Ladeuil
Fix 1.1 related bugs in HTTP server, add HTTPS passing tests (by temporarily disabling pycurl certificate verification).
622
                self._httpd = self.create_httpd(serv_cls, rhandler)
5247.1.1 by Vincent Ladeuil
Merge previous attempt into current trunk
623
            # Ensure we get the right port and an updated host if needed
624
            self.host, self.port = self._httpd.server_address
2164.2.13 by v.ladeuil+lp at free
Add tests for redirection. Preserve transport decorations.
625
        return self._httpd
2004.1.28 by v.ladeuil+lp at free
Merge bzr.dev. Including http modifications by "smart" related code
626
5247.2.6 by Vincent Ladeuil
Clarify some iable/method names in the test servers.
627
    def run_server(self, started):
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
628
        """Server thread main entry point. """
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
629
        server = self._get_httpd()
630
        self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
631
                                               self.host, self.port)
632
        server.serve(started)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
633
634
    def _get_remote_url(self, path):
635
        path_parts = path.split(os.path.sep)
636
        if os.path.isabs(path):
637
            if path_parts[:len(self._local_path_parts)] != \
638
                   self._local_path_parts:
639
                raise BadWebserverPath(path, self.test_dir)
640
            remote_path = '/'.join(path_parts[len(self._local_path_parts):])
641
        else:
642
            remote_path = '/'.join(path_parts)
643
644
        return self._http_base_url + remote_path
645
646
    def log(self, format, *args):
647
        """Capture Server log output."""
648
        self.logs.append(format % args)
649
4934.3.3 by Martin Pool
Rename Server.setUp to Server.start_server
650
    def start_server(self, backing_transport_server=None):
651
        """See bzrlib.transport.Server.start_server.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
652
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
653
        :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 :).
654
            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.
655
            supported for HTTP.
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
656
        """
2381.1.2 by Robert Collins
Fixup the test changes made for hpss to be clean and self contained.
657
        # XXX: TODO: make the server back onto vfs_server rather than local
658
        # disk.
4731.2.1 by Vincent Ladeuil
Don't use shutdown() to stop http servers.
659
        if not (backing_transport_server is None
5017.3.23 by Vincent Ladeuil
selftest -s bt.test_bzrdir passing
660
                or isinstance(backing_transport_server,
661
                              test_server.LocalURLServer)):
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
662
            raise AssertionError(
4731.2.1 by Vincent Ladeuil
Don't use shutdown() to stop http servers.
663
                "HTTPServer currently assumes local transport, got %s" %
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
664
                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 :)
665
        self._home_dir = os.getcwdu()
666
        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.
667
        self._http_base_url = None
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
668
        self.logs = []
3111.1.4 by Vincent Ladeuil
Select the server depending on the request handler protocol. Add tests.
669
3111.1.6 by Vincent Ladeuil
Begin refactoring test_http.py into parameterized tests.
670
        # Create the server thread
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
671
        started = threading.Event()
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
672
        self._http_thread = test_server.ThreadWithException(
5247.2.6 by Vincent Ladeuil
Clarify some iable/method names in the test servers.
673
            event=started, target=self.run_server, args=(started,))
2167.3.5 by v.ladeuil+lp at free
Tests for proxies, covering #74759.
674
        self._http_thread.start()
2167.3.6 by v.ladeuil+lp at free
Take John's comments into account and add more tests.
675
        # Wait for the server thread to start (i.e release the lock)
4731.2.12 by Vincent Ladeuil
Start adding a more precise synchronization between the various test threads.
676
        started.wait()
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
677
        if self._httpd is None:
678
            if 'threads' in tests.selftest_debug_flags:
679
                print 'Server %s:% start failed ' % (self.host, self.port)
680
        else:
681
            self._http_thread.name = self._http_base_url
682
            if 'threads' in tests.selftest_debug_flags:
683
                print 'Thread started: %s' % (self._http_thread.name,)
684
685
        # If an exception occured during the server start, it will get raised
686
        self._http_thread.join(timeout=0)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
687
4934.3.1 by Martin Pool
Rename Server.tearDown to .stop_server
688
    def stop_server(self):
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
689
        """See bzrlib.transport.Server.tearDown."""
5247.2.4 by Vincent Ladeuil
Add an event to ThreadWithException that can be shared with the calling thread.
690
        if self._httpd is not None:
691
            # The server has been started successfully, shut it down now
692
            self._httpd.shutdown()
693
            if 'threads' in tests.selftest_debug_flags:
694
                print 'Try    joining: %s' % (self._http_thread.name,)
695
            self._httpd.join_thread(self._http_thread)
696
            if 'threads' in tests.selftest_debug_flags:
697
                print 'Thread  joined: %s' % (self._http_thread.name,)
2004.1.25 by v.ladeuil+lp at free
Shuffle http related test code. Hopefully it ends up at the right place :)
698
699
    def get_url(self):
700
        """See bzrlib.transport.Server.get_url."""
701
        return self._get_remote_url(self._home_dir)
702
703
    def get_bogus_url(self):
704
        """See bzrlib.transport.Server.get_bogus_url."""
705
        # this is chosen to try to prevent trouble with proxies, weird dns,
706
        # etc
2929.3.10 by Vincent Ladeuil
Add a fake https server and test facilities.
707
        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 :)
708
709
710
class HttpServer_urllib(HttpServer):
711
    """Subclass of HttpServer that gives http+urllib urls.
712
713
    This is for use in testing: connections to this server will always go
714
    through urllib where possible.
715
    """
716
717
    # urls returned by this server should require the urllib client impl
718
    _url_protocol = 'http+urllib'
719
720
721
class HttpServer_PyCurl(HttpServer):
722
    """Subclass of HttpServer that gives http+pycurl urls.
723
724
    This is for use in testing: connections to this server will always go
725
    through pycurl where possible.
726
    """
727
728
    # We don't care about checking the pycurl availability as
729
    # this server will be required only when pycurl is present
730
731
    # urls returned by this server should require the pycurl client impl
732
    _url_protocol = 'http+pycurl'