From 27f592628bc518988062b09b6f53debee61237d1 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Sun, 29 Nov 2015 17:33:58 -0800 Subject: [PATCH] Don't send basic auth header when redirecting to different hosts This behavior is consistent with cURL: https://github.com/bagder/curl/blob/6beb0eee/lib/http.c#L710 --- lib/httparty/request.rb | 13 ++++++++++- spec/httparty/request_spec.rb | 44 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/httparty/request.rb b/lib/httparty/request.rb index 8900e8f..1e232f8 100644 --- a/lib/httparty/request.rb +++ b/lib/httparty/request.rb @@ -128,6 +128,7 @@ module HTTParty end handle_deflation unless http_method == Net::HTTP::Head + handle_host_redirection if response_redirects? handle_response(chunked_body, &block) end @@ -174,7 +175,7 @@ module HTTParty @raw_request.body = body if body @raw_request.body_stream = options[:body_stream] if options[:body_stream] @raw_request.initialize_http_header(options[:headers].to_hash) if options[:headers].respond_to?(:to_hash) - @raw_request.basic_auth(username, password) if options[:basic_auth] + @raw_request.basic_auth(username, password) if options[:basic_auth] && send_authorization_header? setup_digest_auth if options[:digest_auth] end @@ -312,6 +313,16 @@ module HTTParty end end + def handle_host_redirection + redirect_path = options[:uri_adapter].parse last_response['location'] + return if redirect_path.relative? || path.host == redirect_path.host + @changed_hosts = true + end + + def send_authorization_header? + !defined?(@changed_hosts) + end + def response_redirects? case last_response when Net::HTTPNotModified # 304 diff --git a/spec/httparty/request_spec.rb b/spec/httparty/request_spec.rb index 7af0c4b..2f60075 100644 --- a/spec/httparty/request_spec.rb +++ b/spec/httparty/request_spec.rb @@ -1033,6 +1033,50 @@ RSpec.describe HTTParty::Request do end end + describe "#send_authorization_header?" do + context "basic_auth" do + before do + @credentials = { username: "username", password: "password" } + @authorization = "Basic dXNlcm5hbWU6cGFzc3dvcmQ=" + @request.options[:basic_auth] = @credentials + @redirect = stub_response("", 302) + @ok = stub_response('bar', 200) + end + + before(:each) do + allow(@http).to receive(:request).and_return(@redirect, @ok) + end + + it "should not send Authorization header when redirecting to a different host" do + @redirect['location'] = 'http://example.com/' + @request.perform + @request.send(:setup_raw_request) + expect(@request.instance_variable_get(:@raw_request)['authorization']).to be_nil + end + + it "should send Authorization header when redirecting to a relative path" do + @redirect['location'] = '/v3' + @request.perform + @request.send(:setup_raw_request) + expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization) + end + + it "should send Authorization header when redirecting to the same host" do + @redirect['location'] = 'http://api.foo.com/v2' + @request.perform + @request.send(:setup_raw_request) + expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization) + end + + it "should send Authorization header when redirecting to a different port on the same host" do + @redirect['location'] = 'http://api.foo.com:3000/v3' + @request.perform + @request.send(:setup_raw_request) + expect(@request.instance_variable_get(:@raw_request)['authorization']).to eq(@authorization) + end + end + end + context "with POST http method" do it "should raise argument error if query is not a hash" do expect {