forked from adafruit/Adafruit_CircuitPython_HTTPServer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathheaders.py
146 lines (110 loc) · 4.39 KB
/
headers.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# SPDX-FileCopyrightText: Copyright (c) 2022 Michał Pokusa
#
# SPDX-License-Identifier: MIT
"""
`adafruit_httpserver.headers`
====================================================
* Author(s): Michał Pokusa
"""
try:
from typing import Dict, List, Union
except ImportError:
pass
from .interfaces import _IFieldStorage
class Headers(_IFieldStorage):
"""
A dict-like class for storing HTTP headers.
Allows access to headers using **case insensitive** names.
Does **not** implement all dict methods.
Examples::
headers = Headers("Content-Type: text/html\\r\\nContent-Length: 1024\\r\\n")
# or
headers = Headers({"Content-Type": "text/html", "Content-Length": "1024"})
len(headers)
# 2
headers.setdefault("Access-Control-Allow-Origin", "*")
headers["Access-Control-Allow-Origin"]
# '*'
headers["Content-Length"]
# '1024'
headers["content-type"]
# 'text/html'
headers["User-Agent"]
# KeyError: User-Agent
"CONTENT-TYPE" in headers
# True
"""
_storage: Dict[str, List[str]]
def __init__(self, headers: Union[str, Dict[str, str]] = None) -> None:
self._storage = {}
if isinstance(headers, str):
for header_line in headers.strip().splitlines():
name, value = header_line.split(": ", 1)
self.add(name, value)
else:
for key, value in (headers or {}).items():
self.add(key, value)
def add(self, field_name: str, value: str):
"""Adds a header with the given field name and value."""
self._add_field_value(field_name.lower(), value)
def get(self, field_name: str, default: str = None) -> Union[str, None]:
"""Returns the value for the given header name, or default if not found."""
return super().get(field_name.lower(), default)
def get_list(self, field_name: str) -> List[str]:
"""Get the list of values of a field."""
return super().get_list(field_name.lower())
def get_directive(self, name: str, default: str = None) -> Union[str, None]:
"""
Returns the main value (directive) for the given header name, or default if not found.
Example::
headers = Headers({"Content-Type": "text/html; charset=utf-8"})
headers.get_directive("Content-Type")
# 'text/html'
"""
header_value = self.get(name)
if header_value is None:
return default
return header_value.split(";")[0].strip('" ')
def get_parameter(
self, name: str, parameter: str, default: str = None
) -> Union[str, None]:
"""
Returns the value of the given parameter for the given header name, or default if not found.
Example::
headers = Headers({"Content-Type": "text/html; charset=utf-8"})
headers.get_parameter("Content-Type", "charset")
# 'utf-8'
"""
header_value = self.get(name)
if header_value is None:
return default
for header_parameter in header_value.split(";"):
if header_parameter.strip().startswith(parameter):
return header_parameter.strip().split("=")[1].strip('" ')
return default
def set(self, name: str, value: str):
"""Sets the value for the given header name."""
self._storage[name.lower()] = [value]
def setdefault(self, name: str, default: str = None):
"""Sets the value for the given header name if it does not exist."""
return self._storage.setdefault(name.lower(), [default])
def update(self, headers: Dict[str, str]):
"""Updates the headers with the given dict."""
return self._storage.update(
{key.lower(): [value] for key, value in headers.items()}
)
def copy(self):
"""Returns a copy of the headers."""
return Headers(
"\r\n".join(
f"{key}: {value}" for key in self.fields for value in self.get_list(key)
)
)
def __getitem__(self, name: str):
return super().__getitem__(name.lower())
def __setitem__(self, name: str, value: str):
self._storage[name.lower()] = [value]
def __delitem__(self, name: str):
del self._storage[name.lower()]
def __contains__(self, key: str):
return super().__contains__(key.lower())