Skip to content

Commit

Permalink
Ensure multiple values for the same header can be recorded and played…
Browse files Browse the repository at this point in the history
… back.

This already worked for most adapters, but had an issue for the HTTP client adapter.

Note that I had to change the line breaks in the webmock server response to \r\n (which matches the HTTP spec, I believe) in order to get curb and patron to parse the headers correctly.
  • Loading branch information
myronmarston committed Feb 19, 2012
1 parent 7c21556 commit 5534968
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
12 changes: 11 additions & 1 deletion lib/webmock/http_lib_adapters/httpclient_adapter.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -112,7 +112,17 @@ def build_httpclient_response(webmock_response, stream = false, &block)
def build_webmock_response(httpclient_response) def build_webmock_response(httpclient_response)
webmock_response = WebMock::Response.new webmock_response = WebMock::Response.new
webmock_response.status = [httpclient_response.status, httpclient_response.reason] webmock_response.status = [httpclient_response.status, httpclient_response.reason]
webmock_response.headers = httpclient_response.header.all
webmock_response.headers = {}.tap do |hash|
httpclient_response.header.all.each do |(key, value)|
if hash.has_key?(key)
hash[key] = Array(hash[key]) + [value]
else
hash[key] = value
end
end
end

if httpclient_response.content.respond_to?(:read) if httpclient_response.content.respond_to?(:read)
webmock_response.body = httpclient_response.content.read webmock_response.body = httpclient_response.content.read
body = HTTP::Message::Body.new body = HTTP::Message::Body.new
Expand Down
10 changes: 10 additions & 0 deletions spec/acceptance/curb/curb_spec_helper.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ def http_request(method, uri, options = {}, &block)
status, response_headers = status, response_headers =
WebMock::HttpLibAdapters::CurbAdapter.parse_header_string(curl.header_str) WebMock::HttpLibAdapters::CurbAdapter.parse_header_string(curl.header_str)


# Deal with the fact that the HTTP spec allows multi-values headers
# to either be a single entry with a comma-separated listed of
# values, or multiple separate entries
response_headers.keys.each do |k|
v = response_headers[k]
if v.is_a?(Array)
response_headers[k] = v.join(', ')
end
end

OpenStruct.new( OpenStruct.new(
:body => curl.body_str, :body => curl.body_str,
:headers => WebMock::Util::Headers.normalize_headers(response_headers), :headers => WebMock::Util::Headers.normalize_headers(response_headers),
Expand Down
21 changes: 21 additions & 0 deletions spec/acceptance/shared/complex_cross_concern_behaviors.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,21 @@
shared_context "complex cross-concern behaviors" do |*adapter_info|
it 'allows a response with multiple values for the same header to be recorded and played back exactly as-is' do
WebMock.allow_net_connect!

recorded_response = nil
WebMock.after_request { |_,r| recorded_response = r }
real_response = http_request(:get, webmock_server_url)

stub_request(:get, webmock_server_url).to_return(
:status => recorded_response.status,
:body => recorded_response.body,
:headers => recorded_response.headers
)

played_back_response = http_request(:get, webmock_server_url)

played_back_response.headers.keys.should include('Set-Cookie')
played_back_response.should == real_response
end
end

3 changes: 3 additions & 0 deletions spec/acceptance/webmock_shared.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require 'acceptance/shared/stubbing_requests' require 'acceptance/shared/stubbing_requests'
require 'acceptance/shared/allowing_and_disabling_net_connect' require 'acceptance/shared/allowing_and_disabling_net_connect'
require 'acceptance/shared/precedence_of_stubs' require 'acceptance/shared/precedence_of_stubs'
require 'acceptance/shared/complex_cross_concern_behaviors'


unless defined? SAMPLE_HEADERS unless defined? SAMPLE_HEADERS
SAMPLE_HEADERS = { "Content-Length" => "8888", "Accept" => "application/json" } SAMPLE_HEADERS = { "Content-Length" => "8888", "Accept" => "application/json" }
Expand Down Expand Up @@ -34,5 +35,7 @@
include_context "callbacks", *adapter_info include_context "callbacks", *adapter_info


include_context "enabled and disabled webmock", *adapter_info include_context "enabled and disabled webmock", *adapter_info

include_context "complex cross-concern behaviors", *adapter_info
end end
end end
12 changes: 7 additions & 5 deletions spec/support/webmock_server.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ def start
end end
server.start do |socket| server.start do |socket|
socket.puts <<-EOT.gsub(/^\s+\|/, '') socket.puts <<-EOT.gsub(/^\s+\|/, '')
|HTTP/1.1 200 OK |HTTP/1.1 200 OK\r
|Date: Fri, 31 Dec 1999 23:59:59 GMT |Date: Fri, 31 Dec 1999 23:59:59 GMT\r
|Content-Type: text/html |Content-Type: text/html\r
|Content-Length: 11 |Content-Length: 11\r
| |Set-Cookie: bar\r
|Set-Cookie: foo\r
|\r
|hello world |hello world
EOT EOT
end end
Expand Down

0 comments on commit 5534968

Please sign in to comment.