317
324
# the tests cases.
318
325
self.test_case_server = test_case_server
319
326
self._home_dir = test_case_server._home_dir
322
"""Called to clean-up the server.
324
Since the server may be (surely is, even) in a blocking listen, we
325
shutdown its socket before closing it.
327
# Note that is this executed as part of the implicit tear down in the
328
# main thread while the server runs in its own thread. The clean way
329
# to tear down the server is to instruct him to stop accepting
330
# connections and wait for the current connection(s) to end
331
# naturally. To end the connection naturally, the http transports
332
# should close their socket when they do not need to talk to the
333
# server anymore. This happens naturally during the garbage collection
334
# phase of the test transport objetcs (the server clients), so we
335
# don't have to worry about them. So, for the server, we must tear
336
# down here, from the main thread, when the test have ended. Note
337
# that since the server is in a blocking operation and since python
338
# use select internally, shutting down the socket is reliable and
341
self.socket.shutdown(socket.SHUT_RDWR)
342
except socket.error, e:
343
# WSAENOTCONN (10057) 'Socket is not connected' is harmless on
344
# windows (occurs before the first connection attempt
347
# 'Socket is not connected' can also occur on OSX, with a
348
# "regular" ENOTCONN (when something went wrong during test case
349
# setup leading to self.setUp() *not* being called but
350
# self.tearDown() still being called -- vila20081106
351
if not len(e.args) or e.args[0] not in (errno.ENOTCONN, 10057):
353
# Let the server properly close the socket
357
class TestingHTTPServer(SocketServer.TCPServer, TestingHTTPServerMixin):
328
self.is_shut_down = threading.Event()
329
# We collect the sockets/threads used by the clients so we can
330
# close/join them when shutting down
333
def get_request (self):
334
"""Get the request and client address from the socket.
336
sock, addr = self._get_request()
337
self.clients.append([sock, addr])
340
def verify_request(self, request, client_address):
341
"""Verify the request.
343
Return True if we should proceed with this request, False if we should
344
not even touch a single byte in the socket !
346
return self.serving is not None and self.serving.isSet()
348
def handle_request(self):
349
request, client_address = self.get_request()
351
if self.verify_request(request, client_address):
352
self.process_request(request, client_address)
354
if self.serving is not None and self.serving.isSet():
355
self.handle_error(request, client_address)
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
364
self.close_request(request)
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()
372
def serve(self, started):
373
self.serving = threading.Event()
375
self.is_shut_down.clear()
376
if 'threads' in tests.selftest_debug_flags:
377
print 'Starting %r' % (self.server_address,)
378
# We are listening and ready to accept connections
380
while self.serving.isSet():
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
385
self.handle_request()
386
if 'threads' in tests.selftest_debug_flags:
387
print 'Closing %r' % (self.server_address,)
388
# Let's close the listening socket
390
if 'threads' in tests.selftest_debug_flags:
391
print 'Closed %r' % (self.server_address,)
392
self.is_shut_down.set()
394
def connect_socket(self):
395
err = socket.error('getaddrinfo returns an empty list')
396
for res in socket.getaddrinfo(*self.server_address):
397
af, socktype, proto, canonname, sa = res
400
sock = socket.socket(af, socktype, proto)
404
except socket.error, err:
405
# 'err' is now the most recent error
410
def join_thread(self, thread, timeout=2):
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,))
419
"""Stops the serve() loop.
421
Blocks until the loop has finished. This must be called while serve()
422
is running in another thread, or it will deadlock.
424
if self.serving is None:
425
# If the server wasn't properly started, there is nothing to
428
# As soon as we stop serving, no more connection are accepted except
429
# one to get out of the blocking listen.
431
# The server is listening for a last connection, let's give it:
434
last_conn = self.connect_socket()
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)
442
# We don't have to wait for the server to shut down to start shutting
443
# down the clients, so let's start now.
444
for c in self.clients:
445
self.shutdown_client(c)
447
# Now we wait for the thread running serve() to finish
448
self.is_shut_down.wait()
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).
455
def shutdown_client(self, client):
456
sock, addr = client[:2]
457
self.shutdown_client_socket(sock)
459
def shutdown_client_socket(self, sock):
460
"""Properly shutdown a client socket.
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
466
This should be called only when no other thread is trying to use the
470
# The request process has been completed, the thread is about to
471
# die, let's shutdown the socket if we can.
472
sock.shutdown(socket.SHUT_RDWR)
473
except (socket.error, select.error), e:
474
if e[0] in (errno.EBADF, errno.ENOTCONN):
475
# Right, the socket is already down
481
class TestingHTTPServer(TestingHTTPServerMixin, SocketServer.TCPServer):
359
483
def __init__(self, server_address, request_handler_class,
360
484
test_case_server):
383
515
self.daemon_threads = True
385
def process_request_thread(self, request, client_address):
517
def _get_request (self):
518
return SocketServer.ThreadingTCPServer.get_request(self)
520
def process_request_thread(self, started, request, client_address):
521
if 'threads' in tests.selftest_debug_flags:
522
print 'Processing: %s' % (threading.currentThread().name,)
386
524
SocketServer.ThreadingTCPServer.process_request_thread(
387
525
self, request, client_address)
388
# Under some circumstances (as in bug #383920), we need to force the
389
# shutdown as python delays it until gc occur otherwise and the client
392
# The request process has been completed, the thread is about to
393
# die, let's shutdown the socket if we can.
394
request.shutdown(socket.SHUT_RDWR)
395
except (socket.error, select.error), e:
396
if e[0] in (errno.EBADF, errno.ENOTCONN):
397
# Right, the socket is already down
526
# Shutdown the socket as soon as possible, the thread will be joined
527
# later if needed during server shutdown thread.
528
self.shutdown_client_socket(request)
530
def process_request(self, request, client_address):
531
"""Start a new thread to process the request."""
532
client = self.clients.pop()
533
started = threading.Event()
534
t = threading.Thread(target = self.process_request_thread,
535
args = (started, request, client_address))
536
t.name = '%s -> %s' % (client_address, self.server_address)
538
self.clients.append(client)
539
if self.daemon_threads:
544
def shutdown_client(self, client):
545
TestingHTTPServerMixin.shutdown_client(self, client)
547
# The thread has been created only if the request is processed but
548
# after the connection is inited. This could happne when the server
550
sock, addr, thread = client
551
if 'threads' in tests.selftest_debug_flags:
552
print 'Try joining: %s' % (thread.name,)
553
self.join_thread(thread)
555
def server_bind(self):
556
SocketServer.ThreadingTCPServer.server_bind(self)
557
TestingHTTPServerMixin.server_bind(self)
403
560
class HttpServer(transport.Server):
462
619
raise httplib.UnknownProtocol(proto_vers)
464
621
self._httpd = self.create_httpd(serv_cls, rhandler)
465
host, self.port = self._httpd.socket.getsockname()
622
# Ensure we get the right port and an updated host if needed
623
self.host, self.port = self._httpd.server_address
466
624
return self._httpd
468
def _http_start(self):
626
def _http_start(self, started):
469
627
"""Server thread main entry point. """
470
self._http_running = False
473
httpd = self._get_httpd()
474
self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
475
self.host, self.port)
476
self._http_running = True
478
# Whatever goes wrong, we save the exception for the main
479
# thread. Note that since we are running in a thread, no signal
480
# can be received, so we don't care about KeyboardInterrupt.
481
self._http_exception = sys.exc_info()
483
# Release the lock or the main thread will block and the whole
485
self._http_starting.release()
630
server = self._get_httpd()
631
self._http_base_url = '%s://%s:%s/' % (self._url_protocol,
632
self.host, self.port)
634
# Whatever goes wrong, we save the exception for the main
635
# thread. Note that since we are running in a thread, no signal
636
# can be received, so we don't care about KeyboardInterrupt.
637
self._http_exception = sys.exc_info()
487
# From now on, exceptions are taken care of by the
488
# SocketServer.BaseServer or the request handler.
489
while self._http_running:
491
# Really an HTTP connection but the python framework is generic
492
# and call them requests
493
httpd.handle_request()
494
except socket.timeout:
496
except (socket.error, select.error), e:
497
if e[0] == errno.EBADF:
498
# Starting with python-2.6, handle_request may raise socket
499
# or select exceptions when the server is shut down (as we
639
if server is not None:
640
# From now on, exceptions are taken care of by the
641
# SocketServer.BaseServer or the request handler.
642
server.serve(started)
643
if not started.isSet():
644
# Hmm, something went wrong, but we can release the caller anyway
505
647
def _get_remote_url(self, path):
506
648
path_parts = path.split(os.path.sep)
528
670
# XXX: TODO: make the server back onto vfs_server rather than local
530
if not (backing_transport_server is None or \
531
isinstance(backing_transport_server, local.LocalURLServer)):
672
if not (backing_transport_server is None
673
or isinstance(backing_transport_server,
674
test_server.LocalURLServer)):
532
675
raise AssertionError(
533
"HTTPServer currently assumes local transport, got %s" % \
676
"HTTPServer currently assumes local transport, got %s" %
534
677
backing_transport_server)
535
678
self._home_dir = os.getcwdu()
536
679
self._local_path_parts = self._home_dir.split(os.path.sep)
537
680
self._http_base_url = None
539
682
# Create the server thread
540
self._http_starting = threading.Lock()
541
self._http_starting.acquire()
542
self._http_thread = threading.Thread(target=self._http_start)
683
started = threading.Event()
684
self._http_thread = threading.Thread(target=self._http_start,
543
686
self._http_thread.setDaemon(True)
544
687
self._http_exception = None
545
688
self._http_thread.start()
547
689
# Wait for the server thread to start (i.e release the lock)
548
self._http_starting.acquire()
691
self._http_thread.name = self._http_base_url
692
if 'threads' in tests.selftest_debug_flags:
693
print 'Thread started: %s' % (self._http_thread.name,)
550
696
if self._http_exception is not None:
551
697
# Something went wrong during server start
552
698
exc_class, exc_value, exc_tb = self._http_exception
553
699
raise exc_class, exc_value, exc_tb
554
self._http_starting.release()
702
def stop_server(self):
558
703
"""See bzrlib.transport.Server.tearDown."""
559
self._httpd.tearDown()
560
self._http_running = False
561
# We don't need to 'self._http_thread.join()' here since the thread is
562
# a daemonic one and will be garbage collected anyway. Joining just
563
# slows us down for no added benefit.
704
self._httpd.shutdown()
705
if 'threads' in tests.selftest_debug_flags:
706
print 'Try joining: %s' % (self._http_thread.name,)
707
self._httpd.join_thread(self._http_thread)
708
if 'threads' in tests.selftest_debug_flags:
709
print 'Thread joined: %s' % (self._http_thread.name,)
565
711
def get_url(self):
566
712
"""See bzrlib.transport.Server.get_url."""