From 4615ec4eaf5064262829d12a040c8de64290aad7 Mon Sep 17 00:00:00 2001 From: Joe Rafaniello Date: Fri, 15 May 2015 13:57:38 -0400 Subject: [PATCH] Dup the @names hash when the Headers hash is copied. Without this change, a connection's header and each request's header all reference the same `@names` hash object so any request that modified it via delete or other mutating methods, would affect the headers of other requests and the connection. In [travis.rb](https://github.com/travis-ci/travis.rb/blob/9b3eb05542e37b99a40ab89c0e861019664c15d7/lib/travis/client/session.rb#L206-209), it was doing: ```ruby connection.public_send(verb, url, *args) do |request| next if request.path !~ /^https?:/ or request.path.start_with? api_endpoint request.headers.delete("Authorization") end ``` This caused the headers of multiple requests (and the connection) to share the same `@names` hash object, resulting in `@names` and the Header hash to go out of sync: thing| @names | Header --- | --- | --- | --- connection | no Authorization | Has Authorization request 1 | no Authorization | no Authorization request 2 | no Authorization | Has Authorization Because Headers uses the `@names` to determine if it `includes?` a key or if there's a key to `delete`, you would have Authorization in the headers but it wouldn't be removed because `@names` didn't have it. --- lib/faraday/utils.rb | 12 ++++++++++++ test/connection_test.rb | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/lib/faraday/utils.rb b/lib/faraday/utils.rb index 1cd6526a..c3118fb3 100644 --- a/lib/faraday/utils.rb +++ b/lib/faraday/utils.rb @@ -17,6 +17,12 @@ module Faraday self.update(hash || {}) end + # on dup/clone, we need to duplicate @names hash + def initialize_copy(other) + super + @names = other.names.dup + end + # need to synchronize concurrent writes to the shared KeyMap keymap_mutex = Mutex.new @@ -101,6 +107,12 @@ module Faraday end } end + + protected + + def names + @names + end end # hash with stringified keys diff --git a/test/connection_test.rb b/test/connection_test.rb index e1647367..8ef4da9e 100644 --- a/test/connection_test.rb +++ b/test/connection_test.rb @@ -200,6 +200,20 @@ class TestConnection < Faraday::TestCase assert_equal "http://sushi.com/nigiri?a=1&b=2&c=3", url.to_s end + def test_request_header_change_does_not_modify_connection_header + connection = Faraday.new(:url => "https://asushi.com/sake.html") + connection.headers = { "Authorization"=>"token abc123" } + + request = connection.build_request(:get) + request.headers.delete("Authorization") + + assert_equal connection.headers.keys.sort, ["Authorization"] + assert connection.headers.include?("Authorization") + + assert_equal request.headers.keys.sort, [] + assert !request.headers.include?("Authorization") + end + def test_env_url_parses_url_params_into_query uri = env_url("http://sushi.com/sake.html", 'a[b]' => '1 + 2') assert_equal "a%5Bb%5D=1+%2B+2", uri.query