__author__='Timothy Wakeham (timmeh)' __date__='31/12/07' __runas__='__main__' __desc__='Threaded HTTP server' import SocketServer import logging import sys import threading import string import re logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - [%(levelname)s] %(name)s.%(funcName)s: %(message)s',filename='server.log') class HTTPRequestHandler(SocketServer.BaseRequestHandler): def __init__(self, request, addr, server): '''Initialise HTTPRequestHandler''' #setup file logger self.logger = logging.getLogger('HTTPRequestHandler') #also log to console console = logging.StreamHandler() self.logger.addHandler(console) self.logger.debug('Initialising HTTPRequestHandler') self.logger.debug('Connection to %s:%s accepted' % (addr[0], addr[1])) self.implemented_methods = ['GET', 'HEAD', 'PUT'] self.error_no_mapping = {400:['Bad Request', 'Malformed request string. Do not repeat request without modification'], 501:['Not Implemented', 'Functionality not currently implemented']} self.re_request = re.compile(r'(?P.*?) (?P.*?) HTTP\/(?P1\.[0-1])') SocketServer.BaseRequestHandler.__init__(self, request, addr, server) def display_error(error_no, desc=''): self.send_header(sock) err_desc, info = self.error_no_mapping[error_no] output = "%s Error" % error_no output += "

%s

%s

%s

%s

" % (error_no, err_desc, info, desc) output += "" self.request.send(output) return 0 def send_header(self, content='text/html'): self.request.send('Server: pHTTP/0.1\r\n') self.request.send('Content-Type:%s\r\n' % content) self.request.send('\r\n') def setup(self): '''Any setup for the request handler goes here''' self.logger.debug('Setting up HTTPRequestHandler') SocketServer.BaseRequestHandler.setup(self) def handle(self): '''Handle the HTTP request''' self.logger.debug('Handling request') header = [] buffer = '' while(1): buffer += self.request.recv(1024) header.extend(buffer.split('\r\n')) buffer = header.pop() if not buffer: break self.logger.debug('Received header') request = self.re_request.search(header[0]) if request: method = request.group('method') resource = request.group('resource') http_ver = request.group('version') if method not in self.implemented_methods: self.request.send('HTTP/%s 501 Not Implemented' % version) self.logger.debug('[501] Not Implemented - Method: %s' % method) return self.display_error(501, desc='%s method not implemented on this server' % method) self.request.send('HTTP/%s 200 OK\r\n' % http_ver) self.send_header(content='text/plain') self.logger.debug('Requested resource - %s' % resource) self.request.send(string.join(header, '\r\n')) else: self.request.send('HTTP/%s 400 Bad Request' % version) self.logger.debug('[400] Bad Request - Request: %s' % header[0]) return self.display_error(400, desc='Request: %s' % header[0]) self.logger.debug('Request sent') def finish(self): '''Finalise any cleanup needed''' self.logger.debug('Finalise request') class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): def __init__(self, addr, handler_class=HTTPRequestHandler): '''Initialise TCP Socket Server''' self.logger = logging.getLogger('HTTPServer') #also log to console console = logging.StreamHandler() self.logger.addHandler(console) self.logger.debug('Initialising threaded HTTP Server') SocketServer.TCPServer.__init__(self, addr, handler_class) def server_activate(self): '''Called by constructor to start server''' self.logger.debug('Server activated') SocketServer.TCPServer.server_activate(self) def serve_forever(self): '''Start server''' self.logger.debug('Listening...') self.logger.info('Handling requests, to quit') while(1): self.handle_request() return def handle_request(self): '''Handle one request, possibly blocking''' self.logger.debug('Request received') return SocketServer.TCPServer.handle_request(self) def verify_request(self, req, addr): '''Verify the request - return True to continue handline''' #put stuff here to deal with blocked IP adresses if not addr: addr='Unknown' self.logger.debug('Verifying request from: %s:%s...' % (addr[0], addr[1])) verified = SocketServer.TCPServer.verify_request(self, req, addr) if not verified: self.logger.debug('Verification failed! [End process]') return 0 self.logger.debug('Verification succeeded!') return 1 def process_request(self, req, addr): '''Actually process the request''' self.logger.debug('Processing request...') try: processed = SocketServer.ThreadingMixIn.process_request(self, req, addr) except: exc, exc_str = sys.exc_info() self.logger.critical('%s whilst processing request from %s:%s' % (exc_str, addr[0], addr[1])) return 0 else: return processed def finish_request(self, req, addr): '''Finalise anything to do with this request''' self.logger.debug('Finalised processing') return SocketServer.TCPServer.finish_request(self, req, addr) def server_close(self): '''Stop serving''' self.logger.debug('Server closed, [End listening]') return SocketServer.TCPServer.server_close(self) def close_request(self, addr): '''Finalise request''' self.logger.debug('Request finalised [Close connection]') return SocketServer.TCPServer.close_request(self, addr) if __name__ == '__main__': logger = logging.getLogger('__main__') #also log to console console = logging.StreamHandler() logger.addHandler(console) addr = ('127.0.0.1', 0) server = ThreadingTCPServer(addr, HTTPRequestHandler) ip, port = server.server_address logger.info('Server bound to address - %s:%s' % (ip, port)) server_thread = threading.Thread(target=server.serve_forever) server_thread.setDaemon(1) #server_thread.start() server.serve_forever()