Top

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