diff --git a/http_server.py b/http_server.py
index 58d7386..c75307e 100644
--- a/http_server.py
+++ b/http_server.py
@@ -1,6 +1,10 @@
import socket
import sys
import traceback
+import os
+import mimetypes
+import subprocess
+
def response_ok(body=b"This is a minimal response", mimetype=b"text/plain"):
"""
@@ -18,34 +22,45 @@ def response_ok(body=b"This is a minimal response", mimetype=b"text/plain"):
Welcome:
\r\n
'''
"""
-
# TODO: Implement response_ok
- return b""
+ return b"\r\n".join([
+ b"HTTP/1.1 200 OK",
+ b"Content-Type: " + mimetype,
+ b"", # indicate the begining of body part of the HTTP response.
+ 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 server!",
+ ])
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"Not Found response!",
+ ])
def parse_request(request):
"""
Given the content of an HTTP request, returns the path of that request.
-
This server only handles GET requests, so this method shall raise a
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):
"""
@@ -74,22 +89,51 @@ 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.
-
- # 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"
- return content, mime_type
+ file_dir = os.path.join(os.getcwd(), 'webroot')
+ file_name = os.path.join(file_dir, *path.split('/'))
+ #print('--- filename:{}'.format(file_name))
+
+ content = ''
+ mime_type = ''
+
+ if os.path.isdir(file_name):
+ for file in os.listdir(file_name):
+ content += '{}\n'.format(file)
+ mime_type = "text/plain"
+ return content.encode(), mime_type.encode()
+
+ if os.path.isfile(file_name):
+ # 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
+ root, extension = os.path.splitext(file_name)
+ try:
+ # mime_type = mimetypes.guess_type(file_name)[0]
+ mime_type = mimetypes.types_map[extension]
+ except Exception:
+ print(f"Can't find the mimetype for file extension:{extension}")
+ sys.exit()
+ # 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`.
+ if path == '/make_time.py':
+ result = subprocess.run(["python", file_name],
+ stdout=subprocess.PIPE,
+ # text=True for regular string, default
+ # stdout is bytestring.
+ #text=True,
+ )
+ content = result.stdout
+ # If the file is not 'make_time.py', then return the file content
+ else:
+ with open(file_name, 'rb') as f:
+ content = f.read()
+ return content, mime_type.encode()
+
+ # Raise a NameError if the requested content is not present under webroot.
+ raise NameError
def server(log_buffer=sys.stderr):
@@ -114,40 +158,44 @@ 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"
- )
+ try:
+ # TODO: Use parse_request to retrieve the path from the request.
+ # If parse_request raised a NotImplementedError, then let
+ # response be a method_not_allowed response.
+ 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)
+ # 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=content,
+ mimetype=mimetype
+ )
+ except NotImplementedError:
+ response = response_method_not_allowed()
+
+ except NameError:
+ response = response_not_found()
conn.sendall(response)
- except:
+ except Exception as e:
traceback.print_exc()
finally:
- conn.close()
+ conn.close()
except KeyboardInterrupt:
sock.close()
return
- except:
+ except Exception as e:
traceback.print_exc()
if __name__ == '__main__':
server()
sys.exit(0)
-
-
diff --git a/tests.py b/tests.py
index 21da57e..d984ec1 100644
--- a/tests.py
+++ b/tests.py
@@ -47,8 +47,9 @@ def test_post_yields_method_not_allowed(self):
conn.close()
- self.assertEqual(response.getcode(), 405)
-
+ # both .getcode() and .status can be used to check the response code.
+ self.assertEqual(response.status, 405)
+ #self.assertEqual(response.getcode(), 405)
def test_get_sample_text_content(self):
"""
@@ -64,6 +65,7 @@ def test_get_sample_text_content(self):
self.assertEqual(response.getcode(), 200, error_comment)
+ # response.read() will read the http response body.
with open(local_path, 'rb') as f:
self.assertEqual(f.read(), response.read(), error_comment)
@@ -79,7 +81,9 @@ def test_get_sample_text_mime_type(self):
response = self.get_response(web_path)
self.assertEqual(response.getcode(), 200, error_comment)
- self.assertEqual(response.getheader('Content-Type'), 'text/plain', error_comment)
+ # response.getheader(header_name) will return the value of the header name
+ self.assertEqual(response.getheader('Content-Type'),
+ 'text/plain', error_comment)
def test_get_sample_scene_balls_jpeg(self):
"""
@@ -110,7 +114,8 @@ 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)
+ self.assertEqual(response.getheader('Content-Type'),
+ 'image/jpeg', error_comment)
def test_get_sample_1_png(self):
"""
@@ -190,7 +195,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 = ''
@@ -200,6 +205,24 @@ def test_ok_response_at_root_index(self):
self.assertEqual(response.getcode(), 200)
+ def test_make_time_python_file(self):
+ """
+ A call to wobroot/make_time.py and execute the file and serve up the
+ result of performing that execution.
+ """
+ file = 'make_time.py'
+
+ web_path = '/' + file
+ error_comment = "Error encountered while visiting " + web_path
+
+ response = self.get_response(web_path)
+
+ self.assertEqual(response.getcode(), 200, error_comment)
+ self.assertEqual(response.getheader('Content-Type'),
+ 'text/x-python', error_comment)
+ # HTTPResponse.read() will read the response body in bytestring.
+ self.assertIn('', response.read().decode(), error_comment)
+
if __name__ == '__main__':
unittest.main()
diff --git a/unit-tests.py b/unit-tests.py
index a0c657a..9e823fb 100644
--- a/unit-tests.py
+++ b/unit-tests.py
@@ -53,7 +53,7 @@ def test_response_path_file(self):
content, mime_type = http_server.response_path(path)
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)