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
def parse_request(buf: bytes) -> dict[str, dict]:
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.

def parse_request_head(line: str) -> dict[str, str]:
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.

def parse_request_params(lines: list[str]) -> dict[str, str]:
 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.