require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe Rack::ReverseProxy do include Rack::Test::Methods include WebMock::API def app Rack::ReverseProxy.new end def dummy_app lambda { [200, {}, ['Dummy App']] } end describe "as middleware" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy '/test', 'http://example.com/', {:preserve_host => true} end end it "should forward requests to the calling app when the path is not matched" do get '/' last_response.body.should == "Dummy App" last_response.should be_ok end it "should proxy requests when a pattern is matched" do stub_request(:get, 'http://example.com/test').to_return({:body => "Proxied App"}) get '/test' last_response.body.should == "Proxied App" end it "the response header should never contain Status" do stub_request(:any, 'example.com/test/stuff').to_return(:headers => {'Status' => '200 OK'}) get '/test/stuff' last_response.headers['Status'].should == nil end it "the response header should never transfer-encoding" do stub_request(:any, 'example.com/test/stuff').to_return(:headers => {'transfer-encoding' => 'Chunked'}) get '/test/stuff' last_response.headers['transfer-encoding'].should == nil end it "should set the Host header" do stub_request(:any, 'example.com/test/stuff') get '/test/stuff' a_request(:get, 'http://example.com/test/stuff').with(:headers => {"Host" => "example.com"}).should have_been_made end describe "with preserve host turned off" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy '/test', 'http://example.com/' end end it "should not set the Host header" do stub_request(:any, 'example.com/test/stuff') get '/test/stuff' a_request(:get, 'http://example.com/test/stuff').should have_been_made end end describe "with basic auth turned on" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy '/test', 'http://example.com/', {:username => "joe", :password => "shmoe"} end end it "should make request with basic auth" do stub_request(:get, "http://joe:shmoe@example.com/test/stuff").to_return(:body => "secured content") get '/test/stuff' last_response.body.should == "secured content" end end describe "with ambiguous routes" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy '/test', 'http://example.com/' reverse_proxy /^\/test/, 'http://example.com/' end end it "should throw an exception" do lambda { get '/test' }.should raise_error(Rack::AmbiguousProxyMatch) end end describe "with a route as a regular expression" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy %r|^/test(/.*)$|, 'http://example.com$1' end end it "should support subcaptures" do stub_request(:get, 'http://example.com/path').to_return({:body => "Proxied App"}) get '/test/path' last_response.body.should == "Proxied App" end end describe "with a https route" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy '/test', 'https://example.com' end end it "should make a secure request" do stub_request(:get, 'https://example.com/test/stuff').to_return({:body => "Proxied Secure App"}) get '/test/stuff' last_response.body.should == "Proxied Secure App" end end describe "with a route as a string" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy '/test', 'http://example.com' reverse_proxy '/path', 'http://example.com/foo$0' end end it "should append the full path to the uri" do stub_request(:get, 'http://example.com/test/stuff').to_return({:body => "Proxied App"}) get '/test/stuff' last_response.body.should == "Proxied App" end end describe "with a generic url" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy '/test', 'example.com' end end it "should throw an exception" do lambda{ app }.should raise_error(Rack::GenericProxyURI) end end describe "with a matching route" do def app Rack::ReverseProxy.new(dummy_app) do reverse_proxy '/test', 'http://example.com/' end end %w|get head delete put post|.each do |method| describe "and using method #{method}" do it "should forward the correct request" do stub_request(method.to_sym, 'http://example.com/test').to_return({:body => "Proxied App for #{method}"}) eval "#{method} '/test'" last_response.body.should == "Proxied App for #{method}" end if %w|put post|.include?(method) it "should forward the request payload" do stub_request(method.to_sym, 'http://example.com/test').to_return { |req| {:body => req.body} } eval "#{method} '/test', {:test => 'test'}" last_response.body.should == "test=test" end end end end end end describe "as a rack app" do it "should respond with 404 when the path is not matched" do get '/' last_response.should be_not_found end end end