Skip to content

Fix leading slash for abspath in joinpath - #62

Closed
pb866 wants to merge 2 commits into
JuliaWeb:masterfrom
LIM-AeroCloud:bug/joinpath
Closed

Fix leading slash for abspath in joinpath#62
pb866 wants to merge 2 commits into
JuliaWeb:masterfrom
LIM-AeroCloud:bug/joinpath

Conversation

@pb866

@pb866 pb866 commented Dec 28, 2024

Copy link
Copy Markdown
Contributor

Currently, joinpath gives two leading slashes, when an absolute path is joined to an empty URI path. This PR fixes this issue.

julia> using URIs

julia> u = URI("http://test.com")
URI("http://test.com")

julia> joinpath(u, "/abs/path")
URI("http://test.com//abs/path")

Signed-off-by: Peter Bräuer <pb866.git@gmail.com>
Add tests to add absolut path with and without trailing slash and
absolut path with additional part to an empty uri path.

Signed-off-by: Peter Bräuer <pb866.git@gmail.com>
@pb866

pb866 commented Jan 12, 2025

Copy link
Copy Markdown
Contributor Author

Is there anything that needs to be done before this can be merged? I think, the failing test has nothing to do with this fix.

An alternative fix would be to ensure non-empty URI paths, so the condition that was adjusted in this PR is not needed at all. This is also a workaround for the current situation (without tempering with the package's code), but it would be nice to have a proper resolution one way or the other.

@ararslan

ararslan commented Feb 20, 2025

Copy link
Copy Markdown
Member

Thanks for the contribution and apologies for the delayed response. What you've implemented here seems reasonable to me and is what I would generally have expected joinpath to do in this case. My read of RFC 2396 also suggests that what you're proposing is the correct behavior and joinpath is currently (arguably) not compliant. However, this is technically breaking as some code may be relying on the current behavior. I'm in favor of merging but would want a second opinion; @quinnj?

@pb866

pb866 commented Apr 15, 2025

Copy link
Copy Markdown
Contributor Author

Thanks @ararslan for your review. I hadn’t considered it a breaking change since URIs claims to obey RFC-3986, which builds on RFC-2396. So I would argue, this PR is a bug fix as it corrects currently incorrectly implemented behaviour. Therefore, even a patch release should be fine. @quinnj do you have other views on this. It would be great to see this getting merged, so I can use it in some other project.

@ararslan
ararslan requested a review from quinnj June 18, 2025 20:27
@quinnj

quinnj commented Jul 23, 2026

Copy link
Copy Markdown
Member

Thanks for the contribution, and sorry this has sat for so long. I agree that the reported /abs/path behavior is a bug: joinpath(URI("http://test.com"), "/abs/path") should produce http://test.com/abs/path, and we should get that fix in + released.

There is one related double-slash case I think we should settle before merging. The new condition also changes //server/share. For example:

x = joinpath(URI("file:"), "//server/share")
string(x)              # "file://server/share"
x.host                 # ""
x.path                 # "//server/share"
URI(string(x)) == x    # false

The serialized form treats server as the authority, but the stored components still have no authority. RFC 3986 also reserves a leading // for a network-path reference when no authority is already present.

Could you handle or reject that case explicitly, or keep absent-authority // behavior out of the above fix and add regression tests for file:, file://, and an empty URI?

If you want me to fix/push to this PR directly, I'm happy to do that and we can merge and be on our way (I know it can be weird/ahrd to pick something up after its' been a while)

[double-slash case/example found by codex while helping review this; comments are my own]

@pb866

pb866 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @quinnj for the thorough review! You're making an excellent point. But this is currently also not working on master:

x = joinpath(URI("file:"), "/a/b/c") # URI("file://a/b/c")
y = URI(string(x)) # URI("file://a/b/c")
x == y # false

So, there should probably be some regex check that the host includes a dot or whatever rules there are for a host (I'm no URI expert). I have no problems with anybody working on the fix to continue the work on this branch. If I can support in any way to get this on master, let me know.

quinnj added a commit that referenced this pull request Aug 9, 2026
joinpath(URI("http://test.com"), "/abs/path") now correctly yields
http://test.com/abs/path instead of http://test.com//abs/path.

Additionally, when the base URI has no authority (host) component, a
joined path beginning with "//" is unrepresentable per RFC 3986 Sec. 3.3
(it would be re-parsed with the first path segment as the authority), so
joinpath now throws an informative ArgumentError in that case. Includes
regression tests for "file:", "file://", empty-URI, and
authority-present cases, and bumps the version to 1.6.3.

Co-authored-by: Peter Bräuer <pb866.git@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@quinnj

quinnj commented Aug 9, 2026

Copy link
Copy Markdown
Member

This landed via #71 (squash-merged as 0f4ecc3, with co-author credit) — GitHub doesn't allow maintainer pushes to org-owned fork branches, so I carried this branch over to the base repo to finish it. On top of the fix here, joinpath now throws an ArgumentError when the base URI has no authority component and the joined path begins with "//", since such a URI is unrepresentable per RFC 3986 Sec. 3.3 (this also covers the master-branch round-trip issue you pointed out). Registering v1.6.3 now. Thanks @pb866 for the contribution and the patience!

@quinnj quinnj closed this Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants