read only http finished
This commit is contained in:
parent
a4846211dc
commit
3b3f15a6ac
62
http.py
62
http.py
@ -33,10 +33,10 @@ Fork = False
|
||||
# i suspect this one might be ai generated.
|
||||
# It's a subclass of dict with key access via the dot
|
||||
# operator. Similar to how ruby does things
|
||||
# I don't know why this isn't the default
|
||||
# i've coded this dozens of times but i couldn't use
|
||||
# client's code in a public project.
|
||||
# Thus cut 'n' paste.
|
||||
|
||||
# Obviously some things still need standard dictionary access
|
||||
# i found this code looked at it, tested it, before using it
|
||||
#
|
||||
|
||||
CRLF = "\r\n"
|
||||
LF = "\n"
|
||||
@ -78,13 +78,12 @@ class AccessDict(dict):
|
||||
# In a future part. I will go over how to make a more full featured
|
||||
# implementation. This is just making us ssl ready and laying the ground work
|
||||
class HttpRequest(AccessDict):
|
||||
def __init__(
|
||||
self, method="GET", path="/", headers={}, body="goodbye\r\n", *args, **kwargs
|
||||
):
|
||||
def __init__(self, method="GET", path="/", headers={}, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self["method"] = method
|
||||
self["headers"] = headers
|
||||
self["body"] = StringIO(body)
|
||||
if "body" in kwargs:
|
||||
self["body"] = StringIO(kwargs["body"])
|
||||
self["path"] = path
|
||||
if "Host" not in self["headers"]:
|
||||
self["headers"]["Host"] = "localhost"
|
||||
@ -96,14 +95,14 @@ class HttpRequest(AccessDict):
|
||||
buf = StringIO()
|
||||
buf.write(f"{self.method} {self.path} HTTP/1.1")
|
||||
for k, v in self["headers"].items():
|
||||
buf.write(f"{k}: {v}\r\n")
|
||||
buf.write(CRLF + CRLF)
|
||||
buf.write(self["body"].getvalue() + "\r\n")
|
||||
return buf.getvalue() + "\r\n"
|
||||
buf.write(f"{k}: {v}" + CRLF)
|
||||
buf.write(CRLF)
|
||||
buf.write(self["body"].getvalue() + CRLF)
|
||||
return buf.getvalue() + CRLF
|
||||
|
||||
|
||||
class HttpResponse(AccessDict):
|
||||
def __init__(self, status="404", headers={}, body="goodbye\r\n", *args, **kwargs):
|
||||
def __init__(self, status="400", headers={}, body="goodbye\r\n", *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self["status"] = status
|
||||
self["headers"] = headers
|
||||
@ -125,15 +124,16 @@ class HttpResponse(AccessDict):
|
||||
def __str__(self):
|
||||
buf = StringIO()
|
||||
print(self.headers)
|
||||
buf.write(f"HTTP/1.1 {self.status}\r\n")
|
||||
buf.write(f"HTTP/1.1 {self.status}" + CRLF)
|
||||
length = len(self["body"].getvalue())
|
||||
for k, v in self["headers"].items():
|
||||
buf.write(f"{k}: {v}\r\n")
|
||||
buf.write(f"Content-Length: {length}\r\n")
|
||||
buf.write(CRLF + CRLF) # Per RFC 9112
|
||||
if "Content-Length" not in self["headers"]:
|
||||
buf.write(f"Content-Length: {length}\r\n")
|
||||
buf.write(CRLF) # Per RFC 9112
|
||||
|
||||
buf.write(self["body"].getvalue() + "\r\n")
|
||||
return buf.getvalue() + "\r\n"
|
||||
buf.write(self["body"].getvalue() + CRLF)
|
||||
return buf.getvalue() + CRLF
|
||||
|
||||
|
||||
RICKROLL_LYRICS = """
|
||||
@ -170,6 +170,10 @@ Never gonna make you cry, never gonna say goodbye
|
||||
Never gonna tell a lie and hurt you
|
||||
|
||||
"""
|
||||
head_response = HttpResponse()
|
||||
head_response.status = 200
|
||||
head_response.headers["Content-Length"] = 980
|
||||
head_response.write("")
|
||||
good_response = HttpResponse()
|
||||
good_response.status = 200
|
||||
good_response.headers["Last-Modified"] = "Mon, 27 July 1987 00:00 GMT"
|
||||
@ -209,7 +213,7 @@ def server_handler():
|
||||
return
|
||||
|
||||
|
||||
# I made two simple changes to make it use our new http objects
|
||||
# I made three simple changes to make it use our new http objects
|
||||
# This will still accept anything as long as the method verb
|
||||
# is correct. Clients need not conform to RFC 9112 (yet).
|
||||
# We however, do our best effort to conform to rfc 9112,
|
||||
@ -219,8 +223,19 @@ def server_handler():
|
||||
# the client, but strict in what you send back, was first
|
||||
# was first forumlated by John Postel in that later half
|
||||
# of the 1970s.
|
||||
#
|
||||
# Lastly we add support for the HEAD method, as some http clients
|
||||
# Will get confused if we don't have it
|
||||
# RFC 9112 appears to say GET and HEAD are the only methods we
|
||||
# are ABSOLUTELY REQUIRED to support. So we add it.abs
|
||||
# At this point it will get a static response as well.
|
||||
# See Above.
|
||||
|
||||
# Doing this, is also motivation for me to write Parts 4, 5, and 6
|
||||
# Doing this, is also motivation for me to write Parts 1, 2, and 3
|
||||
# By the way you're in a Star Wars, Sort of thing
|
||||
# This is Part 5. I thought the 4 would be more entertaining.abs
|
||||
# Parts 7, 8, and 9 will be made for Capitalism reasons
|
||||
# AKA Donate on my kofi link at the end.
|
||||
|
||||
|
||||
def client_handler(sock):
|
||||
@ -234,11 +249,16 @@ def client_handler(sock):
|
||||
dstring = data.decode("UTF-8")
|
||||
if dstring.startswith("GET"):
|
||||
break
|
||||
elif dstring.startswith("HEAD"):
|
||||
hr = str(head_response)
|
||||
sock.send(hr.encode("utf-8"))
|
||||
sock.close()
|
||||
return
|
||||
else:
|
||||
error = str(error_response)
|
||||
sock.send(error.encode("utf-8"))
|
||||
junk_counter += 1
|
||||
gevent.sleep(0.25)
|
||||
gevent.sleep(0.25) # this is a somewhat magical value
|
||||
default = str(good_response)
|
||||
sock.send(default.encode("utf-8"))
|
||||
sock.close()
|
||||
|
Loading…
x
Reference in New Issue
Block a user