Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/rfc3986/normalizers.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ def normalize_authority(

def normalize_username(username: str) -> str:
"""Normalize a username to make it safe to include in userinfo."""
return urlquote(username)
return urlquote(username, safe="")


def normalize_password(password: str) -> str:
"""Normalize a password to make safe for userinfo."""
return urlquote(password)
return urlquote(password, safe="")


def normalize_host(host: str) -> str:
Expand Down
21 changes: 21 additions & 0 deletions tests/test_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def test_add_scheme(scheme):
("user", None, "user"),
("user@domain.com", "password", "user%40domain.com:password"),
("user", "pass:word", "user:pass%3Aword"),
("domain/user", "pass/word", "domain%2Fuser:pass%2Fword"),
],
)
def test_add_credentials(username, password, userinfo):
Expand All @@ -102,6 +103,26 @@ def test_add_credentials_requires_username():
builder.URIBuilder().add_credentials(None, None)


@pytest.mark.parametrize(
"username, password",
[("domain/user", "password"), ("user", "pass/word")],
)
def test_credentials_with_slashes_preserve_uri_components(username, password):
"""Keep credential slashes from terminating the URI authority."""
reference = (
builder.URIBuilder()
.add_scheme("https")
.add_host("example.com")
.add_credentials(username, password)
.add_path("resource")
.finalize()
)
reparsed = uri_reference(reference.unsplit())
assert reparsed.host == "example.com"
assert reparsed.userinfo == reference.userinfo
assert reparsed.path == "/resource"


@pytest.mark.parametrize(
["hostname", "expected_hostname"],
[
Expand Down