Skip to content

Commit c57a52a

Browse files
committed
Fix: Handle relative URLs in HTTP redirects
Fixes #442
1 parent b6ccc27 commit c57a52a

File tree

2 files changed

+47
-2
lines changed

2 files changed

+47
-2
lines changed

lib/u3d/utils.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,11 @@ def follow_redirects(url, redirect_limit: 10, http_method: :get, request_headers
8484
when Net::HTTPSuccess
8585
yield(request, response)
8686
when Net::HTTPRedirection
87-
UI.verbose "Redirected to #{response['location']}"
88-
follow_redirects(response['location'], redirect_limit: redirect_limit - 1, http_method: http_method, request_headers: request_headers, &block)
87+
location = response['location']
88+
# Handle relative URLs in redirects
89+
location = (uri + location).to_s if location && !location.start_with?('http://', 'https://')
90+
UI.verbose "Redirected to #{location}"
91+
follow_redirects(location, redirect_limit: redirect_limit - 1, http_method: http_method, request_headers: request_headers, &block)
8992
else raise "Request failed with status #{response.code}"
9093
end
9194
end

spec/u3d/utils_spec.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,47 @@
105105
end
106106
end
107107
end
108+
109+
describe '.follow_redirects' do
110+
it 'handles relative URLs in redirects' do
111+
http_mock = double('http')
112+
redirect_response = double('redirect_response')
113+
success_response = double('success_response')
114+
115+
# First request returns redirect with relative URL
116+
allow(redirect_response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(false)
117+
allow(redirect_response).to receive(:kind_of?).with(Net::HTTPRedirection).and_return(true)
118+
allow(Net::HTTPSuccess).to receive(:===).with(redirect_response).and_return(false)
119+
allow(Net::HTTPRedirection).to receive(:===).with(redirect_response).and_return(true)
120+
allow(redirect_response).to receive(:[]).with('location').and_return('/new-path')
121+
allow(redirect_response).to receive(:code).and_return('302')
122+
123+
# Second request succeeds
124+
allow(success_response).to receive(:kind_of?).with(Net::HTTPSuccess).and_return(true)
125+
allow(success_response).to receive(:kind_of?).with(Net::HTTPRedirection).and_return(false)
126+
allow(Net::HTTPSuccess).to receive(:===).with(success_response).and_return(true)
127+
allow(Net::HTTPRedirection).to receive(:===).with(success_response).and_return(false)
128+
allow(success_response).to receive(:body).and_return('success')
129+
allow(success_response).to receive(:code).and_return('200')
130+
131+
call_count = 0
132+
allow(Net::HTTP).to receive(:start) do |host, port, _opts, &block|
133+
call_count += 1
134+
expect(host).to eq('example.com')
135+
expect(port).to eq(443)
136+
allow(http_mock).to receive(:request) do
137+
call_count == 1 ? redirect_response : success_response
138+
end
139+
block.call(http_mock)
140+
end
141+
142+
result = U3d::Utils.follow_redirects('https://example.com/original') do |_request, response|
143+
response.body
144+
end
145+
146+
expect(result).to eql('success')
147+
expect(call_count).to eq(2)
148+
end
149+
end
108150
end
109151
end

0 commit comments

Comments
 (0)