Merge pull request #14176 from Frederick888/curl_follow_redirection

Curl: Fix following redirections when base changes
This commit is contained in:
Mike McQuaid 2022-11-29 15:02:11 +00:00 committed by GitHub
commit cb355a23a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 1 deletions

View File

@ -471,7 +471,7 @@ class CurlDownloadStrategy < AbstractFileDownloadStrategy
lines = output.to_s.lines.map(&:chomp)
final_url = curl_response_last_location(parsed_output[:responses], absolutize: true, base_url: url)
final_url = curl_response_follow_redirections(parsed_output[:responses], url)
final_url ||= url
content_disposition_parser = Mechanize::HTTP::ContentDispositionParser.new

View File

@ -556,4 +556,58 @@ describe "Utils::Curl" do
expect(curl_response_last_location([response_hash[:ok]])).to be_nil
end
end
describe "#curl_response_follow_redirections" do
it "returns the original URL when there are no location headers" do
expect(
curl_response_follow_redirections(
[response_hash[:ok]],
"https://brew.sh/test1/test2",
),
).to eq("https://brew.sh/test1/test2")
end
it "returns the URL relative to base when locations are relative" do
expect(
curl_response_follow_redirections(
[response_hash[:redirection_root_relative], response_hash[:ok]],
"https://brew.sh/test1/test2",
),
).to eq("https://brew.sh/example/")
expect(
curl_response_follow_redirections(
[response_hash[:redirection_parent_relative], response_hash[:ok]],
"https://brew.sh/test1/test2",
),
).to eq("https://brew.sh/test1/example/")
expect(
curl_response_follow_redirections(
[
response_hash[:redirection_parent_relative],
response_hash[:redirection_parent_relative],
response_hash[:ok],
],
"https://brew.sh/test1/test2",
),
).to eq("https://brew.sh/test1/example/example/")
end
it "returns new base when there are absolute location(s)" do
expect(
curl_response_follow_redirections(
[response_hash[:redirection], response_hash[:ok]],
"https://brew.sh/test1/test2",
),
).to eq(location_urls[0])
expect(
curl_response_follow_redirections(
[response_hash[:redirection], response_hash[:redirection_parent_relative], response_hash[:ok]],
"https://brew.sh/test1/test2",
),
).to eq("#{location_urls[0]}example/")
end
end
end

View File

@ -506,6 +506,30 @@ module Utils
nil
end
# Returns the final URL by following location headers in cURL responses.
# @param responses [Array<Hash>] An array of hashes containing response
# status information and headers from `#parse_curl_response`.
# @param base_url [String] The URL to use as a base.
# @return [String] The final absolute URL after redirections.
sig {
params(
responses: T::Array[T::Hash[Symbol, T.untyped]],
base_url: String,
).returns(String)
}
def curl_response_follow_redirections(responses, base_url)
responses.each do |response|
next if response[:headers].blank?
location = response[:headers]["location"]
next if location.blank?
base_url = URI.join(base_url, location).to_s
end
base_url
end
private
# Parses HTTP response text from `curl` output into a hash containing the