Skip to content

Commit 1de6c4f

Browse files
authored
Fix URI#host= to wrap IPv6 address in brackets (#16164)
The square brackets around IPv6 addresses are only required for URIs. This also ensures a URI initialized with otherwise valid data is a valid URI.
1 parent ccb3e57 commit 1de6c4f

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

spec/std/uri_spec.cr

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,42 @@ describe "URI" do
172172
it { URI.new(path: "/foo").hostname.should be_nil }
173173
end
174174

175+
describe "#host" do
176+
it "works with IPv6 address literals" do
177+
uri = URI.new("http", "[::1]", path: "foo")
178+
uri.hostname.should eq("::1")
179+
uri.host.should eq("[::1]")
180+
uri.to_s.should eq "http://[::1]/foo"
181+
uri.host = "[::1]"
182+
uri.to_s.should eq "http://[::1]/foo"
183+
184+
uri = URI.new("http", "::1", path: "foo")
185+
uri.hostname.should eq("::1")
186+
uri.host.should eq("[::1]")
187+
uri.to_s.should eq "http://[::1]/foo"
188+
uri.host = "::1"
189+
uri.to_s.should eq "http://[::1]/foo"
190+
end
191+
192+
it "works with IPv4 addresses" do
193+
uri = URI.new("http", "192.168.0.2", path: "foo")
194+
uri.hostname.should eq("192.168.0.2")
195+
uri.host.should eq("192.168.0.2")
196+
uri.to_s.should eq "http://192.168.0.2/foo"
197+
uri.host = "192.168.0.2"
198+
uri.to_s.should eq "http://192.168.0.2/foo"
199+
end
200+
201+
it "works with domain names" do
202+
uri = URI.new("http", "test.domain", path: "foo")
203+
uri.hostname.should eq("test.domain")
204+
uri.host.should eq("test.domain")
205+
uri.to_s.should eq "http://test.domain/foo"
206+
uri.host = "test.domain"
207+
uri.to_s.should eq "http://test.domain/foo"
208+
end
209+
end
210+
175211
describe "#authority" do
176212
it { URI.new.authority.should be_nil }
177213
it { URI.new(scheme: "scheme").authority.should be_nil }

src/uri.cr

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ class URI
9999
getter host : String?
100100

101101
# Sets the host component of the URI.
102-
setter host : String?
102+
def host=(host : String?)
103+
@host = host && !host.starts_with?('[') && host.includes?(':') ? "[#{host}]" : host
104+
end
103105

104106
# Returns the port component of the URI.
105107
#
@@ -175,7 +177,9 @@ class URI
175177

176178
def_equals_and_hash scheme, host, port, path, query, user, password, fragment
177179

178-
def initialize(@scheme = nil, @host = nil, @port = nil, @path = "", query : String | Params | Nil = nil, @user = nil, @password = nil, @fragment = nil)
180+
def initialize(@scheme = nil, host = nil, @port = nil, @path = "", query : String | Params | Nil = nil, @user = nil, @password = nil, @fragment = nil)
181+
# wrap IPv6 addresses
182+
self.host = host
179183
@query = query.try(&.to_s)
180184
end
181185

0 commit comments

Comments
 (0)