From 644f8b7c080dd75709e254a815b1b151109d576b Mon Sep 17 00:00:00 2001 From: ChengFa <166748424+indexGin@users.noreply.github.com> Date: Tue, 10 Nov 2026 05:17:01 +0000 Subject: [PATCH] fix(url): normalize base url path without corrupting query and fragment (#45647) --- api/libs/url_utils.py | 5 ++++- api/tests/unit_tests/libs/test_url_utils.py | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 api/tests/unit_tests/libs/test_url_utils.py diff --git a/api/libs/url_utils.py b/api/libs/url_utils.py index 59a9f8fbce2..9f4df1f007e 100644 --- a/api/libs/url_utils.py +++ b/api/libs/url_utils.py @@ -3,7 +3,10 @@ from urllib.parse import urlsplit, urlunsplit def normalize_api_base_url(base_url: str) -> str: """Normalize a base URL to always end with /v1, avoiding double /v1 suffixes.""" - return base_url.rstrip("/").removesuffix("/v1").rstrip("/") + "/v1" + base_url = base_url.strip() + parsed = urlsplit(base_url) + path = parsed.path.rstrip("/").removesuffix("/v1").rstrip("/") + "/v1" + return urlunsplit(parsed._replace(path=path)) def github_blob_to_raw_url(url: str) -> str: diff --git a/api/tests/unit_tests/libs/test_url_utils.py b/api/tests/unit_tests/libs/test_url_utils.py new file mode 100644 index 00000000000..6ee2d67f6c6 --- /dev/null +++ b/api/tests/unit_tests/libs/test_url_utils.py @@ -0,0 +1,18 @@ +from libs.url_utils import normalize_api_base_url + + +def test_normalize_api_base_url_appends_v1() -> None: + assert normalize_api_base_url("https://api.example.com") == "https://api.example.com/v1" + assert normalize_api_base_url("https://api.example.com/") == "https://api.example.com/v1" + assert normalize_api_base_url("https://api.example.com/v1") == "https://api.example.com/v1" + assert normalize_api_base_url("https://api.example.com/v1/") == "https://api.example.com/v1" + + +def test_normalize_api_base_url_preserves_query_and_fragment() -> None: + assert normalize_api_base_url("https://api.example.com/v1?timeout=30") == "https://api.example.com/v1?timeout=30" + assert normalize_api_base_url("https://api.example.com?timeout=30") == "https://api.example.com/v1?timeout=30" + assert normalize_api_base_url("https://api.example.com/v1#section") == "https://api.example.com/v1#section" + + +def test_normalize_api_base_url_strips_surrounding_whitespace() -> None: + assert normalize_api_base_url(" https://api.example.com/v1 ") == "https://api.example.com/v1"