"""HTTP Server This module contains a HTTP server """ import threading import socket from composer import ResponseComposer from parser import RequestParser import weblogging as logging from config import config class ConnectionHandler(threading.Thread): """Connection Handler for HTTP Server""" def __init__(self, conn_socket, addr, timeout): """Initialize the HTTP Connection Handler Args: conn_socket (socket): socket used for connection with client addr (str): ip address of client timeout (int): seconds until timeout """ super(ConnectionHandler, self).__init__() self.daemon = True self.conn_socket = conn_socket self.addr = addr self.timeout = timeout self.done = False def handle_connection(self): """Handle a new connection""" self.rp = RequestParser() self.rc = ResponseComposer(timeout=self.timeout) self.conn_socket.settimeout(self.timeout) try: while not self.done: data = self.conn_socket.recv(32) if len(data) == 0: break self.handle_data(data) except socket.timeout: logging.debug('%s connection timed out.' % self.addr[0]) finally: self.conn_socket.shutdown(socket.SHUT_RDWR) self.conn_socket.close() logging.debug('%s connection closed.' % self.addr[0]) def handle_data(self, data): for req in self.rp.parse_requests(data): logging.info("<-- (%s) %s" % (self.addr[0], req.startline())) resp = self.rc.compose_response(req) logging.info("--> (%s) %s" % (self.addr[0], resp.startline())) self.send(resp) if resp.get_header('Connection') == 'close': self.done = True return def send(self, data): sent = self.conn_socket.send(str(data)) if sent == 0: raise RuntimeError('Socket broken') def run(self): """Run the thread of the connection handler""" try: self.handle_connection() except socket.error, e: logging.error('Error in handling connection with %s: %s' % (self.addr[0], str(e))) class Server: """HTTP Server""" def __init__(self, configfile, **kwargs): """Initialize the HTTP server Args: hostname (str): hostname of the server server_port (int): port that the server is listening on timeout (int): seconds until timeout """ self.read_config(configfile, **kwargs) self.done = False def read_config(self, configfile, **kwargs): config().read(configfile) if not config().has_section('webhttp'): config().add_section('webhttp') for name, val in kwargs.items(): if val != None: config().set('webhttp', name, str(val)) def run(self): """Run the HTTP Server and start listening""" self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.bind((config('hostname', default='localhost'), config('port', type=int, default=8001))) self.socket.listen(config('max_connections', type=int, default=1000)) while not self.done: (csocket, addr) = self.socket.accept() logging.debug('%s connection accepted.' % addr[0]) ch = ConnectionHandler(csocket, addr, config('timeout', type=int)) ch.start() def shutdown(self): """Safely shut down the HTTP server""" self.socket.shutdown(socket.SHUT_RDWR) self.socket.close() self.done = True