diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 30aef2e7..981189a7 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -29,6 +29,10 @@ module Sinatra alias secure? ssl? end + def forwarded? + @env.include? "HTTP_X_FORWARDED_HOST" + end + def route @route ||= begin path = Rack::Utils.unescape(path_info) @@ -104,7 +108,16 @@ module Sinatra def uri(addr = nil, absolute = true, add_script_name = true) return addr if addr =~ /^https?:\/\// uri = [host = ""] - uri << request.host_with_port if absolute + if absolute + host << 'http' + host << 's' if request.secure? + host << "://" + if request.forwarded? or request.port != (request.secure? ? 443 : 80) + host << request.host_with_port + else + host << request.host + end + end uri << request.script_name.to_s if add_script_name uri << (addr ? addr : request.path_info).to_s File.join uri diff --git a/test/helpers_test.rb b/test/helpers_test.rb index 935cc2ab..bee2d005 100644 --- a/test/helpers_test.rb +++ b/test/helpers_test.rb @@ -111,6 +111,18 @@ class HelpersTest < Test::Unit::TestCase response = request.get('/', 'SERVER_PORT' => '444') assert_equal 'http://example.org:444/foo', response['Location'] end + + it 'works behind a reverse proxy' do + mock_app do + get '/' do + redirect '/foo' + end + end + + request = Rack::MockRequest.new(@app) + response = request.get('/', 'HTTP_X_FORWARDED_HOST' => 'example.com', 'SERVER_PORT' => '8080') + assert_equal 'http://example.com/foo', response['Location'] + end end describe 'error' do