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

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

64 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 host = "" 

76 

77 if host_header is not None: 

78 host = host_header 

79 elif server is not None: 

80 host = server[0] 

81 

82 if server[1] is not None: 

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

84 

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

86 host = host[:-3] 

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

88 host = host[:-4] 

89 

90 if trusted_hosts is not None: 

91 if not host_is_trusted(host, trusted_hosts): 

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

93 

94 return host 

95 

96 

97def get_current_url( 

98 scheme: str, 

99 host: str, 

100 root_path: str | None = None, 

101 path: str | None = None, 

102 query_string: bytes | None = None, 

103) -> str: 

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

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

106 

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

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

109 

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

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

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

113 is prepended to ``path``. 

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

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

116 """ 

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

118 

119 if root_path is None: 

120 url.append("/") 

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

122 

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

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

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

126 url.append("/") 

127 

128 if path is None: 

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

130 

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

132 

133 if query_string: 

134 url.append("?") 

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

136 

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

138 

139 

140def get_content_length( 

141 http_content_length: str | None = None, 

142 http_transfer_encoding: str | None = None, 

143) -> int | None: 

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

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

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

147 

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

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

150 

151 .. versionadded:: 2.2 

152 """ 

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

154 return None 

155 

156 try: 

157 return max(0, _plain_int(http_content_length)) 

158 except ValueError: 

159 return 0