165
140
def get_multiple_ranges(self, file, file_size, ranges):
166
141
self.send_response(206)
167
142
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)
143
boundary = "%d" % random.randint(0,0x7FFFFFFF)
144
self.send_header("Content-Type",
145
"multipart/byteranges; boundary=%s" % boundary)
184
146
self.end_headers()
186
# Send the multipart body
187
147
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))
148
self.wfile.write("--%s\r\n" % boundary)
149
self.send_header("Content-type", 'application/octet-stream')
150
self.send_header("Content-Range", "bytes %d-%d/%d" % (start,
192
153
self.end_headers()
193
154
self.send_range_content(file, start, end - start + 1)
195
self.wfile.write(boundary_line)
156
self.wfile.write("--%s\r\n" % boundary)
197
158
def do_GET(self):
198
159
"""Serve a GET request.
283
244
return self._translate_path(path)
285
246
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):
247
return SimpleHTTPServer.SimpleHTTPRequestHandler.translate_path(
250
if sys.platform == 'win32':
251
# On win32 you cannot access non-ascii filenames without
252
# decoding them into unicode first.
253
# However, under Linux, you can access bytestream paths
254
# without any problems. If this function was always active
255
# it would probably break tests when LANG=C was set
256
def _translate_path(self, path):
257
"""Translate a /-separated PATH to the local filename syntax.
259
For bzr, all url paths are considered to be utf8 paths.
260
On Linux, you can access these paths directly over the bytestream
261
request, but on win32, you must decode them, and access them
264
# abandon query parameters
265
path = urlparse.urlparse(path)[2]
266
path = posixpath.normpath(urllib.unquote(path))
267
path = path.decode('utf-8')
268
words = path.split('/')
269
words = filter(None, words)
305
272
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):
273
head, word = os.path.split(word)
274
if word in (os.curdir, os.pardir): continue
275
path = os.path.join(path, word)
279
class TestingHTTPServerWrapper(object):
280
"""Isolate the wrapper itself to make the server use transparent.
282
Daughter classes can override any method and/or directly call the _server
286
def __init__(self, server_class, test_case_server,
287
server_address, request_handler_class):
288
self._server = server_class(server_address, request_handler_class)
315
289
# test_case_server can be used to communicate between the
316
290
# tests and the server (or the request handler and the
317
291
# server), allowing dynamic behaviors to be defined from
318
292
# 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):
293
self._server.test_case_server = test_case_server
295
def __getattr__(self, name):
296
return getattr(self._server, name)
298
def server_bind(self):
299
"""Override server_bind to store the server name."""
300
self._server.server_bind()
301
host, port = self._server.socket.getsockname()[:2]
302
self._server.server_name = socket.getfqdn(host)
303
self._server.server_port = port
305
def server_close(self):
323
306
"""Called to clean-up the server.
325
308
Since the server may be (surely is, even) in a blocking listen, we
326
309
shutdown its socket before closing it.
328
311
# Note that is this executed as part of the implicit tear down in the
329
312
# 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):
313
# to tear down the server will be to instruct him to stop accepting
314
# connections and wait for the current connection to end naturally. To
315
# end the connection naturally, the http transports should close their
316
# socket when they do not need to talk to the server anymore. We
317
# don't want to impose such a constraint on the http transports (and
318
# we can't anyway ;). So we must tear down here, from the main thread,
319
# when the test have ended. Note that since the server is in a
320
# blocking operation and since python use select internally, shutting
321
# down the socket is reliable and relatively clean.
322
self._server.socket.shutdown(socket.SHUT_RDWR)
354
323
# 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):
324
self._server.server_close()
326
class TestingHTTPServer(TestingHTTPServerWrapper):
328
def __init__(self, server_address, request_handler_class, test_case_server):
329
super(TestingHTTPServer, self).__init__(
330
SocketServer.TCPServer, test_case_server,
331
server_address, request_handler_class)
334
class TestingThreadingHTTPServer(TestingHTTPServerWrapper):
369
335
"""A threading HTTP test server for HTTP 1.1.
371
337
Since tests can initiate several concurrent connections to the same http
373
339
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)
342
def __init__(self, server_address, request_handler_class, test_case_server):
343
super(TestingThreadingHTTPServer, self).__init__(
344
SocketServer.ThreadingTCPServer, test_case_server,
345
server_address, request_handler_class)
381
346
# Decides how threads will act upon termination of the main
382
347
# 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
349
self._server.daemon_threads = True
404
352
class HttpServer(transport.Server):
438
387
# Allows tests to verify number of GET requests issued
439
388
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
390
def _get_httpd(self):
449
391
if self._httpd is None:
450
392
rhandler = self.request_handler
451
# Depending on the protocol version, we will create the approriate
453
393
if self.protocol_version is None:
454
# Use the request handler one
455
394
proto_vers = rhandler.protocol_version
457
# Use our own, it will be used to override the request handler
459
396
proto_vers = self.protocol_version
460
397
# Create the appropriate server for the required protocol
461
398
serv_cls = self.http_server_class.get(proto_vers, None)
462
399
if serv_cls is None:
463
400
raise httplib.UnknownProtocol(proto_vers)
465
self._httpd = self.create_httpd(serv_cls, rhandler)
466
self.host, self.port = self._httpd.socket.getsockname()
402
self._httpd = serv_cls((self.host, self.port), rhandler, self)
403
host, self.port = self._httpd.socket.getsockname()
467
404
return self._httpd
469
406
def _http_start(self):