diff --git a/lib/pact/consumer/mock_service/rack_request_helper.rb b/lib/pact/consumer/mock_service/rack_request_helper.rb index 8d85108..0d97211 100644 --- a/lib/pact/consumer/mock_service/rack_request_helper.rb +++ b/lib/pact/consumer/mock_service/rack_request_helper.rb @@ -38,14 +38,25 @@ def request_as_hash_from env def headers_from env headers = env.reject{ |key, value| !(key.start_with?("HTTP") || key == 'CONTENT_TYPE' || key == 'CONTENT_LENGTH')} - headers.inject({}) do | hash, header | + dasherized_headers = headers.inject({}) do | hash, header | hash[standardise_header(header.first)] = header.last hash end + # This header is set in lib/pact/mock_service/server/webrick_request_monkeypatch.rb to allow use to + # restore the original header names with underscores. + restore_underscored_header_names(dasherized_headers, (env['X_PACT_UNDERSCORED_HEADER_NAMES'] || '').split(",")) end def standardise_header header - header.gsub(/^HTTP_/, '').split("_").collect{|word| word[0] + word[1..-1].downcase}.join("-") + header.gsub(/^HTTP_/, '').split(/[_-]/).collect{|word| word[0].upcase + word[1..-1].downcase}.join("-") + end + + def restore_underscored_header_names dasherized_headers, original_header_names + original_header_names.each_with_object(dasherized_headers) do | original_header_name, headers | + if headers.key?(standardise_header(original_header_name)) + headers[original_header_name] = headers.delete(standardise_header(original_header_name)) + end + end end end end diff --git a/lib/pact/mock_service/control_server/run.rb b/lib/pact/mock_service/control_server/run.rb index 2353fc2..7c3e15b 100644 --- a/lib/pact/mock_service/control_server/run.rb +++ b/lib/pact/mock_service/control_server/run.rb @@ -1,4 +1,5 @@ require 'pact/mock_service/control_server/app' +require 'pact/mock_service/server/webrick_request_monkeypatch' module Pact module MockService diff --git a/lib/pact/mock_service/run.rb b/lib/pact/mock_service/run.rb index f93d717..a9d9d8c 100644 --- a/lib/pact/mock_service/run.rb +++ b/lib/pact/mock_service/run.rb @@ -2,6 +2,7 @@ require 'pact/mock_service/app' require 'pact/consumer/mock_service/set_location' require 'pact/mock_service/run' +require 'pact/mock_service/server/webrick_request_monkeypatch' module Pact module MockService diff --git a/lib/pact/mock_service/server/webrick_request_monkeypatch.rb b/lib/pact/mock_service/server/webrick_request_monkeypatch.rb new file mode 100644 index 0000000..784407c --- /dev/null +++ b/lib/pact/mock_service/server/webrick_request_monkeypatch.rb @@ -0,0 +1,15 @@ +module WEBrick + class HTTPRequest + alias_method :pact_original_meta_vars, :meta_vars + + def meta_vars + original_underscored_headers = [] + self.each{|key, val| original_underscored_headers << key if key.include?("_") } + # This header allows us to restore the original format (eg. underscored) of the headers + # when parsing the incoming Rack env back to a response object. + vars = pact_original_meta_vars + vars["X_PACT_UNDERSCORED_HEADER_NAMES"] = original_underscored_headers.join(",") + vars + end + end +end diff --git a/spec/integration/cli_spec.rb b/spec/integration/cli_spec.rb index 2be758e..9d470c3 100644 --- a/spec/integration/cli_spec.rb +++ b/spec/integration/cli_spec.rb @@ -23,6 +23,13 @@ expect(response.status).to eq 200 end + it "respects headers with underscores" do + setup_interaction_with_underscored_header 1234 + response = invoke_request_with_underscored_header 1234 + puts response.body unless response.status == 200 + expect(response.status).to eq 200 + end + it "sets the X-Pact-Mock-Service-Location header" do response = setup_interaction 1234 expect(response.headers['X-Pact-Mock-Service-Location']).to eq 'http://0.0.0.0:1234' diff --git a/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb b/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb index 1aaa1f7..ffa1cd3 100644 --- a/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb +++ b/spec/lib/pact/consumer/mock_service/rack_request_helper_spec.rb @@ -63,10 +63,10 @@ class TestSubject } } + let(:expected_body) { body } context "with a text body" do let(:content_type) { "application/x-www-form-urlencoded" } let(:body) { 'this is the body' } - let(:expected_body) { body } it "extracts the body" do expect(subject.request_as_hash_from(rack_env)).to eq expected_request @@ -83,6 +83,19 @@ class TestSubject end end + context "with X_PACT_UNDERSCORED_HEADER_NAMES" do + before do + rack_env["HTTP_ACCESS_TOKEN"] = "123" + rack_env["X_PACT_UNDERSCORED_HEADER_NAMES"] = "access_token" + end + + let(:request) { subject.request_as_hash_from(rack_env) } + it "sets any headers with underscores back to their original format" do + expect(request[:headers]["access_token"]).to eq "123" + expect(request[:headers]["X-Something"]).to eq "1, 2" + expect(request[:headers].key?("Access-Token")).to be false + end + end end -end \ No newline at end of file +end diff --git a/spec/support/integration_spec_support.rb b/spec/support/integration_spec_support.rb index 508196e..23a0c89 100644 --- a/spec/support/integration_spec_support.rb +++ b/spec/support/integration_spec_support.rb @@ -82,6 +82,20 @@ def another_expected_interaction }.to_json end + def interaction_with_underscored_header + { + description: "another request for a greeting", + request: { + method: :get, + headers: {'access_token' => '123'}, + path: '/' + }, + response: { + status: 200 + } + }.to_json + end + def mock_service_headers { 'Content-Type' => 'application/json', @@ -108,6 +122,12 @@ def setup_another_interaction port mock_service_headers end + def setup_interaction_with_underscored_header port + Faraday.post "http://localhost:#{port}/interactions", + interaction_with_underscored_header, + mock_service_headers + end + def invoke_expected_request port Faraday.get "http://localhost:#{port}/greeting", nil, @@ -120,6 +140,12 @@ def invoke_another_expected_request port {'Foo' => 'Bar'} end + def invoke_request_with_underscored_header port + Faraday.get "http://localhost:#{port}/", + nil, + {'access_token' => '123'} + end + def verify port Faraday.get "http://localhost:#{port}/interactions/verification", nil,