A base_url that contains a query string is not rejected, but every relative request built from it has a broken URL. Reproduced on httpx2 2.13.1:
import httpx2
client = httpx2.Client(base_url="https://example.com/api?key=k")
print(repr(client.base_url))
# URL('https://example.com/api?key=k/')
print(client.build_request("GET", "items").url)
# https://example.com/api?key=k/items
print(client.build_request("GET", "items", params={"b": "2"}).url)
# https://example.com/api?b=2
In the first request the path ends up inside the query (key becomes k/items). In the second the path items is lost entirely. No error is raised in either case, so the request silently goes to the wrong URL.
Cause
Both steps operate on raw_path, which includes the query:
_enforce_trailing_slash (_client.py) appends / to url.raw_path, so the slash lands after the query: /api?key=k/.
_merge_url builds self.base_url.raw_path + merge_url.raw_path.lstrip(b"/"), so the request path is appended after the query too.
The second case then loses the path because params= replaces the whole query (#905), and the query now holds the path.
Possible fixes
- Reject a
base_url with a query string in the base_url setter, with a message pointing to params=.
- Support it: operate on
path rather than raw_path in both places and merge the base query into the request's params.
A
base_urlthat contains a query string is not rejected, but every relative request built from it has a broken URL. Reproduced on httpx2 2.13.1:In the first request the path ends up inside the query (
keybecomesk/items). In the second the pathitemsis lost entirely. No error is raised in either case, so the request silently goes to the wrong URL.Cause
Both steps operate on
raw_path, which includes the query:_enforce_trailing_slash(_client.py) appends/tourl.raw_path, so the slash lands after the query:/api?key=k/._merge_urlbuildsself.base_url.raw_path + merge_url.raw_path.lstrip(b"/"), so the request path is appended after the query too.The second case then loses the path because
params=replaces the whole query (#905), and the query now holds the path.Possible fixes
base_urlwith a query string in thebase_urlsetter, with a message pointing toparams=.pathrather thanraw_pathin both places and merge the base query into the request's params.