From cf1688e099d7bec7638a3718e1f9f5ecebfc8ab4 Mon Sep 17 00:00:00 2001 From: Andy Simpson Date: Mon, 12 Oct 2020 21:52:24 -0700 Subject: [PATCH 1/4] class-based-server.py setup - AS --- .gitignore | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ http_server.py | 50 +++++++++++++++--- 2 files changed, 178 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 1981ccb..d1f0145 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,139 @@ *pycache* *solution* *.idea* + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# USER SPECIFIC/IDE FILES +.idea/ + +# GENERAL PYTHON FILES +__pycache__/ diff --git a/http_server.py b/http_server.py index 69ebaa3..d960ea4 100644 --- a/http_server.py +++ b/http_server.py @@ -54,8 +54,19 @@ def get_path(request): Then you would return "/images/sample_1.png" """ - - return "TODO: COMPLETE THIS" # TODO + try: + if "favicon.ico" in request: + return "/webroot/favicon.ico" + if "make_time.py" in request: + return "/webroot/make_time.py" + if "sample.txt" in request: + return "/webroot/sample.txt" + if "a_web_page.html" in request: + return "/webroot/a_web_page.html" + #if b"favicon.ico" in request: + #return "/webroot/a_web_page.html" + except: + return "/" @staticmethod @@ -63,7 +74,7 @@ def get_mimetype(path): """ This method should return a suitable mimetype for the given `path`. - A mimetype is a short bytestring that tells a browser how to + A mimetype is a short byte string that tells a browser how to interpret the response body. For example, if the response body contains a web page then the mimetype should be b"text/html". If the response body contains a JPG image, then the mimetype would @@ -84,11 +95,22 @@ def get_mimetype(path): # This function should return an appropriate mimetype event # for files that don't exist. """ - - if path.endswith('/'): + try: + if path.endswith('/'): + return b"text/plain" + if path.endswith('.html'): + return b"text/html" + if path.endswith('.png'): + return b"image/png" + if path.endswith('.jpg'): + return b"image/jpg" + if path.endswith('.ico'): + return b"image/ico" + if path.endswith('.txt'): + return b"text/plain" + except FileNotFoundError: return b"text/plain" - else: - return b"TODO: FINISH THE REST OF THESE CASES" # TODO + @staticmethod def get_content(path): @@ -123,8 +145,20 @@ def get_content(path): # The file `webroot/a_page_that_doesnt_exist.html`) doesn't exist, # so this should raise a FileNotFoundError. """ + try: + if os.path.isdir(path): + entries = os.listdir(path) + return entries + + if os.path.isfile(path): + with open(path, 'r') as f: + data = f.read() + return data + + except FileNotFoundError: + return f"The file {path} does not exist" + - return b"Not implemented!" # TODO: Complete this function. def __init__(self, port): self.port = port From 085439d215024641d6e731eb6f7476b4793d5aa6 Mon Sep 17 00:00:00 2001 From: Andy Simpson Date: Tue, 13 Oct 2020 11:33:00 -0700 Subject: [PATCH 2/4] updated http_server.py, get_content(), get_path() and get_mimetype() functions. Now running Unittests - AS --- http_server.py | 61 +++++++++++++++++++++++++++++++++++++------------- unit-tests.py | 3 +++ 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/http_server.py b/http_server.py index d960ea4..97114d3 100644 --- a/http_server.py +++ b/http_server.py @@ -3,6 +3,8 @@ import traceback import os import mimetypes +import errno + class HttpServer(): @@ -55,18 +57,22 @@ def get_path(request): Then you would return "/images/sample_1.png" """ try: - if "favicon.ico" in request: + if b"favicon.ico" in request: return "/webroot/favicon.ico" - if "make_time.py" in request: + if b"make_time.py" in request: return "/webroot/make_time.py" - if "sample.txt" in request: + if b"sample.txt" in request: return "/webroot/sample.txt" - if "a_web_page.html" in request: + if b"a_web_page.html" in request: return "/webroot/a_web_page.html" + # else: + #return "/webroot/" #if b"favicon.ico" in request: #return "/webroot/a_web_page.html" except: - return "/" + header_parts = request.split(" ") + sub_string = header_parts[1] + return sub_string @staticmethod @@ -146,17 +152,42 @@ def get_content(path): # so this should raise a FileNotFoundError. """ try: - if os.path.isdir(path): - entries = os.listdir(path) - return entries - - if os.path.isfile(path): - with open(path, 'r') as f: - data = f.read() - return data - + #check_path = HttpServer.get_path(path) + cur_dir = sys.path[0] + "\\webroot\\" + #os.chdir(cur_dir) + webroot_dir = os.getcwd() + return_list = '' + if path == "/": + #os.path.isdir(check_path): + entries = os.listdir(cur_dir) + for item in entries: + return_list += item + '\n' + return bytes(return_list, 'utf-8') + + #if path == "/images/": + #os.path.isdir(check_path): + #entries = os.listdir(cur_dir) + #return entries + + if os.path.isfile(cur_dir + path): + file_path = os.path.join(cur_dir, path.strip('/')) + if '.html' in path: + with open(file_path, 'r') as fp: + Lines = fp.readlines() + new_html = "" + for line in Lines: + new_html += line.strip('\n') + '\r\n' + return bytes(new_html, 'utf-8') + else: + with open(file_path, 'r') as f: + data = f.read() + return data # bytes(data, 'utf-8')w + + #os.path.isfile(path) + raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), path) except FileNotFoundError: - return f"The file {path} does not exist" + raise FileNotFoundError + #return True diff --git a/unit-tests.py b/unit-tests.py index 8e4ae26..3f03834 100644 --- a/unit-tests.py +++ b/unit-tests.py @@ -70,4 +70,7 @@ def test_get_content_not_found(self): if __name__ == '__main__': + #test_get_content_file() + #test_get_content_not_found() + test_get_path() unittest.main() From 3fa9acddf27e29a9bb8f463b38f49a5db2e02434 Mon Sep 17 00:00:00 2001 From: Andy Simpson Date: Tue, 13 Oct 2020 16:32:30 -0700 Subject: [PATCH 3/4] Made it through all but 2 tests - AS --- http_server.py | 21 +++++++++++++++++++-- tests.py | 6 +++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/http_server.py b/http_server.py index 97114d3..7b89f05 100644 --- a/http_server.py +++ b/http_server.py @@ -108,14 +108,19 @@ def get_mimetype(path): return b"text/html" if path.endswith('.png'): return b"image/png" + if path.endswith('.jpg'): + if 'JPEG' in path: + return b"image/jpeg" return b"image/jpg" if path.endswith('.ico'): return b"image/ico" if path.endswith('.txt'): return b"text/plain" + if path.endswith('.py'): + return b"text/plain" except FileNotFoundError: - return b"text/plain" + return "" @staticmethod @@ -178,10 +183,22 @@ def get_content(path): for line in Lines: new_html += line.strip('\n') + '\r\n' return bytes(new_html, 'utf-8') + + if '.png' or '.jpg' in path: + with open(file_path, "rb") as image: + f = image.read() + #b = bytes(b, 'utf-8') + return f + if 'jpeg' in path: + #with open(file_path, "rb") as image: + #f = image.read() + #b = bytes(b, 'utf-8') + raise FileNotFoundError + else: with open(file_path, 'r') as f: data = f.read() - return data # bytes(data, 'utf-8')w + return bytes(data, 'utf-8') #os.path.isfile(path) raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), path) diff --git a/tests.py b/tests.py index 55c8af6..ce3ac48 100644 --- a/tests.py +++ b/tests.py @@ -99,6 +99,7 @@ def test_get_sample_scene_balls_jpeg_mime_type(self): response = self.get_response(web_path) self.assertEqual(response.getcode(), 200, error_comment) + self.assertEqual(response.getheader('Content-Type'), 'image/jpeg', error_comment) def test_get_sample_1_png(self): @@ -154,9 +155,11 @@ def test_images_index(self): local_path = os.path.join('webroot', directory) web_path = '/' + directory error_comment = "Error encountered while visiting " + web_path - + print(web_path) response = self.get_response(web_path) + body = response.read().decode() + print(os.getcwd()) for path in os.listdir(local_path): self.assertIn(path, body, error_comment) @@ -191,4 +194,5 @@ def test_ok_response_at_root_index(self): if __name__ == '__main__': + #test_get_sample_scene_balls_jpeg_mime_type() unittest.main() From ae77458804e31620075daaadd78e2861079a1a84 Mon Sep 17 00:00:00 2001 From: Joseph Schilz Date: Sun, 25 Oct 2020 16:45:13 -0700 Subject: [PATCH 4/4] Update http_server.py Great work! One lesson here is: whatever the type of the file, it can be processed the same way: read as bytes and passed onto the web browser. Using a "b" in the `open` makes this a little bit easier. This makes Python read the file directly as bytes, so that they don't have to be converted into bytes in a later line. --- http_server.py | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/http_server.py b/http_server.py index 7b89f05..3e28585 100644 --- a/http_server.py +++ b/http_server.py @@ -175,30 +175,9 @@ def get_content(path): #return entries if os.path.isfile(cur_dir + path): - file_path = os.path.join(cur_dir, path.strip('/')) - if '.html' in path: - with open(file_path, 'r') as fp: - Lines = fp.readlines() - new_html = "" - for line in Lines: - new_html += line.strip('\n') + '\r\n' - return bytes(new_html, 'utf-8') - - if '.png' or '.jpg' in path: - with open(file_path, "rb") as image: - f = image.read() - #b = bytes(b, 'utf-8') - return f - if 'jpeg' in path: - #with open(file_path, "rb") as image: - #f = image.read() - #b = bytes(b, 'utf-8') - raise FileNotFoundError - - else: - with open(file_path, 'r') as f: - data = f.read() - return bytes(data, 'utf-8') + with open(file_path, 'rb') as f: + data = f.read() + return data #os.path.isfile(path) raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), path)