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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

66 statements  

1from __future__ import annotations 

2 

3import typing as t 

4from urllib.parse import quote 

5 

6from .._internal import _plain_int 

7from ..exceptions import SecurityError 

8from ..urls import uri_to_iri 

9 

10 

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

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

13 

14 :param hostname: The name to check. 

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

16 starts with a dot it will match all subdomains. 

17 

18 .. versionadded:: 0.9 

19 """ 

20 if not hostname: 

21 return False 

22 

23 try: 

24 hostname = hostname.partition(":")[0].encode("idna").decode("ascii") 

25 except UnicodeEncodeError: 

26 return False 

27 

28 if isinstance(trusted_list, str): 

29 trusted_list = [trusted_list] 

30 

31 for ref in trusted_list: 

32 if ref.startswith("."): 

33 ref = ref[1:] 

34 suffix_match = True 

35 else: 

36 suffix_match = False 

37 

38 try: 

39 ref = ref.partition(":")[0].encode("idna").decode("ascii") 

40 except UnicodeEncodeError: 

41 return False 

42 

43 if ref == hostname or (suffix_match and hostname.endswith(f".{ref}")): 

44 return True 

45 

46 return False 

47 

48 

49def get_host( 

50 scheme: str, 

51 host_header: str | None, 

52 server: tuple[str, int | None] | None = None, 

53 trusted_hosts: t.Iterable[str] | None = None, 

54) -> str: 

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

56 

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

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

59 different than the standard port for the protocol. 

60 

61 Optionally, verify that the host is trusted using 

62 :func:`host_is_trusted` and raise a 

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

64 

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

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

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

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

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

70 

71 :return: Host, with port if necessary. 

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

73 trusted. 

74 

75 .. versionchanged:: 3.1.3 

76 If ``SERVER_NAME`` is IPv6, it is wrapped in ``[]``. 

77 """ 

78 host = "" 

79 

80 if host_header is not None: 

81 host = host_header 

82 elif server is not None: 

83 host = server[0] 

84 

85 # If SERVER_NAME is IPv6, wrap it in [] to match Host header. 

86 # Check for : because domain or IPv4 can't have that. 

87 if ":" in host and host[0] != "[": 

88 host = f"[{host}]" 

89 

90 if server[1] is not None: 

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

92 

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

94 host = host[:-3] 

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

96 host = host[:-4] 

97 

98 if trusted_hosts is not None: 

99 if not host_is_trusted(host, trusted_hosts): 

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

101 

102 return host 

103 

104 

105def get_current_url( 

106 scheme: str, 

107 host: str, 

108 root_path: str | None = None, 

109 path: str | None = None, 

110 query_string: bytes | None = None, 

111) -> str: 

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

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

114 

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

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

117 

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

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

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

121 is prepended to ``path``. 

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

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

124 """ 

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

126 

127 if root_path is None: 

128 url.append("/") 

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

130 

131 # safe = https://url.spec.whatwg.org/#url-path-segment-string 

132 # as well as percent for things that are already quoted 

133 url.append(quote(root_path.rstrip("/"), safe="!$&'()*+,/:;=@%")) 

134 url.append("/") 

135 

136 if path is None: 

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

138 

139 url.append(quote(path.lstrip("/"), safe="!$&'()*+,/:;=@%")) 

140 

141 if query_string: 

142 url.append("?") 

143 url.append(quote(query_string, safe="!$&'()*+,/:;=?@%")) 

144 

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

146 

147 

148def get_content_length( 

149 http_content_length: str | None = None, 

150 http_transfer_encoding: str | None = None, 

151) -> int | None: 

152 """Return the ``Content-Length`` header value as an int. If the header is not given 

153 or the ``Transfer-Encoding`` header is ``chunked``, ``None`` is returned to indicate 

154 a streaming request. If the value is not an integer, or negative, 0 is returned. 

155 

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

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

158 

159 .. versionadded:: 2.2 

160 """ 

161 if http_transfer_encoding == "chunked" or http_content_length is None: 

162 return None 

163 

164 try: 

165 return max(0, _plain_int(http_content_length)) 

166 except ValueError: 

167 return 0