read only http finished
This commit is contained in:
parent
a4846211dc
commit
3b3f15a6ac
60
http.py
60
http.py
@ -33,10 +33,10 @@ Fork = False
|
|||||||
# i suspect this one might be ai generated.
|
# i suspect this one might be ai generated.
|
||||||
# It's a subclass of dict with key access via the dot
|
# It's a subclass of dict with key access via the dot
|
||||||
# operator. Similar to how ruby does things
|
# 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
|
# Obviously some things still need standard dictionary access
|
||||||
# client's code in a public project.
|
# i found this code looked at it, tested it, before using it
|
||||||
# Thus cut 'n' paste.
|
#
|
||||||
|
|
||||||
CRLF = "\r\n"
|
CRLF = "\r\n"
|
||||||
LF = "\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
|
# 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
|
# implementation. This is just making us ssl ready and laying the ground work
|
||||||
class HttpRequest(AccessDict):
|
class HttpRequest(AccessDict):
|
||||||
def __init__(
|
def __init__(self, method="GET", path="/", headers={}, *args, **kwargs):
|
||||||
self, method="GET", path="/", headers={}, body="goodbye\r\n", *args, **kwargs
|
|
||||||
):
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self["method"] = method
|
self["method"] = method
|
||||||
self["headers"] = headers
|
self["headers"] = headers
|
||||||
self["body"] = StringIO(body)
|
if "body" in kwargs:
|
||||||
|
self["body"] = StringIO(kwargs["body"])
|
||||||
self["path"] = path
|
self["path"] = path
|
||||||
if "Host" not in self["headers"]:
|
if "Host" not in self["headers"]:
|
||||||
self["headers"]["Host"] = "localhost"
|
self["headers"]["Host"] = "localhost"
|
||||||
@ -96,14 +95,14 @@ class HttpRequest(AccessDict):
|
|||||||
buf = StringIO()
|
buf = StringIO()
|
||||||
buf.write(f"{self.method} {self.path} HTTP/1.1")
|
buf.write(f"{self.method} {self.path} HTTP/1.1")
|
||||||
for k, v in self["headers"].items():
|
for k, v in self["headers"].items():
|
||||||
buf.write(f"{k}: {v}\r\n")
|
buf.write(f"{k}: {v}" + CRLF)
|
||||||
buf.write(CRLF + CRLF)
|
buf.write(CRLF)
|
||||||
buf.write(self["body"].getvalue() + "\r\n")
|
buf.write(self["body"].getvalue() + CRLF)
|
||||||
return buf.getvalue() + "\r\n"
|
return buf.getvalue() + CRLF
|
||||||
|
|
||||||
|
|
||||||
class HttpResponse(AccessDict):
|
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)
|
super().__init__(*args, **kwargs)
|
||||||
self["status"] = status
|
self["status"] = status
|
||||||
self["headers"] = headers
|
self["headers"] = headers
|
||||||
@ -125,15 +124,16 @@ class HttpResponse(AccessDict):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
buf = StringIO()
|
buf = StringIO()
|
||||||
print(self.headers)
|
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())
|
length = len(self["body"].getvalue())
|
||||||
for k, v in self["headers"].items():
|
for k, v in self["headers"].items():
|
||||||
buf.write(f"{k}: {v}\r\n")
|
buf.write(f"{k}: {v}\r\n")
|
||||||
|
if "Content-Length" not in self["headers"]:
|
||||||
buf.write(f"Content-Length: {length}\r\n")
|
buf.write(f"Content-Length: {length}\r\n")
|
||||||
buf.write(CRLF + CRLF) # Per RFC 9112
|
buf.write(CRLF) # Per RFC 9112
|
||||||
|
|
||||||
buf.write(self["body"].getvalue() + "\r\n")
|
buf.write(self["body"].getvalue() + CRLF)
|
||||||
return buf.getvalue() + "\r\n"
|
return buf.getvalue() + CRLF
|
||||||
|
|
||||||
|
|
||||||
RICKROLL_LYRICS = """
|
RICKROLL_LYRICS = """
|
||||||
@ -170,6 +170,10 @@ Never gonna make you cry, never gonna say goodbye
|
|||||||
Never gonna tell a lie and hurt you
|
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 = HttpResponse()
|
||||||
good_response.status = 200
|
good_response.status = 200
|
||||||
good_response.headers["Last-Modified"] = "Mon, 27 July 1987 00:00 GMT"
|
good_response.headers["Last-Modified"] = "Mon, 27 July 1987 00:00 GMT"
|
||||||
@ -209,7 +213,7 @@ def server_handler():
|
|||||||
return
|
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
|
# This will still accept anything as long as the method verb
|
||||||
# is correct. Clients need not conform to RFC 9112 (yet).
|
# is correct. Clients need not conform to RFC 9112 (yet).
|
||||||
# We however, do our best effort to conform to rfc 9112,
|
# 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
|
# the client, but strict in what you send back, was first
|
||||||
# was first forumlated by John Postel in that later half
|
# was first forumlated by John Postel in that later half
|
||||||
# of the 1970s.
|
# 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):
|
def client_handler(sock):
|
||||||
@ -234,11 +249,16 @@ def client_handler(sock):
|
|||||||
dstring = data.decode("UTF-8")
|
dstring = data.decode("UTF-8")
|
||||||
if dstring.startswith("GET"):
|
if dstring.startswith("GET"):
|
||||||
break
|
break
|
||||||
|
elif dstring.startswith("HEAD"):
|
||||||
|
hr = str(head_response)
|
||||||
|
sock.send(hr.encode("utf-8"))
|
||||||
|
sock.close()
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
error = str(error_response)
|
error = str(error_response)
|
||||||
sock.send(error.encode("utf-8"))
|
sock.send(error.encode("utf-8"))
|
||||||
junk_counter += 1
|
junk_counter += 1
|
||||||
gevent.sleep(0.25)
|
gevent.sleep(0.25) # this is a somewhat magical value
|
||||||
default = str(good_response)
|
default = str(good_response)
|
||||||
sock.send(default.encode("utf-8"))
|
sock.send(default.encode("utf-8"))
|
||||||
sock.close()
|
sock.close()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user