You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.7 KiB

4 years ago
  1. from base64 import urlsafe_b64encode
  2. def headers_raw_to_dict(headers_raw):
  3. r"""
  4. Convert raw headers (single multi-line bytestring)
  5. to a dictionary.
  6. For example:
  7. >>> import w3lib.http
  8. >>> w3lib.http.headers_raw_to_dict(b"Content-type: text/html\n\rAccept: gzip\n\n") # doctest: +SKIP
  9. {'Content-type': ['text/html'], 'Accept': ['gzip']}
  10. Incorrect input:
  11. >>> w3lib.http.headers_raw_to_dict(b"Content-typt gzip\n\n")
  12. {}
  13. >>>
  14. Argument is ``None`` (return ``None``):
  15. >>> w3lib.http.headers_raw_to_dict(None)
  16. >>>
  17. """
  18. if headers_raw is None:
  19. return None
  20. headers = headers_raw.splitlines()
  21. headers_tuples = [header.split(b':', 1) for header in headers]
  22. result_dict = {}
  23. for header_item in headers_tuples:
  24. if not len(header_item) == 2:
  25. continue
  26. item_key = header_item[0].strip()
  27. item_value = header_item[1].strip()
  28. if item_key in result_dict:
  29. result_dict[item_key].append(item_value)
  30. else:
  31. result_dict[item_key] = [item_value]
  32. return result_dict
  33. def headers_dict_to_raw(headers_dict):
  34. r"""
  35. Returns a raw HTTP headers representation of headers
  36. For example:
  37. >>> import w3lib.http
  38. >>> w3lib.http.headers_dict_to_raw({b'Content-type': b'text/html', b'Accept': b'gzip'}) # doctest: +SKIP
  39. 'Content-type: text/html\\r\\nAccept: gzip'
  40. >>>
  41. Note that keys and values must be bytes.
  42. Argument is ``None`` (returns ``None``):
  43. >>> w3lib.http.headers_dict_to_raw(None)
  44. >>>
  45. """
  46. if headers_dict is None:
  47. return None
  48. raw_lines = []
  49. for key, value in headers_dict.items():
  50. if isinstance(value, bytes):
  51. raw_lines.append(b": ".join([key, value]))
  52. elif isinstance(value, (list, tuple)):
  53. for v in value:
  54. raw_lines.append(b": ".join([key, v]))
  55. return b'\r\n'.join(raw_lines)
  56. def basic_auth_header(username, password, encoding='ISO-8859-1'):
  57. """
  58. Return an `Authorization` header field value for `HTTP Basic Access Authentication (RFC 2617)`_
  59. >>> import w3lib.http
  60. >>> w3lib.http.basic_auth_header('someuser', 'somepass')
  61. 'Basic c29tZXVzZXI6c29tZXBhc3M='
  62. .. _HTTP Basic Access Authentication (RFC 2617): http://www.ietf.org/rfc/rfc2617.txt
  63. """
  64. auth = "%s:%s" % (username, password)
  65. if not isinstance(auth, bytes):
  66. # XXX: RFC 2617 doesn't define encoding, but ISO-8859-1
  67. # seems to be the most widely used encoding here. See also:
  68. # http://greenbytes.de/tech/webdav/draft-ietf-httpauth-basicauth-enc-latest.html
  69. auth = auth.encode(encoding)
  70. return b'Basic ' + urlsafe_b64encode(auth)