8
8
"""
9
9
10
10
try :
11
- from typing import Dict , Tuple
11
+ from typing import Dict , List , Union
12
12
except ImportError :
13
13
pass
14
14
15
+ from .interfaces import _IFieldStorage
15
16
16
- class Headers :
17
+
18
+ class Headers (_IFieldStorage ):
17
19
"""
18
20
A dict-like class for storing HTTP headers.
19
21
@@ -23,6 +25,8 @@ class Headers:
23
25
24
26
Examples::
25
27
28
+ headers = Headers("Content-Type: text/html\\ r\\ nContent-Length: 1024\\ r\\ n")
29
+ # or
26
30
headers = Headers({"Content-Type": "text/html", "Content-Length": "1024"})
27
31
28
32
len(headers)
@@ -45,60 +49,101 @@ class Headers:
45
49
# True
46
50
"""
47
51
48
- _storage : Dict [str , Tuple [str , str ]]
52
+ _storage : Dict [str , List [str ]]
53
+
54
+ def __init__ (self , headers : Union [str , Dict [str , str ]] = None ) -> None :
55
+ self ._storage = {}
49
56
50
- def __init__ (self , headers : Dict [str , str ] = None ) -> None :
51
- headers = headers or {}
57
+ if isinstance (headers , str ):
58
+ for header_line in headers .strip ().splitlines ():
59
+ name , value = header_line .split (": " , 1 )
60
+ self .add (name , value )
61
+ else :
62
+ for key , value in (headers or {}).items ():
63
+ self .add (key , value )
52
64
53
- self ._storage = {key .lower (): [key , value ] for key , value in headers .items ()}
65
+ def add (self , field_name : str , value : str ):
66
+ """
67
+ Adds a header with the given field name and value.
68
+ Allows adding multiple headers with the same name.
69
+ """
70
+ self ._add_field_value (field_name .lower (), value )
54
71
55
- def get (self , name : str , default : str = None ):
72
+ def get (self , field_name : str , default : str = None ) -> Union [ str , None ] :
56
73
"""Returns the value for the given header name, or default if not found."""
57
- return self . _storage . get (name .lower (), [ None , default ])[ 1 ]
74
+ return super (). get (field_name .lower (), default )
58
75
59
- def setdefault (self , name : str , default : str = None ):
60
- """Sets the value for the given header name if it does not exist."""
61
- return self ._storage .setdefault (name .lower (), [name , default ])[1 ]
76
+ def get_list (self , field_name : str ) -> List [str ]:
77
+ """Get the list of values of a field."""
78
+ return super ().get_list (field_name .lower ())
79
+
80
+ def get_directive (self , name : str , default : str = None ) -> Union [str , None ]:
81
+ """
82
+ Returns the main value (directive) for the given header name, or default if not found.
83
+
84
+ Example::
85
+
86
+ headers = Headers({"Content-Type": "text/html; charset=utf-8"})
87
+ headers.get_directive("Content-Type")
88
+ # 'text/html'
89
+ """
90
+
91
+ header_value = self .get (name )
92
+ if header_value is None :
93
+ return default
94
+ return header_value .split (";" )[0 ].strip ('" ' )
95
+
96
+ def get_parameter (
97
+ self , name : str , parameter : str , default : str = None
98
+ ) -> Union [str , None ]:
99
+ """
100
+ Returns the value of the given parameter for the given header name, or default if not found.
62
101
63
- def items (self ):
64
- """Returns a list of (name, value) tuples."""
65
- return dict (self ._storage .values ()).items ()
102
+ Example::
66
103
67
- def keys (self ):
68
- """Returns a list of header names."""
69
- return dict (self ._storage .values ()).keys ()
104
+ headers = Headers({"Content-Type": "text/html; charset=utf-8"})
105
+ headers.get_parameter("Content-Type", "charset")
106
+ # 'utf-8'
107
+ """
70
108
71
- def values (self ):
72
- """Returns a list of header values."""
73
- return dict (self ._storage .values ()).values ()
109
+ header_value = self .get (name )
110
+ if header_value is None :
111
+ return default
112
+ for header_parameter in header_value .split (";" ):
113
+ if header_parameter .strip ().startswith (parameter ):
114
+ return header_parameter .strip ().split ("=" )[1 ].strip ('" ' )
115
+ return default
116
+
117
+ def set (self , name : str , value : str ):
118
+ """Sets the value for the given header name."""
119
+ self ._storage [name .lower ()] = [value ]
120
+
121
+ def setdefault (self , name : str , default : str = None ):
122
+ """Sets the value for the given header name if it does not exist."""
123
+ return self ._storage .setdefault (name .lower (), [default ])
74
124
75
125
def update (self , headers : Dict [str , str ]):
76
126
"""Updates the headers with the given dict."""
77
127
return self ._storage .update (
78
- {key .lower (): [key , value ] for key , value in headers .items ()}
128
+ {key .lower (): [value ] for key , value in headers .items ()}
79
129
)
80
130
81
131
def copy (self ):
82
132
"""Returns a copy of the headers."""
83
- return Headers (dict (self ._storage .values ()))
133
+ return Headers (
134
+ "\r \n " .join (
135
+ f"{ key } : { value } " for key in self .fields for value in self .get_list (key )
136
+ )
137
+ )
84
138
85
139
def __getitem__ (self , name : str ):
86
- return self . _storage [ name .lower ()][ 1 ]
140
+ return super (). __getitem__ ( name .lower ())
87
141
88
142
def __setitem__ (self , name : str , value : str ):
89
- self ._storage [name .lower ()] = [name , value ]
143
+ self ._storage [name .lower ()] = [value ]
90
144
91
145
def __delitem__ (self , name : str ):
92
146
del self ._storage [name .lower ()]
93
147
94
- def __iter__ (self ):
95
- return iter (dict (self ._storage .values ()))
96
-
97
- def __len__ (self ):
98
- return len (self ._storage )
99
-
100
148
def __contains__ (self , key : str ):
101
- return key .lower () in self ._storage .keys ()
102
-
103
- def __repr__ (self ):
104
- return f"{ self .__class__ .__name__ } ({ dict (self ._storage .values ())} )"
149
+ return super ().__contains__ (key .lower ())
0 commit comments