88"""
99
1010try :
11- from typing import Dict , Tuple
11+ from typing import Dict , List , Union
1212except ImportError :
1313 pass
1414
15+ from .interfaces import _IFieldStorage
1516
16- class Headers :
17+
18+ class Headers (_IFieldStorage ):
1719 """
1820 A dict-like class for storing HTTP headers.
1921
@@ -23,6 +25,8 @@ class Headers:
2325
2426 Examples::
2527
28+ headers = Headers("Content-Type: text/html\\ r\\ nContent-Length: 1024\\ r\\ n")
29+ # or
2630 headers = Headers({"Content-Type": "text/html", "Content-Length": "1024"})
2731
2832 len(headers)
@@ -45,60 +49,101 @@ class Headers:
4549 # True
4650 """
4751
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 = {}
4956
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 )
5264
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 )
5471
55- def get (self , name : str , default : str = None ):
72+ def get (self , field_name : str , default : str = None ) -> Union [ str , None ] :
5673 """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 )
5875
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.
62101
63- def items (self ):
64- """Returns a list of (name, value) tuples."""
65- return dict (self ._storage .values ()).items ()
102+ Example::
66103
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+ """
70108
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 ])
74124
75125 def update (self , headers : Dict [str , str ]):
76126 """Updates the headers with the given dict."""
77127 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 ()}
79129 )
80130
81131 def copy (self ):
82132 """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+ )
84138
85139 def __getitem__ (self , name : str ):
86- return self . _storage [ name .lower ()][ 1 ]
140+ return super (). __getitem__ ( name .lower ())
87141
88142 def __setitem__ (self , name : str , value : str ):
89- self ._storage [name .lower ()] = [name , value ]
143+ self ._storage [name .lower ()] = [value ]
90144
91145 def __delitem__ (self , name : str ):
92146 del self ._storage [name .lower ()]
93147
94- def __iter__ (self ):
95- return iter (dict (self ._storage .values ()))
96-
97- def __len__ (self ):
98- return len (self ._storage )
99-
100148 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