Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Ensure that header values are the same when recording and replaying.

- Typhoeus would have a single header value like 'text/html' when recording, but it was in an array on playback ['text/html'].
- Faraday headers are returned with lower case keys, and I was not handling this properly at all.

There are a few adapter/http library combinations that do not work properly when there are multiple values for one header:
- Faraday/Patron
- WebMock/HTTP Client
- WebMock/EM HTTP Request
- WebMock/Curb

I think this is due to a bug in those libraries.  I could change the way I pass headers to Faraday and WebMock, but that would break the other libs used with Faraday and WebMock (i.e. Faraday/Net::HTTP or WebMock/Net::HTTP) so I think it's best for now to just leave these pending.

Closes #50.
  • Loading branch information...
commit dbbc4b3461cf228113ebe172bcbef06ad235c9e6 1 parent f189e62
@myronmarston authored
View
6 CHANGELOG.md
@@ -2,6 +2,12 @@
[Full Changelog](http://github.com/myronmarston/vcr/compare/v1.7.1...master)
+* Fixed Typhoeus adapter so headers are returned in the same form during
+ playback as they would be without VCR. Bug reported by
+ [Avdi Grimm](https://github.com/avdi).
+* Fixed Faraday adapter so it treats response headers in the same way
+ Faraday itself does (i.e. with lowercase keys).
+
## 1.7.1 (March 19, 2011)
[Full Changelog](http://github.com/myronmarston/vcr/compare/v1.7.0...v1.7.1)
View
12 lib/vcr/http_stubbing_adapters/typhoeus.rb
@@ -32,7 +32,7 @@ def stub_requests(http_interactions, match_attributes)
::Typhoeus::Response.new(
:code => response.status.code,
:body => response.body,
- :headers_hash => response.headers
+ :headers_hash => normalized_response_headers(response)
)
end
)
@@ -65,6 +65,16 @@ def request_hash(request_matcher)
hash
end
+
+ def normalized_response_headers(response)
+ hash = {}
+
+ response.headers.each do |key, values|
+ hash[key] = values.size == 1 ? values.first : values
+ end if response.headers
+
+ hash
+ end
end
end
end
View
15 lib/vcr/middleware/faraday.rb
@@ -18,7 +18,7 @@ def call(env)
elsif response = VCR::HttpStubbingAdapters::Faraday.stubbed_response_for(request_matcher)
env.update(
:status => response.status.code,
- :response_headers => correctly_cased_headers(response.headers || {}),
+ :response_headers => normalized_headers(response.headers),
:body => response.body
)
@@ -64,15 +64,14 @@ def response_for(env)
)
end
- def correctly_cased_headers(headers)
- correctly_cased_hash = {}
+ def normalized_headers(headers)
+ hash = {}
- headers.each do |key, value|
- key = key.to_s.split('-').map { |segment| segment.capitalize }.join("-")
- correctly_cased_hash[key] = value
- end
+ headers.each do |key, values|
+ hash[key] = values.join(', ')
+ end if headers
- correctly_cased_hash
+ hash
end
end
end
View
3  spec/support/http_library_adapters.rb
@@ -127,7 +127,8 @@ def get_body_string(response)
end
def get_header(header_key, response)
- response.headers[header_key]
+ header = response.headers[header_key.downcase]
+ header.split(', ')
end
def make_http_request(method, url, body = nil, headers = {})
View
35 spec/support/shared_example_groups/http_library.rb
@@ -14,6 +14,41 @@
# so this gives us another alias we can use for the original method.
alias make_request make_http_request
+ 1.upto(2) do |header_count|
+ describe "making an HTTP request that responds with #{header_count} Set-Cookie header(s)" do
+ define_method :get_set_cookie_header do
+ VCR.use_cassette('header_test', :record => :once) do
+ get_header 'Set-Cookie', make_http_request(:get, "http://localhost:#{VCR::SinatraApp.port}/set-cookie-headers/#{header_count}")
+ end
+ end
+
+ define_method :should_be_pending do
+ if header_count == 2
+ [
+ 'Faraday (patron)',
+ 'HTTP Client',
+ 'EM HTTP Request',
+ 'Curb'
+ ].include?(adapter_module.http_library_name)
+ end
+ end
+
+ it 'returns the same header value when recording and replaying' do
+ pending "There appears to be a bug in the the HTTP stubbing library", :if => should_be_pending do
+ (recorded_val = get_set_cookie_header).should_not be_nil
+ replayed_val = get_set_cookie_header
+
+ # we don't care about order differences if the values are arrays
+ if recorded_val.is_a?(Array) && replayed_val.is_a?(Array)
+ replayed_val.should =~ recorded_val
+ else
+ replayed_val.should == recorded_val
+ end
+ end
+ end
+ end
+ end
+
describe 'making an HTTP request' do
let(:status) { VCR::ResponseStatus.new(200, 'OK') }
let(:interaction) { VCR::HTTPInteraction.new(request, response) }
View
10 spec/support/sinatra_app.rb
@@ -14,6 +14,16 @@ class SinatraApp < ::Sinatra::Base
"FOO!"
end
+ get '/set-cookie-headers/1' do
+ headers 'Set-Cookie' => 'foo'
+ 'header set'
+ end
+
+ get '/set-cookie-headers/2' do
+ headers 'Set-Cookie' => %w[ foo bar ]
+ 'header set'
+ end
+
def self.port
server.port
end

0 comments on commit dbbc4b3

Please sign in to comment.
Something went wrong with that request. Please try again.