mirror of
https://github.com/GAM-team/GAM.git
synced 2025-07-07 21:23:34 +00:00
101 lines
3.2 KiB
Python
101 lines
3.2 KiB
Python
import logging
|
|
import os
|
|
import select
|
|
import SimpleHTTPServer
|
|
import SocketServer
|
|
import threading
|
|
|
|
HERE = os.path.dirname(__file__)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ThisDirHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
|
|
def translate_path(self, path):
|
|
path = path.split('?', 1)[0].split('#', 1)[0]
|
|
return os.path.join(HERE, *filter(None, path.split('/')))
|
|
|
|
def log_message(self, s, *args):
|
|
# output via logging so nose can catch it
|
|
logger.info(s, *args)
|
|
|
|
|
|
class ShutdownServer(SocketServer.TCPServer):
|
|
"""Mixin that allows serve_forever to be shut down.
|
|
|
|
The methods in this mixin are backported from SocketServer.py in the Python
|
|
2.6.4 standard library. The mixin is unnecessary in 2.6 and later, when
|
|
BaseServer supports the shutdown method directly.
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
SocketServer.TCPServer.__init__(self, *args, **kwargs)
|
|
self.__is_shut_down = threading.Event()
|
|
self.__serving = False
|
|
|
|
def serve_forever(self, poll_interval=0.1):
|
|
"""Handle one request at a time until shutdown.
|
|
|
|
Polls for shutdown every poll_interval seconds. Ignores
|
|
self.timeout. If you need to do periodic tasks, do them in
|
|
another thread.
|
|
"""
|
|
self.__serving = True
|
|
self.__is_shut_down.clear()
|
|
while self.__serving:
|
|
r, w, e = select.select([self.socket], [], [], poll_interval)
|
|
if r:
|
|
self._handle_request_noblock()
|
|
self.__is_shut_down.set()
|
|
|
|
def shutdown(self):
|
|
"""Stops the serve_forever loop.
|
|
|
|
Blocks until the loop has finished. This must be called while
|
|
serve_forever() is running in another thread, or it will deadlock.
|
|
"""
|
|
self.__serving = False
|
|
self.__is_shut_down.wait()
|
|
|
|
def handle_request(self):
|
|
"""Handle one request, possibly blocking.
|
|
|
|
Respects self.timeout.
|
|
"""
|
|
# Support people who used socket.settimeout() to escape
|
|
# handle_request before self.timeout was available.
|
|
timeout = self.socket.gettimeout()
|
|
if timeout is None:
|
|
timeout = self.timeout
|
|
elif self.timeout is not None:
|
|
timeout = min(timeout, self.timeout)
|
|
fd_sets = select.select([self], [], [], timeout)
|
|
if not fd_sets[0]:
|
|
self.handle_timeout()
|
|
return
|
|
self._handle_request_noblock()
|
|
|
|
def _handle_request_noblock(self):
|
|
"""Handle one request, without blocking.
|
|
|
|
I assume that select.select has returned that the socket is
|
|
readable before this function was called, so there should be
|
|
no risk of blocking in get_request().
|
|
"""
|
|
try:
|
|
request, client_address = self.get_request()
|
|
except socket.error:
|
|
return
|
|
if self.verify_request(request, client_address):
|
|
try:
|
|
self.process_request(request, client_address)
|
|
except:
|
|
self.handle_error(request, client_address)
|
|
self.close_request(request)
|
|
|
|
|
|
def start_server(handler):
|
|
httpd = ShutdownServer(("", 0), handler)
|
|
threading.Thread(target=httpd.serve_forever).start()
|
|
_, port = httpd.socket.getsockname()
|
|
return httpd, port
|