blob: 8029943beab4d465a4547e23a19882bade51c604 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
# -*- test-case-name: twisted.web.test.test_abnf -*-
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Tools for pedantically processing the HTTP protocol.
"""
def _istoken(b: bytes) -> bool:
"""
Is the string a token per RFC 9110 section 5.6.2?
"""
for c in b:
if c not in (
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" # ALPHA
b"0123456789" # DIGIT
b"!#$%&'*+-.^_`|~"
):
return False
return b != b""
def _decint(data: bytes) -> int:
"""
Parse a decimal integer of the form C{1*DIGIT}, i.e. consisting only of
decimal digits. The integer may be embedded in whitespace (space and
horizontal tab). This differs from the built-in L{int()} function by
disallowing a leading C{+} character and various forms of whitespace
(note that we sanitize linear whitespace in header values in
L{twisted.web.http_headers.Headers}).
@param data: Value to parse.
@returns: A non-negative integer.
@raises ValueError: When I{value} contains non-decimal characters.
"""
data = data.strip(b" \t")
if not data.isdigit():
raise ValueError(f"Value contains non-decimal digits: {data!r}")
return int(data)
def _ishexdigits(b: bytes) -> bool:
"""
Is the string case-insensitively hexidecimal?
It must be composed of one or more characters in the ranges a-f, A-F
and 0-9.
"""
for c in b:
if c not in b"0123456789abcdefABCDEF":
return False
return b != b""
def _hexint(b: bytes) -> int:
"""
Decode a hexadecimal integer.
Unlike L{int(b, 16)}, this raises L{ValueError} when the integer has
a prefix like C{b'0x'}, C{b'+'}, or C{b'-'}, which is desirable when
parsing network protocols.
"""
if not _ishexdigits(b):
raise ValueError(b)
return int(b, 16)
|