_abnf.py 1.9 KB

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