43
46
class TestingHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
44
47
"""Handles one request.
46
A TestingHTTPRequestHandler is instantiated for every request received by
47
the associated server. Note that 'request' here is inherited from the base
48
TCPServer class, for the HTTP server it is really a connection which itself
49
will handle one or several HTTP requests.
49
A TestingHTTPRequestHandler is instantiated for every request
50
received by the associated server.
51
# Default protocol version
52
protocol_version = 'HTTP/1.1'
54
52
# The Message-like class used to parse the request headers
55
53
MessageClass = httplib.HTTPMessage
58
SimpleHTTPServer.SimpleHTTPRequestHandler.setup(self)
59
self._cwd = self.server._home_dir
60
tcs = self.server.test_case_server
61
if tcs.protocol_version is not None:
62
# If the test server forced a protocol version, use it
63
self.protocol_version = tcs.protocol_version
65
55
def log_message(self, format, *args):
66
56
tcs = self.server.test_case_server
67
57
tcs.log('webserver - %s - - [%s] %s "%s" "%s"',
68
58
self.address_string(),
69
59
self.log_date_time_string(),
71
self.headers.get('referer', '-'),
61
self.headers.get('referrer', '-'),
72
62
self.headers.get('user-agent', '-'))
74
64
def handle_one_request(self):
165
133
def get_multiple_ranges(self, file, file_size, ranges):
166
134
self.send_response(206)
167
135
self.send_header('Accept-Ranges', 'bytes')
168
boundary = '%d' % random.randint(0,0x7FFFFFFF)
169
self.send_header('Content-Type',
170
'multipart/byteranges; boundary=%s' % boundary)
171
boundary_line = '--%s\r\n' % boundary
172
# Calculate the Content-Length
174
for (start, end) in ranges:
175
content_length += len(boundary_line)
176
content_length += self._header_line_length(
177
'Content-type', 'application/octet-stream')
178
content_length += self._header_line_length(
179
'Content-Range', 'bytes %d-%d/%d' % (start, end, file_size))
180
content_length += len('\r\n') # end headers
181
content_length += end - start + 1
182
content_length += len(boundary_line)
183
self.send_header('Content-length', content_length)
136
boundary = "%d" % random.randint(0,0x7FFFFFFF)
137
self.send_header("Content-Type",
138
"multipart/byteranges; boundary=%s" % boundary)
184
139
self.end_headers()
186
# Send the multipart body
187
140
for (start, end) in ranges:
188
self.wfile.write(boundary_line)
189
self.send_header('Content-type', 'application/octet-stream')
190
self.send_header('Content-Range', 'bytes %d-%d/%d'
191
% (start, end, file_size))
141
self.wfile.write("--%s\r\n" % boundary)
142
self.send_header("Content-type", 'application/octet-stream')
143
self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
192
146
self.end_headers()
193
147
self.send_range_content(file, start, end - start + 1)
195
self.wfile.write(boundary_line)
149
self.wfile.write("--%s\r\n" % boundary)
197
151
def do_GET(self):
198
152
"""Serve a GET request.
283
237
return self._translate_path(path)
285
239
def _translate_path(self, path):
286
"""Translate a /-separated PATH to the local filename syntax.
288
Note that we're translating http URLs here, not file URLs.
289
The URL root location is the server's startup directory.
290
Components that mean special things to the local file system
291
(e.g. drive or directory names) are ignored. (XXX They should
292
probably be diagnosed.)
294
Override from python standard library to stop it calling os.getcwd()
296
# abandon query parameters
297
path = urlparse.urlparse(path)[2]
298
path = posixpath.normpath(urllib.unquote(path))
299
path = path.decode('utf-8')
300
words = path.split('/')
301
words = filter(None, words)
303
for num, word in enumerate(words):
240
return SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(
243
if sys.platform == 'win32':
244
# On win32 you cannot access non-ascii filenames without
245
# decoding them into unicode first.
246
# However, under Linux, you can access bytestream paths
247
# without any problems. If this function was always active
248
# it would probably break tests when LANG=C was set
249
def _translate_path(self, path):
250
"""Translate a /-separated PATH to the local filename syntax.
252
For bzr, all url paths are considered to be utf8 paths.
253
On Linux, you can access these paths directly over the bytestream
254
request, but on win32, you must decode them, and access them
257
# abandon query parameters
258
path = urlparse.urlparse(path)[2]
259
path = posixpath.normpath(urllib.unquote(path))
260
path = path.decode('utf-8')
261
words = path.split('/')
262
words = filter(None, words)
305
265
drive, word = os.path.splitdrive(word)
306
head, word = os.path.split(word)
307
if word in (os.curdir, os.pardir): continue
308
path = os.path.join(path, word)
312
class TestingHTTPServerMixin:
314
def __init__(self, test_case_server):
266
head, word = os.path.split(word)
267
if word in (os.curdir, os.pardir): continue
268
path = os.path.join(path, word)
272
class TestingHTTPServerWrapper(object):
273
"""Isolate the wrapper itself to make the server use transparent.
275
Daughter classes can override any method and/or directly call the _server
279
def __init__(self, server_class, test_case_server,
280
server_address, request_handler_class):
281
self._server = server_class(server_address, request_handler_class)
315
282
# test_case_server can be used to communicate between the
316
283
# tests and the server (or the request handler and the
317
284
# server), allowing dynamic behaviors to be defined from
318
285
# the tests cases.
319
self.test_case_server = test_case_server
320
self._home_dir = test_case_server._home_dir
322
def stop_server(self):
286
self._server.test_case_server = test_case_server
288
def __getattr__(self, name):
289
return getattr(self._server, name)
291
def server_bind(self):
292
"""Override server_bind to store the server name."""
293
self._server.server_bind()
294
host, port = self._server.socket.getsockname()[:2]
295
self._server.server_name = socket.getfqdn(host)
296
self._server.server_port = port
298
def server_close(self):
323
299
"""Called to clean-up the server.
325
301
Since the server may be (surely is, even) in a blocking listen, we
326
302
shutdown its socket before closing it.
328
304
# Note that is this executed as part of the implicit tear down in the
329
305
# main thread while the server runs in its own thread. The clean way
330
# to tear down the server is to instruct him to stop accepting
331
# connections and wait for the current connection(s) to end
332
# naturally. To end the connection naturally, the http transports
333
# should close their socket when they do not need to talk to the
334
# server anymore. This happens naturally during the garbage collection
335
# phase of the test transport objetcs (the server clients), so we
336
# don't have to worry about them. So, for the server, we must tear
337
# down here, from the main thread, when the test have ended. Note
338
# that since the server is in a blocking operation and since python
339
# use select internally, shutting down the socket is reliable and
342
self.socket.shutdown(socket.SHUT_RDWR)
343
except socket.error, e:
344
# WSAENOTCONN (10057) 'Socket is not connected' is harmless on
345
# windows (occurs before the first connection attempt
348
# 'Socket is not connected' can also occur on OSX, with a
349
# "regular" ENOTCONN (when something went wrong during test case
350
# setup leading to self.setUp() *not* being called but
351
# self.stop_server() still being called -- vila20081106
352
if not len(e.args) or e.args[0] not in (errno.ENOTCONN, 10057):
306
# to tear down the server will be to instruct him to stop accepting
307
# connections and wait for the current connection to end naturally. To
308
# end the connection naturally, the http transports should close their
309
# socket when they do not need to talk to the server anymore. We
310
# don't want to impose such a constraint on the http transports (and
311
# we can't anyway ;). So we must tear down here, from the main thread,
312
# when the test have ended. Note that since the server is in a
313
# blocking operation and since python use select internally, shutting
314
# down the socket is reliable and relatively clean.
315
self._server.socket.shutdown(socket.SHUT_RDWR)
354
316
# Let the server properly close the socket
358
class TestingHTTPServer(SocketServer.TCPServer, TestingHTTPServerMixin):
360
def __init__(self, server_address, request_handler_class,
362
TestingHTTPServerMixin.__init__(self, test_case_server)
363
SocketServer.TCPServer.__init__(self, server_address,
364
request_handler_class)
367
class TestingThreadingHTTPServer(SocketServer.ThreadingTCPServer,
368
TestingHTTPServerMixin):
317
self._server.server_close()
319
class TestingHTTPServer(TestingHTTPServerWrapper):
321
def __init__(self, server_address, request_handler_class, test_case_server):
322
super(TestingHTTPServer, self).__init__(
323
SocketServer.TCPServer, test_case_server,
324
server_address, request_handler_class)
327
class TestingThreadingHTTPServer(TestingHTTPServerWrapper):
369
328
"""A threading HTTP test server for HTTP 1.1.
371
330
Since tests can initiate several concurrent connections to the same http
373
332
by spawning a new thread for each connection.
376
def __init__(self, server_address, request_handler_class,
378
TestingHTTPServerMixin.__init__(self, test_case_server)
379
SocketServer.ThreadingTCPServer.__init__(self, server_address,
380
request_handler_class)
335
def __init__(self, server_address, request_handler_class, test_case_server):
336
super(TestingThreadingHTTPServer, self).__init__(
337
SocketServer.ThreadingTCPServer, test_case_server,
338
server_address, request_handler_class)
381
339
# Decides how threads will act upon termination of the main
382
340
# process. This is prophylactic as we should not leave the threads
384
self.daemon_threads = True
386
def process_request_thread(self, request, client_address):
387
SocketServer.ThreadingTCPServer.process_request_thread(
388
self, request, client_address)
389
# Under some circumstances (as in bug #383920), we need to force the
390
# shutdown as python delays it until gc occur otherwise and the client
393
# The request process has been completed, the thread is about to
394
# die, let's shutdown the socket if we can.
395
request.shutdown(socket.SHUT_RDWR)
396
except (socket.error, select.error), e:
397
if e[0] in (errno.EBADF, errno.ENOTCONN):
398
# Right, the socket is already down
342
self._server.daemon_threads = True
404
345
class HttpServer(transport.Server):
419
360
# used to form the url that connects to this server
420
361
_url_protocol = 'http'
422
def __init__(self, request_handler=TestingHTTPRequestHandler,
423
protocol_version=None):
426
:param request_handler: a class that will be instantiated to handle an
427
http connection (one or several requests).
429
:param protocol_version: if specified, will override the protocol
430
version of the request handler.
363
# Subclasses can provide a specific request handler
364
def __init__(self, request_handler=TestingHTTPRequestHandler):
432
365
transport.Server.__init__(self)
433
366
self.request_handler = request_handler
434
367
self.host = 'localhost'
436
369
self._httpd = None
437
self.protocol_version = protocol_version
438
370
# Allows tests to verify number of GET requests issued
439
371
self.GET_request_nb = 0
441
def create_httpd(self, serv_cls, rhandler_cls):
442
return serv_cls((self.host, self.port), self.request_handler, self)
445
return "%s(%s:%s)" % \
446
(self.__class__.__name__, self.host, self.port)
448
373
def _get_httpd(self):
449
374
if self._httpd is None:
450
375
rhandler = self.request_handler
451
# Depending on the protocol version, we will create the approriate
453
if self.protocol_version is None:
454
# Use the request handler one
455
proto_vers = rhandler.protocol_version
457
# Use our own, it will be used to override the request handler
459
proto_vers = self.protocol_version
376
proto_vers = rhandler.protocol_version
460
377
# Create the appropriate server for the required protocol
461
378
serv_cls = self.http_server_class.get(proto_vers, None)
462
379
if serv_cls is None:
463
380
raise httplib.UnknownProtocol(proto_vers)
465
self._httpd = self.create_httpd(serv_cls, rhandler)
466
self.host, self.port = self._httpd.socket.getsockname()
382
self._httpd = serv_cls((self.host, self.port), rhandler, self)
383
host, self.port = self._httpd.socket.getsockname()
467
384
return self._httpd
469
386
def _http_start(self):