Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "URIs"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
authors = ["Jacob Quinn", "Sam O'Connor", "contributors: https://github.com/JuliaWeb/URIs.jl/graphs/contributors"]
version = "1.6.2"
version = "1.6.3"

[compat]
julia = "1.6"
Expand Down
13 changes: 11 additions & 2 deletions src/URIs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,10 @@ end
joinpath(uri::URI, path::AbstractString) -> URI

Join the path component of URI and other parts.

If `uri` has no authority (host) component, the resulting path must not begin
with `"//"`, since such a URI cannot be represented (RFC 3986 Section 3.3);
an `ArgumentError` is thrown in that case.
"""
function Base.joinpath(uri::URI, parts::String...)
path = uri.path
Expand All @@ -669,10 +673,15 @@ function Base.joinpath(uri::URI, parts::String...)
end
end

if isempty(uri.path)
if isempty(uri.path) && !startswith(path, "/")
path = "/" * path
end
return URI(uri; path=normpath(path))
path = normpath(path)
if isabsent(uri.host) && startswith(path, "//")
throw(ArgumentError("URI without authority (host) cannot have a path " *
"beginning with \"//\" (RFC 3986 Section 3.3): $(repr(path))"))
end
return URI(uri; path=path)
end

"""
Expand Down
25 changes: 24 additions & 1 deletion test/uri.jl
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ urltests = URLTest[
@test URIs.splitpath("/foo/bar") == ["foo", "bar"]
end
end

@testset "splitfilepath" begin
@static if Sys.iswindows()
data = [
Expand Down Expand Up @@ -612,6 +612,29 @@ urltests = URLTest[
@test joinpath(URIs.URI("http://a.b.c/d/f"), "/b", "c") == URI("http://a.b.c/b/c")
@test joinpath(URIs.URI("http://a.b.c/"), "b", "c") == URI("http://a.b.c/b/c")
@test joinpath(URIs.URI("http://a.b.c"), "b", "c") == URI("http://a.b.c/b/c")
@test joinpath(URIs.URI("http://a.b.c"), "/b/c/") == URI("http://a.b.c/b/c/")
@test joinpath(URIs.URI("http://a.b.c"), "/b/c") == URI("http://a.b.c/b/c")
@test joinpath(URIs.URI("http://a.b.c"), "/b", "c") == URI("http://a.b.c/b/c")

# absolute paths joined to URIs without an authority (host) component
@test string(joinpath(URIs.URI("file:"), "/a/b/c")) == "file:/a/b/c"
@test string(joinpath(URIs.URI("file://"), "/a/b/c")) == "file:///a/b/c"
@test string(joinpath(URIs.URI(), "/a/b")) == "/a/b"
# a path beginning with "//" cannot be represented without an authority
# component (RFC 3986 Section 3.3)
@test_throws ArgumentError joinpath(URIs.URI("file:"), "//server/share")
@test_throws ArgumentError joinpath(URIs.URI(), "//server/share")
# with an authority component (even an empty one), "//" paths are fine
@test string(joinpath(URIs.URI("file://"), "//server/share")) == "file:////server/share"
@test string(joinpath(URIs.URI("http://a.b.c"), "//b/c")) == "http://a.b.c//b/c"
# results must round-trip through their string representation
for u in (joinpath(URIs.URI("file:"), "/a/b/c"),
joinpath(URIs.URI("file://"), "/a/b/c"),
joinpath(URIs.URI(), "/a/b"),
joinpath(URIs.URI("file://"), "//server/share"),
joinpath(URIs.URI("http://a.b.c"), "//b/c"))
@test URI(string(u)) == u
end
end

@testset "resolvereference" begin
Expand Down
Loading