99# existence of which force quoting of the parameter value.
1010import re
1111tspecials = re .compile (r'[ \(\)<>@,;:\\"/\[\]\?=]' )
12- _control_chars_re = re .compile (r'[\x00-\x1F\x7F]' )
12+ # Disallowed characters for headers and values.
13+ # HTAB (\x09) is allowed in header values, but
14+ # not in header names. (RFC 9110 Section 5.5)
15+ _name_disallowed_re = re .compile (r'[\x00-\x1F\x7F]' )
16+ _value_disallowed_re = re .compile (r'[\x00-\x08\x0A-\x1F\x7F]' )
1317
1418def _formatparam (param , value = None , quote = 1 ):
1519 """Convenience function to format and return a key=value pair.
@@ -36,13 +40,13 @@ def __init__(self, headers=None):
3640 self ._headers = headers
3741 if __debug__ :
3842 for k , v in headers :
39- self ._convert_string_type (k )
43+ self ._convert_string_type (k , name = True )
4044 self ._convert_string_type (v )
4145
42- def _convert_string_type (self , value ):
46+ def _convert_string_type (self , value , * , name = False ):
4347 """Convert/check value type."""
4448 if type (value ) is str :
45- if _control_chars_re .search (value ):
49+ if ( _name_disallowed_re if name else _value_disallowed_re ) .search (value ):
4650 raise ValueError ("Control characters not allowed in headers" )
4751 return value
4852 raise AssertionError ("Header names/values must be"
@@ -56,14 +60,14 @@ def __setitem__(self, name, val):
5660 """Set the value of a header."""
5761 del self [name ]
5862 self ._headers .append (
59- (self ._convert_string_type (name ), self ._convert_string_type (val )))
63+ (self ._convert_string_type (name , name = True ), self ._convert_string_type (val )))
6064
6165 def __delitem__ (self ,name ):
6266 """Delete all occurrences of a header, if present.
6367
6468 Does *not* raise an exception if the header is missing.
6569 """
66- name = self ._convert_string_type (name .lower ())
70+ name = self ._convert_string_type (name .lower (), name = True )
6771 self ._headers [:] = [kv for kv in self ._headers if kv [0 ].lower () != name ]
6872
6973 def __getitem__ (self ,name ):
@@ -90,13 +94,13 @@ def get_all(self, name):
9094 fields deleted and re-inserted are always appended to the header list.
9195 If no fields exist with the given name, returns an empty list.
9296 """
93- name = self ._convert_string_type (name .lower ())
97+ name = self ._convert_string_type (name .lower (), name = True )
9498 return [kv [1 ] for kv in self ._headers if kv [0 ].lower ()== name ]
9599
96100
97101 def get (self ,name ,default = None ):
98102 """Get the first header value for 'name', or return 'default'"""
99- name = self ._convert_string_type (name .lower ())
103+ name = self ._convert_string_type (name .lower (), name = True )
100104 for k ,v in self ._headers :
101105 if k .lower ()== name :
102106 return v
@@ -151,7 +155,7 @@ def setdefault(self,name,value):
151155 and value 'value'."""
152156 result = self .get (name )
153157 if result is None :
154- self ._headers .append ((self ._convert_string_type (name ),
158+ self ._headers .append ((self ._convert_string_type (name , name = True ),
155159 self ._convert_string_type (value )))
156160 return value
157161 else :
@@ -178,10 +182,10 @@ def add_header(self, _name, _value, **_params):
178182 _value = self ._convert_string_type (_value )
179183 parts .append (_value )
180184 for k , v in _params .items ():
181- k = self ._convert_string_type (k )
185+ k = self ._convert_string_type (k , name = True )
182186 if v is None :
183187 parts .append (k .replace ('_' , '-' ))
184188 else :
185189 v = self ._convert_string_type (v )
186190 parts .append (_formatparam (k .replace ('_' , '-' ), v ))
187- self ._headers .append ((self ._convert_string_type (_name ), "; " .join (parts )))
191+ self ._headers .append ((self ._convert_string_type (_name , name = True ), "; " .join (parts )))
0 commit comments