24
24
SIGIL = ord (b":" )
25
25
INFORMATIONAL_START = ord (b"1" )
26
26
27
- HEADER_UNPERMITTED_CHARACTERS = frozenset ([
28
- b"\r " ,
29
- b"\n " ,
30
- b"\x00 " ,
31
- ])
32
-
33
27
34
28
# A set of headers that are hop-by-hop or connection-specific and thus
35
29
# forbidden in HTTP/2. This list comes from RFC 7540 § 8.1.2.2.
@@ -207,7 +201,7 @@ def validate_headers(headers: Iterable[Header], hdr_validation_flags: HeaderVali
207
201
# For example, we avoid tuple unpacking in loops because it represents a
208
202
# fixed cost that we don't want to spend, instead indexing into the header
209
203
# tuples.
210
- headers = _reject_unpermitted_characters (
204
+ headers = _reject_illegal_characters (
211
205
headers , hdr_validation_flags ,
212
206
)
213
207
headers = _reject_empty_header_names (
@@ -234,20 +228,35 @@ def validate_headers(headers: Iterable[Header], hdr_validation_flags: HeaderVali
234
228
return _check_path_header (headers , hdr_validation_flags )
235
229
236
230
237
- def _reject_unpermitted_characters (headers : Iterable [Header ],
238
- hdr_validation_flags : HeaderValidationFlags ) -> Generator [Header , None , None ]:
231
+ def _reject_illegal_characters (headers : Iterable [Header ],
232
+ hdr_validation_flags : HeaderValidationFlags ) -> Generator [Header , None , None ]:
239
233
"""
240
- Raises a ProtocolError if any header names or values contain unpermitted characters.
241
- See RFC 7540 , section 10.3 and 8.1.2.6 .
234
+ Raises a ProtocolError if any header names or values contain illegal characters.
235
+ See RFC 9113 , section 8.2.1 .
242
236
"""
243
237
for header in headers :
244
- for c in HEADER_UNPERMITTED_CHARACTERS :
245
- if c in header [0 ]:
246
- msg = f"Unpermitted character '{ c } ' in header name: { header [0 ]!r} "
238
+ # > A field name MUST NOT contain characters in the ranges 0x00-0x20, 0x41-0x5a,
239
+ # > or 0x7f-0xff (all ranges inclusive).
240
+ for c in header [0 ]:
241
+ if c <= 0x20 or 0x41 <= c <= 0x5a or 0x7f <= c :
242
+ msg = f"Illegal character '{ chr (c )} ' in header name: { header [0 ]!r} "
247
243
raise ProtocolError (msg )
248
- if c in header [1 ]:
249
- msg = f"Unpermitted character '{ c } ' in header value: { header [1 ]!r} "
244
+
245
+ # > With the exception of pseudo-header fields (Section 8.3), which have a name
246
+ # > that starts with a single colon, field names MUST NOT include a colon (ASCII
247
+ # > COLON, 0x3a).
248
+ if header [0 ].find (b":" , 1 ) != - 1 :
249
+ msg = f"Illegal character ':' in header name: { header [0 ]!r} "
250
+ raise ProtocolError (msg )
251
+
252
+ # > A field value MUST NOT contain the zero value (ASCII NUL, 0x00), line feed
253
+ # > (ASCII LF, 0x0a), or carriage return (ASCII CR, 0x0d) at any position.
254
+ for c in header [1 ]:
255
+ if c == 0 or c == 0x0a or c == 0x0d :
256
+ msg = f"Illegal character '{ chr (c )} ' in header value: { header [1 ]!r} "
250
257
raise ProtocolError (msg )
258
+
259
+ # Surrounding whitespace is enforced in `_reject_surrounding_whitespace`.
251
260
yield header
252
261
253
262
0 commit comments