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