Edit on GitHub

agent_search_gateway.url_normalization

Stable URL normalization used for state and concurrency keys.

 1"""Stable URL normalization used for state and concurrency keys."""
 2
 3from typing import NewType
 4from urllib.parse import SplitResult, urlsplit, urlunsplit
 5
 6from .errors import ErrorCode, InputFailure
 7
 8NormalizedURL = NewType("NormalizedURL", str)
 9
10
11def _invalid_url() -> InputFailure:
12    return InputFailure(ErrorCode.INVALID_URL, "URL must be a valid HTTP or HTTPS URL")
13
14
15def _lowercase_host(parsed: SplitResult) -> str:
16    netloc = parsed.netloc
17    userinfo, separator, hostport = netloc.rpartition("@")
18    prefix = f"{userinfo}@" if separator else ""
19
20    if hostport.startswith("["):
21        closing = hostport.find("]")
22        if closing < 0:
23            raise _invalid_url()
24        host = hostport[1:closing].lower()
25        return f"{prefix}[{host}]{hostport[closing + 1 :]}"
26
27    host, port_separator, port = hostport.rpartition(":")
28    if port_separator:
29        return f"{prefix}{host.lower()}:{port}"
30    return f"{prefix}{hostport.lower()}"
31
32
33def normalize_url(value: str) -> NormalizedURL:
34    stripped = value.strip()
35    if not stripped:
36        raise _invalid_url()
37
38    try:
39        parsed = urlsplit(stripped)
40        if parsed.scheme not in {"http", "https"} or parsed.hostname is None:
41            raise _invalid_url()
42        _ = parsed.port
43        netloc = _lowercase_host(parsed)
44    except (ValueError, UnicodeError) as exc:
45        raise _invalid_url() from exc
46
47    return NormalizedURL(
48        urlunsplit((parsed.scheme, netloc, parsed.path, parsed.query, parsed.fragment))
49    )
NormalizedURL = NormalizedURL
def normalize_url(value: str) -> NormalizedURL:
34def normalize_url(value: str) -> NormalizedURL:
35    stripped = value.strip()
36    if not stripped:
37        raise _invalid_url()
38
39    try:
40        parsed = urlsplit(stripped)
41        if parsed.scheme not in {"http", "https"} or parsed.hostname is None:
42            raise _invalid_url()
43        _ = parsed.port
44        netloc = _lowercase_host(parsed)
45    except (ValueError, UnicodeError) as exc:
46        raise _invalid_url() from exc
47
48    return NormalizedURL(
49        urlunsplit((parsed.scheme, netloc, parsed.path, parsed.query, parsed.fragment))
50    )