Skip to content

URL.join() decodes percent-encoded characters in the base path (e.g. %2F becomes /) #1774

Description

@pramodavansaber

Description

URL.join() decodes percent-encoded characters in the base URL's path when merging a relative reference (RFC 3986 §5.3, the branch used when the base path does not end with /). The merge is built from self.parts, which are already percent-decoded, so an encoded delimiter like %2F is turned into a real / and the path structure is corrupted.

Reproduction

from yarl import URL

print(URL("http://x/a%2Fb/c").join(URL("d")))   # http://x/a/b/d
print(URL("http://x/a%20b/c").join(URL("d")))   # http://x/a b/d

Expected vs actual

result
expected http://x/a%2Fb/d (the a%2Fb segment is preserved)
actual http://x/a/b/d (%2F decoded into a separator -> the single segment splits into two)

%20 is likewise decoded into a literal space.

Root cause

The RFC-3986 merge branch in URL.join constructs the merged path from self.parts[:-1]. parts runs the segments through UNQUOTER (decoded), so feeding them back into a path mixes decoded text with the still-encoded relative path. The raw/encoded segments (raw_parts) should be used for the merge so the original encoding round-trips.

(Distinct from #896, which is RFC-correct last-segment replacement; this is specifically the loss of percent-encoding.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions