Add intermediate step student_1 after exo 3.2.
This commit is contained in:
parent
687f83ff8d
commit
7700413031
|
@ -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
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue