1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- # -*- 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)
|