src.myserver.http_request
A package for learning network programming in Python.
This module (file) manages the parsing of HTTP requests.
1###################################################################### 2# Copyright (c) Adrien Luxey-Bitri, Boris Baldassari 3# 4# This program and the accompanying materials are made 5# available under the terms of the Eclipse Public License 2.0 6# which is available at https://www.eclipse.org/legal/epl-2.0/ 7# 8# SPDX-License-Identifier: EPL-2.0 9###################################################################### 10 11""" 12A package for learning network programming in Python. 13 14This module (file) manages the parsing of HTTP requests. 15""" 16 17# TODO: Gestion de la casse des paramètres ? 18 19def parse_request(buf: bytes) -> dict[str, dict]: 20 """Parses a full HTTP request bytes buffer into a dict. 21 22 The parsed request dict contains two keys: 23 - head: dict[str, str] 24 Information on the HTTP request header (i.e. the first request line); 25 output of `parse_request_head`. 26 - params: dict[str, str] 27 List of the HTTP parameters (i.e. the following lines); 28 output of `parse_request_params`. 29 30 Parameters 31 ---------- 32 - buf: bytes 33 The HTTP request buffer. 34 35 Returns 36 ------- 37 dict[str, dict] 38 The parsed content of the HTTP request. 39 40 Raises 41 ------ 42 ValueError 43 The request is not valid HTTP. 44 """ 45 if buf == b'': 46 raise ValueError("Received empty request") 47 lines = buf.decode('utf-8').strip().splitlines() 48 49 req_head = parse_request_head(lines[0]) 50 req_params = dict() 51 if len(lines) > 1: 52 req_params = parse_request_params(lines[1:]) 53 54 return dict( 55 head=req_head, 56 params=req_params 57 ) 58 59def parse_request_head(line: str) -> dict[str, str]: 60 """Parses a HTTP request header string (its first line) into a dict. 61 62 The parsed request dict contains two keys: 63 - verb: str 64 The _uppercase_ verb of the request, i.e. the first word of the line; 65 for example: "GET". 66 - resource: str 67 The requested resource, i.e. the second "word" of the line; 68 for example: "/index.html". 69 70 Parameters 71 ---------- 72 - line: str 73 The HTTP request header (the first line of a full HTTP request). 74 75 Returns 76 ------- 77 dict[str, str] 78 The parsed content of the HTTP request header. 79 80 Raises 81 ------ 82 ValueError 83 The request header is not valid HTTP. 84 """ 85 fields = line.split(' ') 86 if len(fields) != 3: 87 raise ValueError(f"Request header is invalid: {line}") 88 89 return dict( 90 verb=fields[0].upper(), 91 resource=fields[1] 92 ) 93 94def parse_request_params(lines: list[str]) -> dict[str, str]: 95 """Parses HTTP request parameters (a list of lines) into a dict. 96 97 The parsed request dict contains one key/value pair per line, with the 98 dict key being the left part of the line (the parameter key), and the 99 dict value being the right part of the line (the parameter value). 100 101 The function strips leading and trailing spaces: " Host: a.org " becomes 102 `{"Host": "a.org"}`. 103 104 Parameters 105 ---------- 106 - lines: list[str] 107 HTTP parameters (one list item per line) 108 109 Returns 110 ------- 111 dict[str, str] 112 Dictionary of the parameters 113 114 Raises 115 ------ 116 ValueError 117 The provided lines are not valid HTTP. 118 """ 119 params = dict() 120 for l in lines: 121 kv = l.strip().split(': ') 122 123 if len(kv) != 2 or len(kv[0]) == 0 or len(kv[1]) == 0: 124 raise ValueError(f"Request line is not a valid key/value pair: {l}") 125 126 params[kv[0]] = kv[1] 127 return params
20def parse_request(buf: bytes) -> dict[str, dict]: 21 """Parses a full HTTP request bytes buffer into a dict. 22 23 The parsed request dict contains two keys: 24 - head: dict[str, str] 25 Information on the HTTP request header (i.e. the first request line); 26 output of `parse_request_head`. 27 - params: dict[str, str] 28 List of the HTTP parameters (i.e. the following lines); 29 output of `parse_request_params`. 30 31 Parameters 32 ---------- 33 - buf: bytes 34 The HTTP request buffer. 35 36 Returns 37 ------- 38 dict[str, dict] 39 The parsed content of the HTTP request. 40 41 Raises 42 ------ 43 ValueError 44 The request is not valid HTTP. 45 """ 46 if buf == b'': 47 raise ValueError("Received empty request") 48 lines = buf.decode('utf-8').strip().splitlines() 49 50 req_head = parse_request_head(lines[0]) 51 req_params = dict() 52 if len(lines) > 1: 53 req_params = parse_request_params(lines[1:]) 54 55 return dict( 56 head=req_head, 57 params=req_params 58 )
Parses a full HTTP request bytes buffer into a dict.
The parsed request dict contains two keys:
- head: dict[str, str]
Information on the HTTP request header (i.e. the first request line);
output of
parse_request_head
. - params: dict[str, str]
List of the HTTP parameters (i.e. the following lines);
output of
parse_request_params
.
Parameters
- buf: bytes The HTTP request buffer.
Returns
dict[str, dict] The parsed content of the HTTP request.
Raises
ValueError The request is not valid HTTP.
60def parse_request_head(line: str) -> dict[str, str]: 61 """Parses a HTTP request header string (its first line) into a dict. 62 63 The parsed request dict contains two keys: 64 - verb: str 65 The _uppercase_ verb of the request, i.e. the first word of the line; 66 for example: "GET". 67 - resource: str 68 The requested resource, i.e. the second "word" of the line; 69 for example: "/index.html". 70 71 Parameters 72 ---------- 73 - line: str 74 The HTTP request header (the first line of a full HTTP request). 75 76 Returns 77 ------- 78 dict[str, str] 79 The parsed content of the HTTP request header. 80 81 Raises 82 ------ 83 ValueError 84 The request header is not valid HTTP. 85 """ 86 fields = line.split(' ') 87 if len(fields) != 3: 88 raise ValueError(f"Request header is invalid: {line}") 89 90 return dict( 91 verb=fields[0].upper(), 92 resource=fields[1] 93 )
Parses a HTTP request header string (its first line) into a dict.
The parsed request dict contains two keys:
- verb: str The _uppercase_ verb of the request, i.e. the first word of the line; for example: "GET".
- resource: str The requested resource, i.e. the second "word" of the line; for example: "/index.html".
Parameters
- line: str The HTTP request header (the first line of a full HTTP request).
Returns
dict[str, str] The parsed content of the HTTP request header.
Raises
ValueError The request header is not valid HTTP.
95def parse_request_params(lines: list[str]) -> dict[str, str]: 96 """Parses HTTP request parameters (a list of lines) into a dict. 97 98 The parsed request dict contains one key/value pair per line, with the 99 dict key being the left part of the line (the parameter key), and the 100 dict value being the right part of the line (the parameter value). 101 102 The function strips leading and trailing spaces: " Host: a.org " becomes 103 `{"Host": "a.org"}`. 104 105 Parameters 106 ---------- 107 - lines: list[str] 108 HTTP parameters (one list item per line) 109 110 Returns 111 ------- 112 dict[str, str] 113 Dictionary of the parameters 114 115 Raises 116 ------ 117 ValueError 118 The provided lines are not valid HTTP. 119 """ 120 params = dict() 121 for l in lines: 122 kv = l.strip().split(': ') 123 124 if len(kv) != 2 or len(kv[0]) == 0 or len(kv[1]) == 0: 125 raise ValueError(f"Request line is not a valid key/value pair: {l}") 126 127 params[kv[0]] = kv[1] 128 return params
Parses HTTP request parameters (a list of lines) into a dict.
The parsed request dict contains one key/value pair per line, with the dict key being the left part of the line (the parameter key), and the dict value being the right part of the line (the parameter value).
The function strips leading and trailing spaces: " Host: a.org " becomes
{"Host": "a.org"}
.
Parameters
- lines: list[str] HTTP parameters (one list item per line)
Returns
dict[str, str] Dictionary of the parameters
Raises
ValueError The provided lines are not valid HTTP.