Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/w3lib/http.py: 24%

34 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-07 06:38 +0000

1from base64 import b64encode 

2from typing import Any, List, MutableMapping, Optional, AnyStr, Sequence, Union, Mapping 

3from w3lib.util import to_bytes, to_unicode 

4 

5HeadersDictInput = Mapping[bytes, Union[Any, Sequence[bytes]]] 

6HeadersDictOutput = MutableMapping[bytes, List[bytes]] 

7 

8 

9def headers_raw_to_dict(headers_raw: Optional[bytes]) -> Optional[HeadersDictOutput]: 

10 r""" 

11 Convert raw headers (single multi-line bytestring) 

12 to a dictionary. 

13 

14 For example: 

15 

16 >>> import w3lib.http 

17 >>> w3lib.http.headers_raw_to_dict(b"Content-type: text/html\n\rAccept: gzip\n\n") # doctest: +SKIP 

18 {'Content-type': ['text/html'], 'Accept': ['gzip']} 

19 

20 Incorrect input: 

21 

22 >>> w3lib.http.headers_raw_to_dict(b"Content-typt gzip\n\n") 

23 {} 

24 >>> 

25 

26 Argument is ``None`` (return ``None``): 

27 

28 >>> w3lib.http.headers_raw_to_dict(None) 

29 >>> 

30 

31 """ 

32 

33 if headers_raw is None: 

34 return None 

35 headers = headers_raw.splitlines() 

36 headers_tuples = [header.split(b":", 1) for header in headers] 

37 

38 result_dict: HeadersDictOutput = {} 

39 for header_item in headers_tuples: 

40 if not len(header_item) == 2: 

41 continue 

42 

43 item_key = header_item[0].strip() 

44 item_value = header_item[1].strip() 

45 

46 if item_key in result_dict: 

47 result_dict[item_key].append(item_value) 

48 else: 

49 result_dict[item_key] = [item_value] 

50 

51 return result_dict 

52 

53 

54def headers_dict_to_raw(headers_dict: Optional[HeadersDictInput]) -> Optional[bytes]: 

55 r""" 

56 Returns a raw HTTP headers representation of headers 

57 

58 For example: 

59 

60 >>> import w3lib.http 

61 >>> w3lib.http.headers_dict_to_raw({b'Content-type': b'text/html', b'Accept': b'gzip'}) # doctest: +SKIP 

62 'Content-type: text/html\\r\\nAccept: gzip' 

63 >>> 

64 

65 Note that keys and values must be bytes. 

66 

67 Argument is ``None`` (returns ``None``): 

68 

69 >>> w3lib.http.headers_dict_to_raw(None) 

70 >>> 

71 

72 """ 

73 

74 if headers_dict is None: 

75 return None 

76 raw_lines = [] 

77 for key, value in headers_dict.items(): 

78 if isinstance(value, bytes): 

79 raw_lines.append(b": ".join([key, value])) 

80 elif isinstance(value, (list, tuple)): 

81 for v in value: 

82 raw_lines.append(b": ".join([key, v])) 

83 return b"\r\n".join(raw_lines) 

84 

85 

86def basic_auth_header( 

87 username: AnyStr, password: AnyStr, encoding: str = "ISO-8859-1" 

88) -> bytes: 

89 """ 

90 Return an `Authorization` header field value for `HTTP Basic Access Authentication (RFC 2617)`_ 

91 

92 >>> import w3lib.http 

93 >>> w3lib.http.basic_auth_header('someuser', 'somepass') 

94 'Basic c29tZXVzZXI6c29tZXBhc3M=' 

95 

96 .. _HTTP Basic Access Authentication (RFC 2617): http://www.ietf.org/rfc/rfc2617.txt 

97 

98 """ 

99 

100 auth = f"{to_unicode(username)}:{to_unicode(password)}" 

101 # XXX: RFC 2617 doesn't define encoding, but ISO-8859-1 

102 # seems to be the most widely used encoding here. See also: 

103 # http://greenbytes.de/tech/webdav/draft-ietf-httpauth-basicauth-enc-latest.html 

104 return b"Basic " + b64encode(to_bytes(auth, encoding=encoding))