Skip to content

Commit 9047a08

Browse files
Allow explicit base URL ports while blocking encoded host delimiters
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 4fdd0bf commit 9047a08

3 files changed

Lines changed: 22 additions & 3 deletions

File tree

hyperbrowser/config.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
from dataclasses import dataclass
2+
import re
23
from urllib.parse import unquote, urlparse
34
from typing import Dict, Mapping, Optional
45
import os
56

67
from .exceptions import HyperbrowserError
78
from .header_utils import normalize_headers, parse_headers_env_json
89

10+
_ENCODED_HOST_DELIMITER_PATTERN = re.compile(r"%(?:2f|3f|23|40|3a)", re.IGNORECASE)
11+
912

1013
@dataclass
1114
class ClientConfig:
@@ -102,6 +105,10 @@ def normalize_base_url(base_url: str) -> str:
102105

103106
decoded_base_netloc = parsed_base_url.netloc
104107
for _ in range(10):
108+
if _ENCODED_HOST_DELIMITER_PATTERN.search(decoded_base_netloc):
109+
raise HyperbrowserError(
110+
"base_url host must not contain encoded delimiter characters"
111+
)
105112
next_decoded_base_netloc = unquote(decoded_base_netloc)
106113
if next_decoded_base_netloc == decoded_base_netloc:
107114
break
@@ -121,9 +128,7 @@ def normalize_base_url(base_url: str) -> str:
121128
for character in decoded_base_netloc
122129
):
123130
raise HyperbrowserError("base_url host must not contain control characters")
124-
if any(
125-
character in {"?", "#", "/", "@", ":"} for character in decoded_base_netloc
126-
):
131+
if any(character in {"?", "#", "/", "@"} for character in decoded_base_netloc):
127132
raise HyperbrowserError(
128133
"base_url host must not contain encoded delimiter characters"
129134
)

tests/test_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ def test_client_config_normalize_base_url_validates_and_normalizes():
360360
ClientConfig.normalize_base_url(" https://example.local/custom/api/ ")
361361
== "https://example.local/custom/api"
362362
)
363+
assert (
364+
ClientConfig.normalize_base_url("https://example.local:443/custom/api")
365+
== "https://example.local:443/custom/api"
366+
)
363367

364368
with pytest.raises(HyperbrowserError, match="base_url must be a string"):
365369
ClientConfig.normalize_base_url(None) # type: ignore[arg-type]

tests/test_url_building.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ def test_client_build_url_uses_normalized_base_url():
4747
client.close()
4848

4949

50+
def test_client_build_url_supports_base_url_with_port():
51+
client = Hyperbrowser(
52+
config=ClientConfig(api_key="test-key", base_url="https://example.local:8443")
53+
)
54+
try:
55+
assert client._build_url("/session") == "https://example.local:8443/api/session"
56+
finally:
57+
client.close()
58+
59+
5060
def test_client_build_url_avoids_duplicate_api_when_base_url_already_has_api():
5161
client = Hyperbrowser(
5262
config=ClientConfig(api_key="test-key", base_url="https://example.local/api")

0 commit comments

Comments
 (0)