-
Notifications
You must be signed in to change notification settings - Fork 1
Dev Web Server
refer Python Web Server DOCS
-
http.server
(python module or class which is imported):
This module defines classes for implementing HTTP servers (Web servers). - Classes in http.server:
- class
http.server.HTTPServer(server_address, RequestHandlerClass)
: implements the server i.e. its a server instance - class
http.server.BaseHTTPRequestHandler(request, client_address, server)
: This class is used to handle the HTTP requests that arrive at the server. By itself, it cannot respond to any actual HTTP requests; it must be inherited to handle each request method (e.g.GET
orPOST
).BaseHTTPRequestHandler
provides a number of class and instance variables, and methods for use by child class. For more info about the implementables (variables and functions) of this abstract class, go HERE
- class
this is the class that we inherit as part of Our custom
WebServer
class and then implement theGET
andPOST
functions using custom funcs (do_GET()
anddo_POST()
)
if __name__ == "__main__":
import MasterControl
else:
from . import MasterControl
If the app is debugged using staring from WebServer.py
, then we need the import to be direct (import MasterControl
), but when init.py
imports WebServer.py
, the import must be relative, i.e. like from . import MasterControl
from sys import exit as ExitProgram
from http.server import *
import os
from pathlib import Path
httpd = None
PORT = 8182
CurrentDir = Path(os.path.dirname(__file__))
class WebServer(BaseHTTPRequestHandler):
This is where all handling of requests to do work will be executed, that is, within an instance of this class, which is THIS
It must be noted that this class is a handler class, which derives (inherits) from the BaseHTTPRequestHandler
class and implements the predefined do_GET
and do_POST
functions as per our requirement, and IT ITSELF BECOMES A HANDLER CLASS. (which handles requests!)
All get requests made by the web page go through here:
def do_GET(self):
IF there is an error, a 404 file not found is sent back to the browser
In this part of the code, HTML File requests are handled
if 'html' in self.path or self.path == '/':
try:
'''
This part here check for what file is requested and sends it. But, if the request is for
index page and if the DB has been initiated, an error is returned. similarly, if request is
for todo page and database is not created it returns an error.
also, '/', '' and '/index.html' return the same page i.e. index.html
'''
self.send_response(200)
self.send_header('Content-type','text/html')
except:
file_to_open = "File not found"
self.send_response(404)
self.end_headers()
self.wfile.write(bytes(file_to_open, 'utf-8'))
When HTML files are requested, their internal code directs the browser to also get the JS code file mentioned int here to use it in the web page:
if '/JS' in self.path:
try:
file_to_open = open(....).read() #JS file is opened here
self.send_response(200)
self.send_header('Content-type','application/javascript')
except:
file_to_open = "File not found"
self.send_response(404)
self.end_headers()
self.wfile.write(bytes(file_to_open, 'utf-8'))
When HTML files are requested, their internal code directs the browser to also get the CSS code file mentioned int here to apply it on the web page:
if '/CSS' in self.path:
try:
file_to_open = open(....).read() #CSS file is opened here
self.send_response(200)
self.send_header('Content-type','text/css')
except:
file_to_open = "File not found"
self.send_response(404)
self.end_headers()
self.wfile.write(bytes(file_to_open, 'utf-8'))
When the user asks to export the file, the file is read in rb
mode, i.e. read as bytes and sent back as an octet-stream
which is fancy way of saying bits
if self.path.endswith("Temp.db"):
self.path = 'Models\Temp.db'
try:
MasterControl.WriteToTempDB()
with open(os.path.join(CurrentDir,self.path), mode='rb') as file: # b is important -> binary
fileContent = file.read()
self.send_response(200)
self.send_header('Content-type','application/octet-stream')
except:
fileContent = "File not found"
self.send_response(404)
self.end_headers()
self.wfile.write(fileContent)
if self.path.endswith("ListData"):
try:
fileContent = MasterControl.GetListDataAsString()
self.send_response(200)
except:
fileContent = "Somethings is wrong. Sorry!"
self.send_response(404)
self.end_headers()
self.wfile.write(bytes(fileContent,'utf-8'))
return
- All post requests made by the web page go through here:
there
responseText
variable is the one which is sent back to the browser. by default it is "Ignore this message!". - When the POST request is made, a string is sent with the request values, and some other data, which is given to the server as bytes in
self.rfile
file. So, we read the file only upto the amount of data that we are supposed to use, i.e. upto thecontentLength
of the file which is provided to us by the POST request of the browser. - Then, multiple
if
statements check for what request has been made:
def do_POST(self):
responseText = "Ignore this message!"
contentLength = int(self.headers['Content-Length']) # <-- Gets the size of data
if self.path.endswith("NewToDoDataBase"):
#goes to MasterControl
if self.path.endswith("Temp.db"):
#goes to MasterControl
In MasterControl.py
, for
after the functions are executed and returned, the request response is sent back to browser
- Each of these
if
statements are used for LIST and TASK manipulation, by getting the manipulation data from the server and then passing it on to MasterControl.py: example:
if self.path.endswith("Edit"):
Data = self.rfile.read(contentLength).decode('utf-8')
print("~Request string: "+Data)
responseText = MasterControl.EditItem(Data)
- The
if
statements have been showed only for one example, the rest of the statements call the given links inMasterControl.py
: a. Edit task b. Delete task c. Done or undone task d. Add task e. Edit List Name f. Delete List g. Add List
if self.path.endswith("DestroyToDoDBFrame"):
#goes to MasterControl
if self.path.endswith("ShutDownServer"):
print("Shutdown command received from webpage")
ExitProgram() #This has been imported
if self.path.endswith("DispToDoDataFrame"):
MasterControl.DispToDoDataFrame()
self.send_response(200)
self.end_headers()
self.wfile.write(bytes(responseText,'utf-8'))
-
self.send_response(200)
makes sure code is successfully read and sent,self.end_headers()
end the request response headers andself.wfile.write(bytes(responseText,'utf-8'))
send the response to the server by writing it to thewfile
which is built into the web server class handler.
- Here, we make a server and pass
webserver
class to it as the handler class, since it handles the custom code we wrote
def Start():
global httpd
httpd = HTTPServer(('localhost', PORT), WebServer)
- here
httpd.serve_forever()
runs the server andhttpd.socket.close()
shuts it down. We try to serve forever, and if a keyboard interrupt is received it shuts down and returns toinit.py
try:
httpd.serve_forever()
From here the function moves to answering requests HERE
except (KeyboardInterrupt,SystemExit): #this is the ctrl + C interrupt
print(MasterControl.Shutdown(CurrentDir))
httpd.socket.close()
This is a default error
except:
print("~There was an error in running the server")