From c28bf7df02fa48deac2790f9ceee6a5e98aadfe9 Mon Sep 17 00:00:00 2001 From: Brian Minsk Date: Fri, 21 Feb 2020 13:54:02 +0700 Subject: [PATCH 1/3] serving up pages correctly but client is connecting sometimes without making a request --- http_server.py | 82 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/http_server.py b/http_server.py index 58d7386..1e0f0ea 100644 --- a/http_server.py +++ b/http_server.py @@ -1,6 +1,8 @@ import socket import sys import traceback +import mimetypes +import os def response_ok(body=b"This is a minimal response", mimetype=b"text/plain"): """ @@ -19,21 +21,23 @@ def response_ok(body=b"This is a minimal response", mimetype=b"text/plain"): ''' """ - # TODO: Implement response_ok - return b"" + return b"\r\n".join([b"HTTP/1.1 200 OK", + b"Content-Type: " + mimetype, + b"", + body,]) def response_method_not_allowed(): """Returns a 405 Method Not Allowed response""" - # TODO: Implement response_method_not_allowed - return b"" + return b"\r\n".join([b"HTTP/1.1 405 Method Not Allowed", + b"", + "GET requests only please!"]) def response_not_found(): """Returns a 404 Not Found response""" - # TODO: Implement response_not_found - return b"" + return b"HTTP/1.1 404 Not Found" def parse_request(request): @@ -44,8 +48,12 @@ def parse_request(request): NotImplementedError if the method of the request is not GET. """ - # TODO: implement parse_request - return "" + method, path, version = request.split("\r\n")[0].split(" ") + + if method != "GET": + raise NotImplementedError + + return path def response_path(path): """ @@ -75,21 +83,43 @@ def response_path(path): """ - # TODO: Raise a NameError if the requested content is not present + path = os.path.join("./webroot/", path[1:]) + + # Raise a NameError if the requested content is not present # under webroot. + if not os.path.exists(path): + raise NameError - # TODO: Fill in the appropriate content and mime_type give the path. + # Fill in the appropriate content and mime_type give the path. # See the assignment guidelines for help on "mapping mime-types", though # you might need to create a special case for handling make_time.py # # If the path is "make_time.py", then you may OPTIONALLY return the # result of executing `make_time.py`. But you need only return the # CONTENTS of `make_time.py`. - - content = b"not implemented" - mime_type = b"not implemented" - return content, mime_type + mime_type = '' + unencoded_content = None + content = None + + if os.path.isdir(path): + mime_type = 'text/plain' + file_list = os.listdir(path) + unencoded_content = "\r\n".join(file_list) + else: # it's a file + mime_type = mimetypes.guess_type(path)[0] + + if mime_type.startswith('text'): + with open(path, "r") as f: + unencoded_content = f.read() + else: # not a text file + with open(path, "rb") as f: + content = f.read() + + if unencoded_content: + content = unencoded_content.encode('utf8') + + return content, mime_type.encode('utf8') def server(log_buffer=sys.stderr): @@ -114,32 +144,30 @@ def server(log_buffer=sys.stderr): if '\r\n\r\n' in request: break - print("Request received:\n{}\n\n".format(request)) - # TODO: Use parse_request to retrieve the path from the request. + try: + path = parse_request(request) - # TODO: Use response_path to retrieve the content and the mimetype, - # based on the request path. + content, mimetype = response_path(path) - # TODO; If parse_request raised a NotImplementedError, then let - # response be a method_not_allowed response. If response_path raised - # a NameError, then let response be a not_found response. Else, - # use the content and mimetype from response_path to build a - # response_ok. - response = response_ok( - body=b"Welcome to my web server", - mimetype=b"text/plain" - ) + response = response_ok(content, mimetype) + except NotImplementedError: + response = response_method_not_allowed() + except NameError: + response = response_not_found() conn.sendall(response) except: traceback.print_exc() finally: + print("response: {}".format(response)) + print("connection closing") conn.close() except KeyboardInterrupt: + print("caught KeyboardInterrupt") sock.close() return except: From ea3faf393368560d21bf89ba01549f978eaafd18 Mon Sep 17 00:00:00 2001 From: Brian Minsk Date: Thu, 27 Feb 2020 18:14:37 +0700 Subject: [PATCH 2/3] trying to figure out why connections are made without a request from the browser ... --- http_server.py | 74 +++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/http_server.py b/http_server.py index 1e0f0ea..9963a10 100644 --- a/http_server.py +++ b/http_server.py @@ -31,7 +31,7 @@ def response_method_not_allowed(): return b"\r\n".join([b"HTTP/1.1 405 Method Not Allowed", b"", - "GET requests only please!"]) + b"GET requests only please!"]) def response_not_found(): @@ -39,6 +39,11 @@ def response_not_found(): return b"HTTP/1.1 404 Not Found" +def response_unknown_error(err_text="unknown"): + return b"\r\n".join([b"HTTP/1.1 520 Web Server Returned an Unknown Error", + b"", + b"Error: {}".format(err_text)]) + def parse_request(request): """ @@ -110,16 +115,48 @@ def response_path(path): mime_type = mimetypes.guess_type(path)[0] if mime_type.startswith('text'): - with open(path, "r") as f: - unencoded_content = f.read() + with open(path, "rb") as f: + content = f.read() else: # not a text file with open(path, "rb") as f: content = f.read() if unencoded_content: - content = unencoded_content.encode('utf8') + content = unencoded_content.encode() + + return content, mime_type.encode() + - return content, mime_type.encode('utf8') +def process_request(conn, addr): + request = '' + while True: + data = conn.recv(1024) + request += data.decode() + + if '\r\n\r\n' in request: + break + + print("Request received:\n{}\n\n".format(request)) + + return request + + +def generate_response(request): + try: + path = parse_request(request) + print("parse_request returned: {}".format(path)) + + content, mimetype = response_path(path) + + response = response_ok(content, mimetype) + except NotImplementedError: + response = response_method_not_allowed() + except NameError: + response = response_not_found() + except Exception as e: + response = response_unknown_error(e) + finally: + return response def server(log_buffer=sys.stderr): @@ -134,32 +171,13 @@ def server(log_buffer=sys.stderr): while True: print('waiting for a connection', file=log_buffer) conn, addr = sock.accept() # blocking + print('connection - {0}:{1}'.format(*addr), file=log_buffer) try: - print('connection - {0}:{1}'.format(*addr), file=log_buffer) - - request = '' - while True: - data = conn.recv(1024) - request += data.decode('utf8') - - if '\r\n\r\n' in request: - break - - print("Request received:\n{}\n\n".format(request)) - - try: - path = parse_request(request) - - content, mimetype = response_path(path) - - response = response_ok(content, mimetype) - except NotImplementedError: - response = response_method_not_allowed() - except NameError: - response = response_not_found() - + request = process_request(conn, addr) + response = generate_response(request) conn.sendall(response) except: + print("in internal exception") traceback.print_exc() finally: print("response: {}".format(response)) From 48668d190f6579aa9bc326756263ce3e7126ee37 Mon Sep 17 00:00:00 2001 From: Brian Minsk Date: Mon, 9 Mar 2020 16:02:32 +0700 Subject: [PATCH 3/3] took out socket timeout code --- Procfile | 0 http_server.py | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Procfile diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..e69de29 diff --git a/http_server.py b/http_server.py index 9963a10..a1e5f44 100644 --- a/http_server.py +++ b/http_server.py @@ -39,6 +39,7 @@ def response_not_found(): return b"HTTP/1.1 404 Not Found" + def response_unknown_error(err_text="unknown"): return b"\r\n".join([b"HTTP/1.1 520 Web Server Returned an Unknown Error", b"", @@ -60,6 +61,7 @@ def parse_request(request): return path + def response_path(path): """ This method should return appropriate content and a mime type. @@ -165,20 +167,28 @@ def server(log_buffer=sys.stderr): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) print("making a server on {0}:{1}".format(*address), file=log_buffer) sock.bind(address) + # sock.settimeout(3.0) sock.listen(1) try: + response = "Failed to generate response." while True: print('waiting for a connection', file=log_buffer) conn, addr = sock.accept() # blocking print('connection - {0}:{1}'.format(*addr), file=log_buffer) + # conn.settimeout(3.0) try: request = process_request(conn, addr) response = generate_response(request) conn.sendall(response) + # except socket.timeout: + # print("connection timed out") + # response = response_not_found() + # conn.close() except: print("in internal exception") traceback.print_exc() + conn.close() finally: print("response: {}".format(response)) print("connection closing") @@ -190,10 +200,10 @@ def server(log_buffer=sys.stderr): return except: traceback.print_exc() + sock.close() + return if __name__ == '__main__': server() sys.exit(0) - -