Skip to content

Commit

Permalink
Merge pull request jaswope#16 from pigoz/ssl_fixes
Browse files Browse the repository at this point in the history
https fixes and a new feature
  • Loading branch information
waterlink committed Sep 18, 2015
2 parents 0562207 + 6fc82f1 commit 59e7fe4
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ run app
* `:password` password for basic auth
* `:matching` is a global only option, if set to :first the first matched url will be requested (no ambigous error). Default: :all.
* `:timeout` seconds to timout the requests
* `:force_ssl` redirects to ssl version, if not already using it (requires `:replace_response_host`). Default: false.

### Sample usage in a Ruby on Rails app

Expand Down
20 changes: 18 additions & 2 deletions lib/rack_reverse_proxy/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ def proxy(env, source_request, rule)

options = @global_options.dup.merge(rule.options)

if options[:force_ssl] && options[:replace_response_host] &&
source_request.scheme == "http"
rewrite_uri(uri, source_request)
uri.scheme = "https"
return [301, { "Location" => uri.to_s }, ""]
end

# Initialize request
target_request = Net::HTTP.const_get(
source_request.request_method.capitalize
Expand Down Expand Up @@ -115,8 +122,7 @@ def proxy(env, source_request, rule)
# Replace the location header with the proxy domain
if response_headers["Location"] && options[:replace_response_host]
response_location = URI(response_headers["location"])
response_location.host = source_request.host
response_location.port = source_request.port
rewrite_uri(response_location, source_request)
response_headers["Location"] = response_location.to_s
end

Expand Down Expand Up @@ -155,5 +161,15 @@ def format_headers(headers)
acc
end
end

def request_default_port?(req)
[["http", 80], ["https", 443]].include?([req.scheme, req.port])
end

def rewrite_uri(uri, original_req)
uri.scheme = original_req.scheme
uri.host = original_req.host
uri.port = original_req.port unless request_default_port?(original_req)
end
end
end
31 changes: 31 additions & 0 deletions spec/rack/reverse_proxy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,16 @@ def app
get "http://example.com:3000/test/stuff"
expect(last_response.headers["location"]).to eq("http://example.com:3000/bar")
end

it "doesn't keep the port when it's default for the protocol" do
# webmock doesn't allow to stub an https URI, but this is enough to
# reply to the https code path
stub_request(:get, "http://example.com/test/stuff").to_return(
:headers => { "location" => "http://test.com/bar" }
)
get "https://example.com/test/stuff"
expect(last_response.headers["location"]).to eq("https://example.com/bar")
end
end

describe "with ambiguous routes and all matching" do
Expand Down Expand Up @@ -288,6 +298,27 @@ def app
end
end

describe "with force ssl turned on" do
def app
Rack::ReverseProxy.new(dummy_app) do
reverse_proxy "/test", "http://example1.com/",
:force_ssl => true, :replace_response_host => true
end
end

it "redirects to the ssl version when requesting non-ssl" do
stub_request(:get, "http://example1.com/test/stuff").to_return(:body => "proxied")
get "http://example.com/test/stuff"
expect(last_response.headers["Location"]).to eq("https://example.com/test/stuff")
end

it "does nothing when already ssl" do
stub_request(:get, "http://example1.com/test/stuff").to_return(:body => "proxied")
get "https://example.com/test/stuff"
expect(last_response.body).to eq("proxied")
end
end

describe "with a route as a regular expression" do
def app
Rack::ReverseProxy.new(dummy_app) do
Expand Down

0 comments on commit 59e7fe4

Please sign in to comment.