Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/werkzeug/sansio/utils.py: 13%

71 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1import typing as t 

2 

3from .._internal import _encode_idna 

4from ..exceptions import SecurityError 

5from ..urls import uri_to_iri 

6from ..urls import url_quote 

7 

8 

9def host_is_trusted(hostname: str, trusted_list: t.Iterable[str]) -> bool: 

10 """Check if a host matches a list of trusted names. 

11 

12 :param hostname: The name to check. 

13 :param trusted_list: A list of valid names to match. If a name 

14 starts with a dot it will match all subdomains. 

15 

16 .. versionadded:: 0.9 

17 """ 

18 if not hostname: 

19 return False 

20 

21 if isinstance(trusted_list, str): 

22 trusted_list = [trusted_list] 

23 

24 def _normalize(hostname: str) -> bytes: 

25 if ":" in hostname: 

26 hostname = hostname.rsplit(":", 1)[0] 

27 

28 return _encode_idna(hostname) 

29 

30 try: 

31 hostname_bytes = _normalize(hostname) 

32 except UnicodeError: 

33 return False 

34 

35 for ref in trusted_list: 

36 if ref.startswith("."): 

37 ref = ref[1:] 

38 suffix_match = True 

39 else: 

40 suffix_match = False 

41 

42 try: 

43 ref_bytes = _normalize(ref) 

44 except UnicodeError: 

45 return False 

46 

47 if ref_bytes == hostname_bytes: 

48 return True 

49 

50 if suffix_match and hostname_bytes.endswith(b"." + ref_bytes): 

51 return True 

52 

53 return False 

54 

55 

56def get_host( 

57 scheme: str, 

58 host_header: t.Optional[str], 

59 server: t.Optional[t.Tuple[str, t.Optional[int]]] = None, 

60 trusted_hosts: t.Optional[t.Iterable[str]] = None, 

61) -> str: 

62 """Return the host for the given parameters. 

63 

64 This first checks the ``host_header``. If it's not present, then 

65 ``server`` is used. The host will only contain the port if it is 

66 different than the standard port for the protocol. 

67 

68 Optionally, verify that the host is trusted using 

69 :func:`host_is_trusted` and raise a 

70 :exc:`~werkzeug.exceptions.SecurityError` if it is not. 

71 

72 :param scheme: The protocol the request used, like ``"https"``. 

73 :param host_header: The ``Host`` header value. 

74 :param server: Address of the server. ``(host, port)``, or 

75 ``(path, None)`` for unix sockets. 

76 :param trusted_hosts: A list of trusted host names. 

77 

78 :return: Host, with port if necessary. 

79 :raise ~werkzeug.exceptions.SecurityError: If the host is not 

80 trusted. 

81 """ 

82 host = "" 

83 

84 if host_header is not None: 

85 host = host_header 

86 elif server is not None: 

87 host = server[0] 

88 

89 if server[1] is not None: 

90 host = f"{host}:{server[1]}" 

91 

92 if scheme in {"http", "ws"} and host.endswith(":80"): 

93 host = host[:-3] 

94 elif scheme in {"https", "wss"} and host.endswith(":443"): 

95 host = host[:-4] 

96 

97 if trusted_hosts is not None: 

98 if not host_is_trusted(host, trusted_hosts): 

99 raise SecurityError(f"Host {host!r} is not trusted.") 

100 

101 return host 

102 

103 

104def get_current_url( 

105 scheme: str, 

106 host: str, 

107 root_path: t.Optional[str] = None, 

108 path: t.Optional[str] = None, 

109 query_string: t.Optional[bytes] = None, 

110) -> str: 

111 """Recreate the URL for a request. If an optional part isn't 

112 provided, it and subsequent parts are not included in the URL. 

113 

114 The URL is an IRI, not a URI, so it may contain Unicode characters. 

115 Use :func:`~werkzeug.urls.iri_to_uri` to convert it to ASCII. 

116 

117 :param scheme: The protocol the request used, like ``"https"``. 

118 :param host: The host the request was made to. See :func:`get_host`. 

119 :param root_path: Prefix that the application is mounted under. This 

120 is prepended to ``path``. 

121 :param path: The path part of the URL after ``root_path``. 

122 :param query_string: The portion of the URL after the "?". 

123 """ 

124 url = [scheme, "://", host] 

125 

126 if root_path is None: 

127 url.append("/") 

128 return uri_to_iri("".join(url)) 

129 

130 url.append(url_quote(root_path.rstrip("/"))) 

131 url.append("/") 

132 

133 if path is None: 

134 return uri_to_iri("".join(url)) 

135 

136 url.append(url_quote(path.lstrip("/"))) 

137 

138 if query_string: 

139 url.append("?") 

140 url.append(url_quote(query_string, safe=":&%=+$!*'(),")) 

141 

142 return uri_to_iri("".join(url)) 

143 

144 

145def get_content_length( 

146 http_content_length: t.Union[str, None] = None, 

147 http_transfer_encoding: t.Union[str, None] = "", 

148) -> t.Optional[int]: 

149 """Returns the content length as an integer or ``None`` if 

150 unavailable or chunked transfer encoding is used. 

151 

152 :param http_content_length: The Content-Length HTTP header. 

153 :param http_transfer_encoding: The Transfer-Encoding HTTP header. 

154 

155 .. versionadded:: 2.2 

156 """ 

157 if http_transfer_encoding == "chunked": 

158 return None 

159 

160 if http_content_length is not None: 

161 try: 

162 return max(0, int(http_content_length)) 

163 except (ValueError, TypeError): 

164 pass 

165 return None