7
7
from __future__ import annotations
8
8
9
9
import collections
10
- import re
11
- from string import whitespace
12
10
from typing import TYPE_CHECKING , Any , NamedTuple
13
11
14
12
from hpack .struct import HeaderTuple , NeverIndexedHeaderTuple
20
18
21
19
from hpack .struct import Header , HeaderWeaklyTyped
22
20
23
- UPPER_RE = re .compile (b"[A-Z]" )
24
21
SIGIL = ord (b":" )
25
22
INFORMATIONAL_START = ord (b"1" )
26
23
70
67
_CONNECT_REQUEST_ONLY_HEADERS = frozenset ([b":protocol" ])
71
68
72
69
73
- _WHITESPACE = frozenset (map (ord , whitespace ))
74
-
75
-
76
70
def _secure_headers (headers : Iterable [Header ],
77
71
hdr_validation_flags : HeaderValidationFlags | None ) -> Generator [Header , None , None ]:
78
72
"""
@@ -207,12 +201,6 @@ def validate_headers(headers: Iterable[Header], hdr_validation_flags: HeaderVali
207
201
headers = _reject_empty_header_names (
208
202
headers , hdr_validation_flags ,
209
203
)
210
- headers = _reject_uppercase_header_fields (
211
- headers , hdr_validation_flags ,
212
- )
213
- headers = _reject_surrounding_whitespace (
214
- headers , hdr_validation_flags ,
215
- )
216
204
headers = _reject_te (
217
205
headers , hdr_validation_flags ,
218
206
)
@@ -232,13 +220,16 @@ def _reject_illegal_characters(headers: Iterable[Header],
232
220
hdr_validation_flags : HeaderValidationFlags ) -> Generator [Header , None , None ]:
233
221
"""
234
222
Raises a ProtocolError if any header names or values contain illegal characters.
235
- See RFC 9113, section 8.2.1.
223
+ See <https://www.rfc-editor.org/rfc/rfc9113.html# section- 8.2.1> .
236
224
"""
237
225
for header in headers :
238
226
# > A field name MUST NOT contain characters in the ranges 0x00-0x20, 0x41-0x5a,
239
227
# > or 0x7f-0xff (all ranges inclusive).
240
228
for c in header [0 ]:
241
- if c <= 0x20 or 0x41 <= c <= 0x5a or 0x7f <= c :
229
+ if 0x41 <= c <= 0x5a :
230
+ msg = f"Received uppercase header name { header [0 ]!r} ."
231
+ raise ProtocolError (msg )
232
+ if c <= 0x20 or c >= 0x7f :
242
233
msg = f"Illegal character '{ chr (c )} ' in header name: { header [0 ]!r} "
243
234
raise ProtocolError (msg )
244
235
@@ -249,14 +240,28 @@ def _reject_illegal_characters(headers: Iterable[Header],
249
240
msg = f"Illegal character ':' in header name: { header [0 ]!r} "
250
241
raise ProtocolError (msg )
251
242
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} "
243
+ # For compatibility with RFC 7230 header fields, we need to allow the field
244
+ # value to be an empty string. This is ludicrous, but technically allowed.
245
+ if field_value := header [1 ]:
246
+
247
+ # > A field value MUST NOT contain the zero value (ASCII NUL, 0x00), line feed
248
+ # > (ASCII LF, 0x0a), or carriage return (ASCII CR, 0x0d) at any position.
249
+ for c in field_value :
250
+ if c == 0 or c == 0x0a or c == 0x0d : # noqa: PLR1714
251
+ msg = f"Illegal character '{ chr (c )} ' in header value: { field_value !r} "
252
+ raise ProtocolError (msg )
253
+
254
+ # > A field value MUST NOT start or end with an ASCII whitespace character
255
+ # > (ASCII SP or HTAB, 0x20 or 0x09).
256
+ if (
257
+ field_value [0 ] == 0x20 or
258
+ field_value [0 ] == 0x09 or
259
+ field_value [- 1 ] == 0x20 or
260
+ field_value [- 1 ] == 0x09
261
+ ):
262
+ msg = f"Received header value surrounded by whitespace { field_value !r} "
257
263
raise ProtocolError (msg )
258
264
259
- # Surrounding whitespace is enforced in `_reject_surrounding_whitespace`.
260
265
yield header
261
266
262
267
@@ -275,41 +280,6 @@ def _reject_empty_header_names(headers: Iterable[Header],
275
280
yield header
276
281
277
282
278
- def _reject_uppercase_header_fields (headers : Iterable [Header ],
279
- hdr_validation_flags : HeaderValidationFlags ) -> Generator [Header , None , None ]:
280
- """
281
- Raises a ProtocolError if any uppercase character is found in a header
282
- block.
283
- """
284
- for header in headers :
285
- if UPPER_RE .search (header [0 ]):
286
- msg = f"Received uppercase header name { header [0 ]!r} ."
287
- raise ProtocolError (msg )
288
- yield header
289
-
290
-
291
- def _reject_surrounding_whitespace (headers : Iterable [Header ],
292
- hdr_validation_flags : HeaderValidationFlags ) -> Generator [Header , None , None ]:
293
- """
294
- Raises a ProtocolError if any header name or value is surrounded by
295
- whitespace characters.
296
- """
297
- # For compatibility with RFC 7230 header fields, we need to allow the field
298
- # value to be an empty string. This is ludicrous, but technically allowed.
299
- # The field name may not be empty, though, so we can safely assume that it
300
- # must have at least one character in it and throw exceptions if it
301
- # doesn't.
302
- for header in headers :
303
- if header [0 ][0 ] in _WHITESPACE or header [0 ][- 1 ] in _WHITESPACE :
304
- msg = f"Received header name surrounded by whitespace { header [0 ]!r} "
305
- raise ProtocolError (msg )
306
- if header [1 ] and ((header [1 ][0 ] in _WHITESPACE ) or
307
- (header [1 ][- 1 ] in _WHITESPACE )):
308
- msg = f"Received header value surrounded by whitespace { header [1 ]!r} "
309
- raise ProtocolError (msg )
310
- yield header
311
-
312
-
313
283
def _reject_te (headers : Iterable [Header ], hdr_validation_flags : HeaderValidationFlags ) -> Generator [Header , None , None ]:
314
284
"""
315
285
Raises a ProtocolError if the TE header is present in a header block and
0 commit comments