handle proxy redirects even if the scheme doesn't match

Normally, when receiving a Location header, nginx will rewrite it to
reference a URL if it matches the proxy_pass. This breaks when the
scheme changes, since proxy_pass can have a scheme. For instance, if you
have a proxy: "https://www.foo.com", but the Location on a redirect from
that site returns "http://www.foo.com" nginx won't rewrite the URL. This
fixes it by specifying the redirect for both http and https.
parent a2e3a022
...@@ -29,6 +29,9 @@ class NginxConfig ...@@ -29,6 +29,9 @@ class NginxConfig
json["proxies"][loc]["path"] = uri.path json["proxies"][loc]["path"] = uri.path
uri.path = "" uri.path = ""
json["proxies"][loc]["host"] = uri.to_s json["proxies"][loc]["host"] = uri.to_s
redirect_scheme = uri.scheme == "https" ? "http" : "https"
json["proxies"][loc]["redirect"] = uri.dup.tap {|u| u.scheme = redirect_scheme }.to_s
json["proxies"][loc]["redirect"] += "/" if !uri.to_s.end_with?("/")
end end
json["clean_urls"] ||= DEFAULT[:clean_urls] json["clean_urls"] ||= DEFAULT[:clean_urls]
......
...@@ -81,6 +81,8 @@ http { ...@@ -81,6 +81,8 @@ http {
location <%= location %> { location <%= location %> {
proxy_pass <%= hash['origin'] %>; proxy_pass <%= hash['origin'] %>;
proxy_ssl_server_name on; proxy_ssl_server_name on;
proxy_redirect default;
proxy_redirect <%= hash["redirect"] %> <%= location %>;
} }
<% end %> <% end %>
...@@ -95,6 +97,8 @@ http { ...@@ -95,6 +97,8 @@ http {
rewrite ^<%= location %>(.*)$ <%= hash['path'] %>/$1 break; rewrite ^<%= location %>(.*)$ <%= hash['path'] %>/$1 break;
proxy_pass <%= hash['host'] %>; proxy_pass <%= hash['host'] %>;
proxy_ssl_server_name on; proxy_ssl_server_name on;
proxy_redirect default;
proxy_redirect <%= hash["redirect"] %> <%= location %>;
} }
<% end %> <% end %>
......
...@@ -383,6 +383,7 @@ STATIC_JSON ...@@ -383,6 +383,7 @@ STATIC_JSON
include PathHelper include PathHelper
let(:name) { "proxies" } let(:name) { "proxies" }
let(:proxy_scheme) { "http" }
let(:static_json_path) { fixtures_path("proxies/static.json") } let(:static_json_path) { fixtures_path("proxies/static.json") }
let(:proxy) do let(:proxy) do
<<PROXY <<PROXY
...@@ -393,6 +394,16 @@ end ...@@ -393,6 +394,16 @@ end
get "/foo/baz/" do get "/foo/baz/" do
"baz" "baz"
end end
get "/foo/http_redirect/" do
uri = URI("http://\#{request.host}/foo/redirect")
redirect URI(uri), 307
end
get "/foo/https_redirect/" do
uri = URI("https://\#{request.host}/foo/redirect")
redirect URI(uri), 307
end
PROXY PROXY
end end
let(:setup_static_json) do let(:setup_static_json) do
...@@ -402,7 +413,7 @@ PROXY ...@@ -402,7 +413,7 @@ PROXY
{ {
"proxies": { "proxies": {
"/api/": { "/api/": {
"origin": "http://#{@proxy_ip_address}#{path}" "origin": "#{proxy_scheme}://#{@proxy_ip_address}#{path}"
} }
}, },
"headers": { "headers": {
...@@ -419,7 +430,7 @@ STATIC_JSON ...@@ -419,7 +430,7 @@ STATIC_JSON
before do before do
@proxy_ip_address = app.proxy.ip_address @proxy_ip_address = app.proxy.ip_address
setup_static_json.call("/foo/") setup_static_json.call("/foo")
end end
after do after do
...@@ -439,6 +450,18 @@ STATIC_JSON ...@@ -439,6 +450,18 @@ STATIC_JSON
expect(response["X-Header"]).to be_nil expect(response["X-Header"]).to be_nil
end end
end end
it "should hanadle redirects regardless of scheme" do
app.run do
response = app.get("/api/http_redirect/")
expect(response.code).to eq("307")
expect(response["Location"]).not_to include(@proxy_ip_address)
response = app.get("/api/https_redirect/")
expect(response.code).to eq("307")
expect(response["Location"]).not_to include(@proxy_ip_address)
end
end
end end
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment