diff --git a/README.md b/README.md index d6888ed1..6a2526ac 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -CMPUT404-assignment-webserver -============================= +# CMPUT404-assignment-webserver CMPUT404-assignment-webserver @@ -7,20 +6,49 @@ See requirements.org (plain-text) for a description of the project. Make a simple webserver. -Contributors / Licensing -======================== +# Contributors / Licensing Generally everything is LICENSE'D under the Apache 2 license by Abram Hindle. server.py contains contributions from: -* Abram Hindle -* Eddie Antonio Santos -* Jackson Z Chang -* Mandy Meindersma +- Abram Hindle +- Eddie Antonio Santos +- Jackson Z Chang +- Mandy Meindersma +- Ferdous Adit But the server.py example is derived from the python documentation -examples thus some of the code is Copyright © 2001-2013 Python +examples thus some of the code is Copyright © 2001-2023 Python Software Foundation; All Rights Reserved under the PSF license (GPL compatible) http://docs.python.org/2/library/socketserver.html +- root.png +- deep.png + +Screenshots are derivative works and as such subject to the copyright of +the displayed content, may it be a video, television program, or a computer +program. Thus, screenshots must not be uploaded to Wikimedia Commons unless +all content in them is under a https://en.wikipedia.org/wiki/Free_license or +in the public domain. + +# Credit or References + +- BogoToBogo
+https://www.bogotobogo.com/python/python_network_programming_socketserver_framework_for_network_servers.php
+Network Programming III - SocketServer
+ +- Tech With Tim
+https://www.youtube.com/@TechWithTim
+Python Socket Programming Tutorial
+https://youtu.be/3QiPPX-KeSc
+Youtube
+ +- jbx
+https://stackoverflow.com/users/340088/jbx
+https://stackoverflow.com/a/53070496
+Stackoverflow
+ +- PyMOTW
+http://pymotw.com/2/SocketServer/
+SocketServer – Creating network servers
diff --git a/deep.png b/deep.png new file mode 100644 index 00000000..6366ad69 Binary files /dev/null and b/deep.png differ diff --git a/root.png b/root.png new file mode 100644 index 00000000..c9801750 Binary files /dev/null and b/root.png differ diff --git a/server.py b/server.py index bc5a725c..d7ce49b9 100644 --- a/server.py +++ b/server.py @@ -1,14 +1,17 @@ -# coding: utf-8 +# coding: utf-8 import socketserver +import os -# Copyright 2013 Abram Hindle, Eddie Antonio Santos -# +# Copyright 2023 Abram Hindle, Eddie Antonio Santos +# +# Updated by Ferdous Adit, 1538839. +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,7 +20,7 @@ # # # Furthermore it is derived from the Python documentation examples thus -# some of the code is Copyright © 2001-2013 Python Software +# some of the code is Copyright © 2001-2023 Python Software # Foundation; All Rights Reserved # # http://docs.python.org/2/library/socketserver.html @@ -28,11 +31,177 @@ class MyWebServer(socketserver.BaseRequestHandler): - + extension_code = { + 'NOTHING': None, + 'INDEX_PAGE': 'index.html', + 'NOT_FOUND': '404' + } + SPACE = '\r\n' + END = '\r\n\r\n' + NOT_OKAY = -1 + OKAY = 1 + def handle(self): self.data = self.request.recv(1024).strip() - print ("Got a request of: %s\n" % self.data) - self.request.sendall(bytearray("OK",'utf-8')) + print("Got a request of: %s\n" % self.data) + + # Now that we have the response. We need to parse it. parse_request + # already decodes the data. + request_is_good = self.parse_request(self.data) + + if request_is_good == self.NOT_OKAY: # handling any POST/PUT/DELETE request + self.request.sendall(bytearray( + f"HTTP/1.1 405 METHOD NOT ALLOWED{self.SPACE}Content-Type: 'text/html'{self.SPACE}Content-Length: 42{self.SPACE} encoding=utf-8{self.END}405 METHOD NOT ALLOWED", 'utf-8')) + return + + elif self.extension == 'index.html': # directed to default index.html + self.serve_default_index() + return + + elif self.extension == 'deep_index.html': + self.serve_deep_index() + return + + elif self.extension == 'base.css': + self.serve_default_css() + return + + elif self.extension == 'hardcode_index.html': + self.serve_hardcode_index() + return + + elif self.extension == 'hardcode_deep_index.html': + self.serve_hardcode_deep_index() + return + + elif self.parse_redirect() == 1: + self.serve_redirect(1) + return + + elif self.extension == '404': + self.request.sendall(bytearray( + f"HTTP/1.1 404 NOT FOUND\r\ncontent-Type: text/html; encoding=utf-8\r\n\r\nThis works!", 'utf-8')) + return + + def parse_request(self, data): + self.data = data.decode('utf-8') + # Is the message anything other than GET? + if self.data[:3] != 'GET': + return -1 + + self.extension = '' + # If root or directly requesting index.html + if self.parse_request_default_html(): + self.extension = 'index.html' + elif self.parse_request_deep_html(): + self.extension = 'deep_index.html' + elif self.parse_request_default_css(): + self.extension = 'base.css' + elif self.parse_request_hardcode_html(): + self.extension = 'hardcode_index.html' + elif self.parse_request_hardcode_deep_html(): + self.extension = 'hardcode_deep_index.html' + + # elif self.data[] + + else: # request is okay but cannot find the extension requested. + self.extension = '404' + return 1 + + """ + Parse the request path methods. --------------------------------- + """ + + def parse_request_default_html(self): + if self.data[4:6] == '/ ' \ + or self.data[4:17] == '/index.html/ ' \ + or self.data[4:16] == '/index.html ': + return True + return False + + def parse_request_deep_html(self): + end = self.data.find("HTTP") + if self.data[4:end] == '/deep/ ' \ + or self.data[4:end] == '/deep/index.html '\ + or self.data[4:end] == '/deep/index.html/ ': + return True + return False + + def parse_request_hardcode_html(self): + end = self.data.find("HTTP") + end = end - 1 + if self.data[4:end] == '/hardcode/'\ + or self.data[4:end] == '/hardcode/index.html'\ + or self.data[4:end] == '/hardcode/index.html/': + return True + return False + + def parse_request_hardcode_deep_html(self): + end = self.data.find("HTTP") + end = end - 1 + if self.data[4:end] == '/hardcode/deep/'\ + or self.data[4:end] == '/hardcode/deep/index.html'\ + or self.data[4:end] == '/hardcode/deep/index.html/': + return True + return False + + def parse_redirect(self): + end = self.data.find("HTTP") + end = end - 1 + if self.data[4:end] == '/deep': + return 1 + + def parse_request_default_css(self): + end = self.data.find("HTTP") + if self.data[4:end] == '/base.css ' \ + or self.data[4:end] == '/base.css/ ': + return True + return False + + """ + Serve the page methods. ---------------------------------------- + """ + + def serve_default_css(self): + with open(os.getcwd() + "/www/base.css", 'r') as file: + f_holder = file.read() + f_holder = f_holder.replace('\n', '') + self.request.sendall(bytearray( + f"HTTP/1.1 200 OK{self.SPACE}Content-Type: text/css{self.SPACE}{self.END}{f_holder}", 'utf-8')) + + def serve_redirect(self, value): + if value == 1: + self.request.sendall(bytearray( + f"HTTP/1.1 301 MOVED PERMANENTLY{self.SPACE}Location: http://127.0.0.1:8080/deep/{self.SPACE}{self.END}", 'utf-8')) + + def serve_hardcode_deep_index(self): + with open(os.getcwd() + "/www/hardcode/deep/index.html", 'r') as file: + f_holder = file.read() + f_holder = f_holder.replace('\n', '') + self.request.sendall(bytearray( + f"HTTP/1.1 200 OK{self.SPACE}Content-Type: text/html{self.SPACE}{self.END}{f_holder}", 'utf-8')) + + def serve_deep_index(self): + with open(os.getcwd() + "/www/deep/index.html", 'r') as file: + f_holder = file.read() + f_holder = f_holder.replace('\n', '') + self.request.sendall(bytearray( + f"HTTP/1.1 200 OK{self.SPACE}Content-Type: text/html{self.SPACE}{self.END}{f_holder}", 'utf-8')) + + def serve_default_index(self): + with open(os.getcwd() + "/www/index.html", 'r') as file: + f_holder = file.read() + f_holder = f_holder.replace('\n', '') + self.request.sendall(bytearray( + f"HTTP/1.1 200 OK{self.SPACE}Content-Type: text/html{self.SPACE}{self.END}{f_holder}", 'utf-8')) + + def serve_hardcode_index(self): + with open(os.getcwd() + "/www/hardcode/index.html", 'r') as file: + f_holder = file.read() + f_holder = f_holder.replace('\n', '') + self.request.sendall(bytearray( + f"HTTP/1.1 200 OK{self.SPACE}Content-Type: text/html{self.SPACE}{self.END}{f_holder}", 'utf-8')) + if __name__ == "__main__": HOST, PORT = "localhost", 8080 diff --git a/www/hardcode/deep.css b/www/hardcode/deep.css new file mode 100644 index 00000000..baafb8d2 --- /dev/null +++ b/www/hardcode/deep.css @@ -0,0 +1,4 @@ +h1 { + color:green; + text-align:center; +} diff --git a/www/hardcode/deep/deep.css b/www/hardcode/deep/deep.css new file mode 100644 index 00000000..baafb8d2 --- /dev/null +++ b/www/hardcode/deep/deep.css @@ -0,0 +1,4 @@ +h1 { + color:green; + text-align:center; +} diff --git a/www/hardcode/deep/index.html b/www/hardcode/deep/index.html new file mode 100644 index 00000000..ca0d6280 --- /dev/null +++ b/www/hardcode/deep/index.html @@ -0,0 +1,20 @@ + + + + Deeper Example Page + + + + + + +
+

An Example of a Deeper Page

+ +
+ + diff --git a/www/hardcode/index.html b/www/hardcode/index.html new file mode 100644 index 00000000..ca0d6280 --- /dev/null +++ b/www/hardcode/index.html @@ -0,0 +1,20 @@ + + + + Deeper Example Page + + + + + + +
+

An Example of a Deeper Page

+ +
+ +