From a950e74cbee5890e913dfba0f8bf2ce578d67563 Mon Sep 17 00:00:00 2001 From: Camil Staps Date: Fri, 18 Mar 2016 16:04:30 +0100 Subject: Project 1: timeout in composer --- project1/proj1_s4498062/Makefile | 5 ++- project1/proj1_s4498062/webhttp/composer.py | 53 ++++++++++++++++++++++++----- project1/proj1_s4498062/webhttp/server.py | 3 -- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/project1/proj1_s4498062/Makefile b/project1/proj1_s4498062/Makefile index a0e071a..39c4da7 100644 --- a/project1/proj1_s4498062/Makefile +++ b/project1/proj1_s4498062/Makefile @@ -12,7 +12,10 @@ webserver: webserver.c $(CC) $(CCFLAGS) -o $@ $< run: webserver - ./webserver + ./$< + +test: webtests.py webhttp/*.py + python $< clean: rm -vf webserver webserver.c diff --git a/project1/proj1_s4498062/webhttp/composer.py b/project1/proj1_s4498062/webhttp/composer.py index b8b9f6a..bce6208 100644 --- a/project1/proj1_s4498062/webhttp/composer.py +++ b/project1/proj1_s4498062/webhttp/composer.py @@ -4,6 +4,7 @@ This module contains a composer, which can compose responses to HTTP requests from a client. """ +from multiprocessing import Process, Queue import re import time @@ -36,17 +37,50 @@ class ResponseComposer: """ response = Response() + q = Queue() + if re.search(r'\/\.\.?(\/|$)', request.uri): - return self.serve_error(403) + p = Process(target=self.serve_error, + args=(403,), kwargs=dict(queue=q)) + else: + p = Process(target=self.serve, + args=(request.uri,), kwargs=dict(queue=q, request=request)) + + p.start() + p.join(self.timeout) + + if p.is_alive(): + p.terminate() + p.join() + + logging.warning('Had to kill Composer.serve') + + resp = Response() + resp.code = 504 + resp.set_header('Connection', 'close') + resp.body = 'Internal timeout' + resp.set_content_length() else: - return self.serve(request.uri, request=request) + try: + resp = q.get(False) + except: + # After a timeout, we just make the most minimalistic response + # here (that is, no special error files are considered). + resp = Response() + resp.code = 500 + resp.set_header('Connection', 'close') + resp.body = 'This should never happen' + resp.set_content_length() + + return resp + - def serve(self, uri, code=200, etag=None, request=None): + def serve(self, uri, code=200, etag=None, request=None, queue=None): resp = Response() + req = request try: resource = Resource(uri) - req = request if req != None and ( resource.etag_match(req.get_header('If-None-Match')) or \ req.get_header('If-Match') != None and \ @@ -70,23 +104,24 @@ class ResponseComposer: resp.set_content_length() except FileExistError: if code < 400: - return self.serve_error(404) + self.serve_error(404, queue=queue) else: resp.code = code resp.body = 'Error %d' % code resp.set_content_length() except FileAccessError: - return self.serve_error(403) + self.serve_error(403, queue=queue) conn = 'keep-alive' if req != None and req.get_header('Connection') == 'close': conn = 'close' resp.set_header('Connection', conn) - return resp + queue.put(resp) - def serve_error(self, code): - return self.serve(config('error%d' % code, default=None), code=code) + def serve_error(self, code, queue=None): + return self.serve(config('error%d' % code, default=None), + code=code, queue=queue) def make_date_string(self): """Make string of date and time diff --git a/project1/proj1_s4498062/webhttp/server.py b/project1/proj1_s4498062/webhttp/server.py index 02ed8a6..62f1bdb 100644 --- a/project1/proj1_s4498062/webhttp/server.py +++ b/project1/proj1_s4498062/webhttp/server.py @@ -36,9 +36,6 @@ class ConnectionHandler(threading.Thread): self.conn_socket.settimeout(self.timeout) - # TODO: should not be persistent when client sends Connection: close - # or can we safely assume that in this case the client will close the - # transport channel, so that recv() returns something empty? try: while not self.done: data = self.conn_socket.recv(4096) -- cgit v1.2.3