From c829f456b282c3ce1ae5e85df7786fee6d30caa1 Mon Sep 17 00:00:00 2001 From: Chase Dullinger Date: Thu, 4 Mar 2021 20:06:28 -0800 Subject: [PATCH] Finishing assignment 3 --- http_server.py | 69 ++++++++++++++++++++++++++++++++++++-------------- tests.py | 33 ++++++++++++------------ 2 files changed, 67 insertions(+), 35 deletions(-) diff --git a/http_server.py b/http_server.py index 58d7386..1d35d05 100644 --- a/http_server.py +++ b/http_server.py @@ -1,7 +1,12 @@ +"""http server assignment""" + +import mimetypes +import os import socket import sys import traceback + def response_ok(body=b"This is a minimal response", mimetype=b"text/plain"): """ returns a basic HTTP response @@ -20,20 +25,28 @@ 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"", + b"You can't do that on this"]) def response_not_found(): """Returns a 404 Not Found response""" # TODO: Implement response_not_found - return b"" + return b"\r\n".join([b"HTTP/1.1 404 Not Found", + b"", + b"File not found"]) def parse_request(request): @@ -45,9 +58,14 @@ def parse_request(request): """ # 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): + +def response_path(path, base_dir = "webroot"): """ This method should return appropriate content and a mime type. @@ -74,9 +92,21 @@ def response_path(path): response_path('/a_page_that_doesnt_exist.html') -> Raises a NameError """ - # TODO: Raise a NameError if the requested content is not present # under webroot. + requested_content = base_dir + path + + if not os.path.exists(requested_content): + raise NameError + + if os.path.isdir(requested_content): + mime_type = b"text/plain" + content = "\r\n".join(os.listdir(requested_content)).encode() + + else: + mime_type = mimetypes.guess_type(requested_content)[0].encode() + with open(requested_content, "rb") as file_contents: + content = file_contents.read() # TODO: Fill in the appropriate content and mime_type give the path. # See the assignment guidelines for help on "mapping mime-types", though @@ -85,9 +115,6 @@ def response_path(path): # 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 @@ -114,30 +141,36 @@ 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. # 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 + # 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" - ) + content, mimetype = response_path(path) + response = response_ok( + body=content, + mimetype=mimetype) + + except NotImplementedError: + response = response_method_not_allowed() + except NameError: + response = response_not_found() conn.sendall(response) except: traceback.print_exc() finally: - conn.close() + conn.close() except KeyboardInterrupt: sock.close() @@ -149,5 +182,3 @@ def server(log_buffer=sys.stderr): if __name__ == '__main__': server() sys.exit(0) - - diff --git a/tests.py b/tests.py index 21da57e..2783920 100644 --- a/tests.py +++ b/tests.py @@ -7,26 +7,27 @@ class WebTestCase(unittest.TestCase): """tests for the echo server and client""" - def setUp(self): - self.server_process = subprocess.Popen( - [ - "python", - "http_server.py" - ], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - - def tearDown(self): - self.server_process.kill() - self.server_process.communicate() + # def setUp(self): + # self.server_process = subprocess.Popen( + # [ + # "python", + # "http_server.py" + # ], + # stdout=subprocess.PIPE, + # stderr=subprocess.PIPE, + # ) + # + # def tearDown(self): + # self.server_process.kill() + # self.server_process.communicate() + def get_response(self, url): """ Helper function to get a response from a given url, using http.client """ - conn = http.client.HTTPConnection('localhost:10000') + conn = http.client.HTTPConnection('127.0.0.1', 10000) conn.request('GET', url) response = conn.getresponse() @@ -40,7 +41,7 @@ def test_post_yields_method_not_allowed(self): Sending a POST request should yield a 405 Method Not Allowed response """ - conn = http.client.HTTPConnection('localhost:10000') + conn = http.client.HTTPConnection('127.0.0.1', 10000) conn.request('POST', '/') response = conn.getresponse() @@ -190,7 +191,7 @@ def test_root_index(self): def test_ok_response_at_root_index(self): """ - A call to / at least yields a 200 OK response + A call to / at least yields a 200 OK response """ directory = ''