Add intermediate step student_1 after exo 3.2.

This commit is contained in:
Boris Baldassari 2024-03-08 08:41:16 +01:00
parent 687f83ff8d
commit 7700413031
5 changed files with 48 additions and 43 deletions

View file

@ -26,6 +26,21 @@ def parse_request(buf: bytes) -> dict[str, dict]:
- params: dict[str, str] - params: dict[str, str]
List of the HTTP parameters (i.e. the following lines); List of the HTTP parameters (i.e. the following lines);
output of `parse_request_params`. output of `parse_request_params`.
An example of return:
```
{
'head': { 'verb': 'GET', 'resource': '//index.html'},
'params': {
'Host': 'localhost:8000',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-GB,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br',
[SNIP]
}
}
```
Parameters Parameters
---------- ----------

View file

@ -106,7 +106,6 @@ def handle_client(c: socket.socket, addr: tuple[str, int], root:str):
c.close() c.close()
def prepare_resource(root: str, req: dict): def prepare_resource(root: str, req: dict):
""" """
Retrieves the content of the resource and sets the status code. Retrieves the content of the resource and sets the status code.

View file

@ -121,9 +121,9 @@ def prepare_resource(root: str, req: dict):
- code: int - code: int
The status code for the reply. The status code for the reply.
""" """
code = 1234 code = 200
content = b"" content = b"Hello World!"
content_type = "" content_type = "text/html"
# Call resolve_location(). # Call resolve_location().
# If an empty string is returned, the resource is not found. # If an empty string is returned, the resource is not found.

View file

@ -14,7 +14,6 @@ A package for learning network programming in Python.
This module (file) manages the parsing of HTTP requests. This module (file) manages the parsing of HTTP requests.
""" """
# TODO: Gestion de la casse des paramètres ?
def parse_request(buf: bytes) -> dict[str, dict]: def parse_request(buf: bytes) -> dict[str, dict]:
"""Parses a full HTTP request bytes buffer into a dict. """Parses a full HTTP request bytes buffer into a dict.
@ -26,6 +25,21 @@ def parse_request(buf: bytes) -> dict[str, dict]:
- params: dict[str, str] - params: dict[str, str]
List of the HTTP parameters (i.e. the following lines); List of the HTTP parameters (i.e. the following lines);
output of `parse_request_params`. output of `parse_request_params`.
An example of return:
```
{
'head': { 'verb': 'GET', 'resource': '//index.html'},
'params': {
'Host': 'localhost:8000',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-GB,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br',
[SNIP]
}
}
```
Parameters Parameters
---------- ----------
@ -42,14 +56,8 @@ def parse_request(buf: bytes) -> dict[str, dict]:
ValueError ValueError
The request is not valid HTTP. The request is not valid HTTP.
""" """
if buf == b'': req_head = dict()
raise ValueError("Received empty request")
lines = buf.decode('utf-8').strip().splitlines()
req_head = parse_request_head(lines[0])
req_params = dict() req_params = dict()
if len(lines) > 1:
req_params = parse_request_params(lines[1:])
return dict( return dict(
head=req_head, head=req_head,
@ -82,13 +90,12 @@ def parse_request_head(line: str) -> dict[str, str]:
ValueError ValueError
The request header is not valid HTTP. The request header is not valid HTTP.
""" """
fields = line.split(' ')
if len(fields) != 3: pass
raise ValueError(f"Request header is invalid: {line}")
return dict( return dict(
verb=fields[0].upper(), verb=None,
resource=fields[1] resource=None
) )
def parse_request_params(lines: list[str]) -> dict[str, str]: def parse_request_params(lines: list[str]) -> dict[str, str]:
@ -117,13 +124,7 @@ def parse_request_params(lines: list[str]) -> dict[str, str]:
The provided lines are not valid HTTP. The provided lines are not valid HTTP.
""" """
params = dict() params = dict()
for l in lines:
kv = l.strip().split(': ')
if len(kv) != 2 or len(kv[0]) == 0 or len(kv[1]) == 0:
raise ValueError(f"Request line is not a valid key/value pair: {l}")
params[kv[0]] = kv[1]
return params return params

View file

@ -70,8 +70,9 @@ def handle_client(c: socket.socket, addr: tuple[str, int], root:str):
In details, we: In details, we:
* read data from the socket provided, * read data from the socket provided,
* parse this data to build the request and headers, * parse this data to build the request and headers,
* call the handle_request() function, * call the prepare_resource() or prepare_reply() function accordingly,
[* optionally write something in the log,] * send the reply back.
* optionally write something in the log,
* close the connection. * close the connection.
Parameters Parameters
@ -84,21 +85,17 @@ def handle_client(c: socket.socket, addr: tuple[str, int], root:str):
The path to the local directory to serve. The path to the local directory to serve.
""" """
buf = c.recv(_BUF_SIZE)
req = parse_request(buf)
buf = c.recv(_BUF_SIZE)
req = dict()
# Prepare our reply. # Prepare our reply.
if req['head']['verb'] == 'GET': reply, code = prepare_resource(root, req)
reply, code = prepare_resource(root, req)
else:
# Not implemented: we treat only GET calls for now.
reply, code = prepare_reply(b"", "", 501)
# Send the reply back. # Send the reply back.
c.send(reply) c.send(reply)
# Trace the action in the logs. # Optionally trace the action in the logs.
log_reply(addr, req, code)
# Close the connection. # Close the connection.
c.close() c.close()
@ -125,15 +122,8 @@ def prepare_resource(root: str, req: dict):
The status code for the reply. The status code for the reply.
""" """
code = 200 code = 200
content = b"" content = b"Hello World!"
content_type = "" content_type = "text/html"
res_path, res_extension = resolve_location(req['head']['resource'], root)
if res_path == "":
code = 404
else:
content_type = get_http_content_type(res_extension)
content, code = get_resource(res_path)
return prepare_reply(content, content_type, code) return prepare_reply(content, content_type, code)