diff --git a/do_integration_tests.bat b/do_integration_tests.bat new file mode 100644 index 0000000..01f7e5f --- /dev/null +++ b/do_integration_tests.bat @@ -0,0 +1,4 @@ +python -m unittest -vv tests.py > integration_test_results.txt 2>&1 +type integration_test_results.txt + + diff --git a/do_unit_tests.bat b/do_unit_tests.bat new file mode 100644 index 0000000..4d3434b --- /dev/null +++ b/do_unit_tests.bat @@ -0,0 +1,5 @@ +python -m unittest -vv unit-tests.py > unit_test_results.txt 2>&1 +type unit_test_results.txt + + + diff --git a/go_run_server.bat b/go_run_server.bat new file mode 100644 index 0000000..202b1cf --- /dev/null +++ b/go_run_server.bat @@ -0,0 +1 @@ +start python -u http_server.py diff --git a/http_server.py b/http_server.py index 58d7386..ef40dc2 100644 --- a/http_server.py +++ b/http_server.py @@ -1,39 +1,46 @@ import socket import sys import traceback +import os +import mimetypes +import base64 def response_ok(body=b"This is a minimal response", mimetype=b"text/plain"): """ returns a basic HTTP response - Ex: - response_ok( - b"

Welcome:

", - b"text/html" - ) -> - - b''' - HTTP/1.1 200 OK\r\n - Content-Type: text/html\r\n - \r\n -

Welcome:

\r\n - ''' """ - # TODO: Implement response_ok - return b"" + # DONE: Implement response_ok + + 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"" + # DONE: Implement response_method_not_allowed + return b"\r\n".join([ + b"HTTP/1.1 405 Method Not Allowed", + b"", + b"You can't do that on this server, 405 error Method Not Allowed!" + ]) + def response_not_found(): """Returns a 404 Not Found response""" - # TODO: Implement response_not_found - return b"" + # DONE: Implement response_not_found + return b"\r\n".join([ + b"HTTP/1.1 404 Not Found", + b"", + b"You can't do that on this server, 404 error Resource Name Not Found!" + ]) def parse_request(request): @@ -44,8 +51,14 @@ def parse_request(request): NotImplementedError if the method of the request is not GET. """ - # TODO: implement parse_request - return "" + # DONE: implement parse_request + + method, path, version = request.split("\r\n")[0].split(" ") + + if method != "GET": + raise NotImplementedError + + return path def response_path(path): """ @@ -75,20 +88,60 @@ def response_path(path): """ - # TODO: Raise a NameError if the requested content is not present - # under webroot. - - # TODO: 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" + + fps = ('webroot\\' + path) + status_isfile = os.path.isfile('webroot\\' + path) + status_isdir = os.path.isdir('webroot\\' + path) + # DONE: Raise a NameError if the requested content is not present + # under webroot. + if ( (status_isfile == False) and (status_isdir == False) ): + raise NameError + + if (status_isfile): + + mime_type=b"text/plain" + + filename, file_extension = os.path.splitext(fps) + if (file_extension == ".html"): + f=open(fps, "r") + contents =f.read() + f.close() + content=contents.encode('utf-8') + mime_type=b"text/html" + elif (file_extension == ".txt"): + f=open(fps, "r") + contents =f.read() + f.close() + content=contents.encode('utf-8') + mime_type=b"text/plain" + elif (file_extension == ".png"): + f=open(fps,"rb") + ary_bytes = f.read() + contents = ary_bytes + content=contents + mime_type=b"image/png" + f.close() + elif (file_extension == ".jpg"): + f=open(fps,"rb") + ary_bytes = f.read() + contents = ary_bytes + content=contents + mime_type=b"image/jpeg" + f.close() + + elif (status_isdir): + ary_files = os.listdir(fps) + str_files = '\n'.join(ary_files) + content = str_files.encode('utf-8') + mime_type=b"text/plain" + + # Done: 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 + return content, mime_type @@ -96,7 +149,7 @@ def server(log_buffer=sys.stderr): address = ('127.0.0.1', 10000) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - print("making a server on {0}:{1}".format(*address), file=log_buffer) + #print("making a server on {0}:{1}".format(*address), file=log_buffer) sock.bind(address) sock.listen(1) @@ -114,31 +167,43 @@ 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. - - # 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 - # response_ok. - response = response_ok( - body=b"Welcome to my web server", - mimetype=b"text/plain" - ) - - conn.sendall(response) + #print("Request received:\n{}\n\n".format(request)) + + try: + + response = None + if (".ico" in request): + pass + else: + + # DONE: Use parse_request to retrieve the path from the request. + path = parse_request(request) + + # DONE: Use response_path to retrieve the content and the mimetype, + # based on the request path. + content, mime_type = response_path(path) + + # DONE: If no exceptions use the content and mimetype from response_path to build a + # response_ok. + response = response_ok(content, mime_type) + + except NameError: + # DONE; If response_path raised + # a NameError, then let response be a not_found response. Else, + response = response_not_found() + except NotImplementedError: + # Done; If parse_request raised a NotImplementedError, then let + # response be a method_not_allowed response. + response = response_method_not_allowed() + + if (response is not None): + conn.sendall(response) except: traceback.print_exc() finally: conn.close() - + except KeyboardInterrupt: sock.close() return diff --git a/integration_test_results.txt b/integration_test_results.txt new file mode 100644 index 0000000..5175ba8 --- /dev/null +++ b/integration_test_results.txt @@ -0,0 +1,16 @@ +test_get_404 (tests.WebTestCase) ... ok +test_get_sample_1_png (tests.WebTestCase) ... ok +test_get_sample_1_png_mime_type (tests.WebTestCase) ... ok +test_get_sample_scene_balls_jpeg (tests.WebTestCase) ... ok +test_get_sample_scene_balls_jpeg_mime_type (tests.WebTestCase) ... ok +test_get_sample_text_content (tests.WebTestCase) ... ok +test_get_sample_text_mime_type (tests.WebTestCase) ... ok +test_images_index (tests.WebTestCase) ... ok +test_ok_response_at_root_index (tests.WebTestCase) ... ok +test_post_yields_method_not_allowed (tests.WebTestCase) ... ok +test_root_index (tests.WebTestCase) ... ok + +---------------------------------------------------------------------- +Ran 11 tests in 11.688s + +OK diff --git a/tests.py b/tests.py index 21da57e..f75da46 100644 --- a/tests.py +++ b/tests.py @@ -61,12 +61,18 @@ def test_get_sample_text_content(self): error_comment = "Error encountered while visiting " + web_path response = self.get_response(web_path) + sr = response.read() + sr = sr.decode('utf8') + sr = sr.rstrip("\n") self.assertEqual(response.getcode(), 200, error_comment) - with open(local_path, 'rb') as f: - self.assertEqual(f.read(), response.read(), error_comment) + with open(local_path, 'r') as f: + ss = f.read() + ss = ss.rstrip("\n") + self.assertEqual(ss, sr, error_comment) + def test_get_sample_text_mime_type(self): """ A call to /sample.txt returns the correct mimetype @@ -153,7 +159,6 @@ def test_get_404(self): error_comment = "Error encountered while visiting " + web_path response = self.get_response(web_path) - self.assertEqual(response.getcode(), 404, error_comment) def test_images_index(self): diff --git a/unit-tests.py b/unit-tests.py index a0c657a..6ba595f 100644 --- a/unit-tests.py +++ b/unit-tests.py @@ -51,11 +51,17 @@ def test_response_path_file(self): path = "/a_web_page.html" content, mime_type = http_server.response_path(path) + sr = content.decode('utf8') + sr = sr.rstrip("\n") self.assertEqual(b"text/html", mime_type) - with open(os.path.join("webroot", "a_web_page.html"), "rb") as f: - self.assertEqual(f.read(), content) + with open(os.path.join("webroot", "a_web_page.html"), "r") as f: + ss = f.read() + ss = ss.rstrip("\n") + #print(f" xxxxxx -{sr}-") + #print(f" yyyyyy -{ss}-") + self.assertEqual(sr, ss) def test_response_path_dir(self): path = "/" diff --git a/unit_test_results.txt b/unit_test_results.txt new file mode 100644 index 0000000..1bcf391 --- /dev/null +++ b/unit_test_results.txt @@ -0,0 +1,13 @@ +test_parse_request (unit-tests.TestCase) ... ok +test_parse_request_bad_method (unit-tests.TestCase) ... ok +test_response_method_not_allowed (unit-tests.TestCase) ... ok +test_response_not_found (unit-tests.TestCase) ... ok +test_response_ok (unit-tests.TestCase) ... ok +test_response_path_dir (unit-tests.TestCase) ... ok +test_response_path_file (unit-tests.TestCase) ... ok +test_response_path_not_found (unit-tests.TestCase) ... ok + +---------------------------------------------------------------------- +Ran 8 tests in 0.002s + +OK