Skip to content

Commit ec356e6

Browse files
committed
Allow relative base URI in merge.
1 parent 52077e9 commit ec356e6

2 files changed

Lines changed: 26 additions & 3 deletions

File tree

lib/uri/generic.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,10 +1108,13 @@ def merge!(oth)
11081108
#
11091109
# +oth+::
11101110
# URI or String
1111+
# +allow_relative+::
1112+
# Boolean (false by default)
11111113
#
11121114
# == Description
11131115
#
1114-
# Merges two URIs.
1116+
# Merges two URIs. If +allow_relative+ is true, allows merging
1117+
# a relative base URI with a relative URI.
11151118
#
11161119
# == Usage
11171120
#
@@ -1121,7 +1124,7 @@ def merge!(oth)
11211124
# uri.merge("/main.rbx?page=1")
11221125
# # => "http://my.example.com/main.rbx?page=1"
11231126
#
1124-
def merge(oth)
1127+
def merge(oth, allow_relative = false)
11251128
rel = parser.__send__(:convert_to_uri, oth)
11261129

11271130
if rel.absolute?
@@ -1130,7 +1133,7 @@ def merge(oth)
11301133
return rel
11311134
end
11321135

1133-
unless self.absolute?
1136+
unless self.absolute? || allow_relative
11341137
raise BadURIError, "both URI are relative"
11351138
end
11361139

test/uri/test_generic.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,26 @@ def test_merge_authority
288288
assert_equal(u0, u1)
289289
end
290290

291+
def test_merge_allow_relative
292+
# When both URIs are relative, merge should raise unless allow_relative is true:
293+
base = URI.parse('a/b/c')
294+
assert_raise(URI::BadURIError) do
295+
base.merge('d/e')
296+
end
297+
298+
# With allow_relative=true, relative base + relative ref should merge paths:
299+
merged = base.merge('d/e', true)
300+
assert_equal('a/b/d/e', merged.to_s)
301+
302+
# Parent directory traversals should be handled as with absolute bases:
303+
merged_up = base.merge('../x', true)
304+
assert_equal('a/x', merged_up.to_s)
305+
306+
# Leading slash should reset to root-like behavior within relative context:
307+
merged_abs = base.merge('/z', true)
308+
assert_equal('/z', merged_abs.to_s)
309+
end
310+
291311
def test_route
292312
url = URI.parse('http://hoge/a.html').route_to('http://hoge/b.html')
293313
assert_equal('b.html', url.to_s)

0 commit comments

Comments
 (0)