From b6ba0cdc80f28c5071dc4c8fac95db4f03e8bdc2 Mon Sep 17 00:00:00 2001 From: Pedro Carbajal Date: Fri, 5 Jan 2024 17:24:17 +0900 Subject: [PATCH] Fix resolution of relative container URL redirects --- lib/fmrest/v1/container_fields.rb | 6 +++++- spec/core/v1/container_fields_spec.rb | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/fmrest/v1/container_fields.rb b/lib/fmrest/v1/container_fields.rb index 85f8abe..5dfcb9f 100644 --- a/lib/fmrest/v1/container_fields.rb +++ b/lib/fmrest/v1/container_fields.rb @@ -55,7 +55,11 @@ def fetch_container_data(container_field_url, base_connection = nil) raise FmRest::ContainerFieldError, "Container field's initial request didn't return a session cookie, the URL may be stale (try downloading it again immediately after retrieving the record)" end - url = URI(e.io.meta["location"]) + url = if e.io.meta["location"].match(/\Ahttps?:/) + URI(e.io.meta["location"]) + else + URI.join("#{url.scheme}://#{url.host}:#{url.port}", e.io.meta["location"]) + end # Now request the URL again with the proper session cookie using # OpenURI, which wraps the response in an IO object which also responds diff --git a/spec/core/v1/container_fields_spec.rb b/spec/core/v1/container_fields_spec.rb index 16ee329..37e4524 100644 --- a/spec/core/v1/container_fields_spec.rb +++ b/spec/core/v1/container_fields_spec.rb @@ -6,7 +6,7 @@ let(:extendee) { Object.new.tap { |obj| obj.extend(described_class) } } describe "#fetch_container_data" do - let(:container_url) { "https://foo.bar/qux" } + let(:container_url) { "https://foo.bar:4444/qux" } context "when given an invalid URL" do it { expect { extendee.fetch_container_data("boo boo") }.to raise_error(FmRest::ContainerFieldError, /Invalid container field URL/) } @@ -27,16 +27,25 @@ context "when the given URL is a redirect" do context "but doesn't return a Set-Cookie header" do it "raises an FmRest::ContainerFieldError" do - stub_request(:get, container_url).to_return(status: 302, headers: { "Location" => container_url }) + stub_request(:get, container_url).to_return(status: 302, headers: { "Location" => "/irrelevant" }) expect { extendee.fetch_container_data(container_url) }.to raise_error(FmRest::ContainerFieldError, /session cookie/) end end - context "and returns a Set-Cookie header" do + context "when it responds with a Set-Cookie and an absolute Location header" do it "returns an IO object with the container field contents" do - stub_request(:get, container_url).to_return(status: 302, headers: { "Location" => container_url, "Set-Cookie" => "secret cookie" }) - stub_request(:get, container_url).with(headers: { "Cookie" => "secret cookie" }).to_return(body: "hi there") + stub_request(:get, container_url).to_return(status: 302, headers: { "Location" => "https://foo.bar:4444/absolute", "Set-Cookie" => "secret cookie" }) + stub_request(:get, "https://foo.bar:4444/absolute").with(headers: { "Cookie" => "secret cookie" }).to_return(body: "hi there") + + expect(extendee.fetch_container_data(container_url).read).to eq("hi there") + end + end + + context "when it responds with a Set-Cookie and a relative Location header" do + it "returns an IO object with the container field contents" do + stub_request(:get, container_url).to_return(status: 302, headers: { "Location" => "/relative", "Set-Cookie" => "secret cookie" }) + stub_request(:get, "https://foo.bar:4444/relative").with(headers: { "Cookie" => "secret cookie" }).to_return(body: "hi there") expect(extendee.fetch_container_data(container_url).read).to eq("hi there") end