goulash.fileserver module
# SOURCE:
# http://stackoverflow.com/questions/14088294/multithreaded-web-server-in-python
import os, sys
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer
import SimpleHTTPServer
from fabric.colors import red
class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
pass
def main(args):
port = int(args.port) if args.port else 8000
_dir = args.dir if args.dir else os.getcwd()
if not os.path.exists(_dir):
err = "cannot serve nonexistent directory: {0}".format(_dir)
raise SystemExit(err)
os.chdir(_dir)
msg = "starting file server. port is {0}, directory is {1}"
msg = msg.format(port, _dir)
print red(msg)
server = ThreadingSimpleServer(
('', port),
SimpleHTTPServer.SimpleHTTPRequestHandler)
try:
while 1:
sys.stdout.flush()
server.handle_request()
except KeyboardInterrupt:
print "Finished"
import addict
def runserver(**kargs):
args = addict.Dict(**kargs)
main(args)
run_server = runserver
if __name__ == '__main__':
runserver()
Functions
def main(
args)
def main(args):
port = int(args.port) if args.port else 8000
_dir = args.dir if args.dir else os.getcwd()
if not os.path.exists(_dir):
err = "cannot serve nonexistent directory: {0}".format(_dir)
raise SystemExit(err)
os.chdir(_dir)
msg = "starting file server. port is {0}, directory is {1}"
msg = msg.format(port, _dir)
print red(msg)
server = ThreadingSimpleServer(
('', port),
SimpleHTTPServer.SimpleHTTPRequestHandler)
try:
while 1:
sys.stdout.flush()
server.handle_request()
except KeyboardInterrupt:
print "Finished"
def run_server(
**kargs)
def runserver(**kargs):
args = addict.Dict(**kargs)
main(args)
def runserver(
**kargs)
def runserver(**kargs):
args = addict.Dict(**kargs)
main(args)
Classes
class ThreadingSimpleServer
class ThreadingSimpleServer(ThreadingMixIn, HTTPServer):
pass
Ancestors (in MRO)
- ThreadingSimpleServer
- SocketServer.ThreadingMixIn
- BaseHTTPServer.HTTPServer
- SocketServer.TCPServer
- SocketServer.BaseServer
Class variables
var address_family
var allow_reuse_address
var daemon_threads
var request_queue_size
var socket_type
var timeout
Methods
def __init__(
self, server_address, RequestHandlerClass, bind_and_activate=True)
Constructor. May be extended, do not override.
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
"""Constructor. May be extended, do not override."""
BaseServer.__init__(self, server_address, RequestHandlerClass)
self.socket = socket.socket(self.address_family,
self.socket_type)
if bind_and_activate:
self.server_bind()
self.server_activate()
def close_request(
self, request)
Called to clean up an individual request.
def close_request(self, request):
"""Called to clean up an individual request."""
request.close()
def fileno(
self)
Return socket file number.
Interface required by select().
def fileno(self):
"""Return socket file number.
Interface required by select().
"""
return self.socket.fileno()
def finish_request(
self, request, client_address)
Finish one request by instantiating RequestHandlerClass.
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)
def get_request(
self)
Get the request and client address from the socket.
May be overridden.
def get_request(self):
"""Get the request and client address from the socket.
May be overridden.
"""
return self.socket.accept()
def handle_error(
self, request, client_address)
Handle an error gracefully. May be overridden.
The default is to print a traceback and continue.
def handle_error(self, request, client_address):
"""Handle an error gracefully. May be overridden.
The default is to print a traceback and continue.
"""
print '-'*40
print 'Exception happened during processing of request from',
print client_address
import traceback
traceback.print_exc() # XXX But this goes to stderr!
print '-'*40
def handle_request(
self)
Handle one request, possibly blocking.
Respects self.timeout.
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 = _eintr_retry(select.select, [self], [], [], timeout)
if not fd_sets[0]:
self.handle_timeout()
return
self._handle_request_noblock()
def handle_timeout(
self)
Called if no new request arrives within self.timeout.
Overridden by ForkingMixIn.
def handle_timeout(self):
"""Called if no new request arrives within self.timeout.
Overridden by ForkingMixIn.
"""
pass
def process_request(
self, request, client_address)
Start a new thread to process the request.
def process_request(self, request, client_address):
"""Start a new thread to process the request."""
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
t.start()
def process_request_thread(
self, request, client_address)
Same as in BaseServer but as a thread.
In addition, exception handling is done here.
def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread.
In addition, exception handling is done here.
"""
try:
self.finish_request(request, client_address)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
self.shutdown_request(request)
def serve_forever(
self, poll_interval=0.5)
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.
def serve_forever(self, poll_interval=0.5):
"""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.__is_shut_down.clear()
try:
while not self.__shutdown_request:
# XXX: Consider using another file descriptor or
# connecting to the socket to wake this up instead of
# polling. Polling reduces our responsiveness to a
# shutdown request and wastes cpu at all other times.
r, w, e = _eintr_retry(select.select, [self], [], [],
poll_interval)
if self in r:
self._handle_request_noblock()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
def server_activate(
self)
Called by constructor to activate the server.
May be overridden.
def server_activate(self):
"""Called by constructor to activate the server.
May be overridden.
"""
self.socket.listen(self.request_queue_size)
def server_bind(
self)
Override server_bind to store the server name.
def server_bind(self):
"""Override server_bind to store the server name."""
SocketServer.TCPServer.server_bind(self)
host, port = self.socket.getsockname()[:2]
self.server_name = socket.getfqdn(host)
self.server_port = port
def server_close(
self)
Called to clean-up the server.
May be overridden.
def server_close(self):
"""Called to clean-up the server.
May be overridden.
"""
self.socket.close()
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.
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.__shutdown_request = True
self.__is_shut_down.wait()
def shutdown_request(
self, request)
Called to shutdown and close an individual request.
def shutdown_request(self, request):
"""Called to shutdown and close an individual request."""
try:
#explicitly shutdown. socket.close() merely releases
#the socket and waits for GC to perform the actual close.
request.shutdown(socket.SHUT_WR)
except socket.error:
pass #some platforms may raise ENOTCONN here
self.close_request(request)
def verify_request(
self, request, client_address)
Verify the request. May be overridden.
Return True if we should proceed with this request.
def verify_request(self, request, client_address):
"""Verify the request. May be overridden.
Return True if we should proceed with this request.
"""
return True