From 40be97db5201983359b7037cd88e728ed6de1b7b Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Wed, 24 Apr 2019 17:51:53 +1000 Subject: [PATCH] feat: monkeypatch webmachine to make the rack env available on the request --- lib/pact_broker/api.rb | 1 + .../api/resources/error_handler.rb | 3 +- lib/webmachine/convert_request_to_rack_env.rb | 37 ---------- lib/webmachine/rack_adapter_monkey_patch.rb | 39 +++++++++++ .../api/resources/error_handler_spec.rb | 3 +- .../convert_request_to_rack_env_spec.rb | 68 ------------------- .../rack_adapter_monkey_patch_spec.rb | 50 ++++++++++++++ 7 files changed, 92 insertions(+), 109 deletions(-) delete mode 100644 lib/webmachine/convert_request_to_rack_env.rb create mode 100644 lib/webmachine/rack_adapter_monkey_patch.rb delete mode 100644 spec/lib/webmachine/convert_request_to_rack_env_spec.rb create mode 100644 spec/lib/webmachine/rack_adapter_monkey_patch_spec.rb diff --git a/lib/pact_broker/api.rb b/lib/pact_broker/api.rb index 35c8c01d3..0d0ed624e 100644 --- a/lib/pact_broker/api.rb +++ b/lib/pact_broker/api.rb @@ -1,4 +1,5 @@ require 'webmachine/adapters/rack_mapped' +require 'webmachine/rack_adapter_monkey_patch' require 'pact_broker/api/resources' require 'pact_broker/feature_toggle' diff --git a/lib/pact_broker/api/resources/error_handler.rb b/lib/pact_broker/api/resources/error_handler.rb index 7a2da1379..a61547af6 100644 --- a/lib/pact_broker/api/resources/error_handler.rb +++ b/lib/pact_broker/api/resources/error_handler.rb @@ -1,4 +1,3 @@ -require 'webmachine/convert_request_to_rack_env' require 'pact_broker/configuration' require 'securerandom' @@ -49,7 +48,7 @@ def self.response_body_hash e, error_reference def self.report e, error_reference, request PactBroker.configuration.api_error_reporters.each do | error_notifier | begin - error_notifier.call(e, env: Webmachine::ConvertRequestToRackEnv.call(request), error_reference: error_reference) + error_notifier.call(e, env: request.env, error_reference: error_reference) rescue StandardError => e log_error(e, "Error executing api_error_reporter") end diff --git a/lib/webmachine/convert_request_to_rack_env.rb b/lib/webmachine/convert_request_to_rack_env.rb deleted file mode 100644 index 9f0a548fb..000000000 --- a/lib/webmachine/convert_request_to_rack_env.rb +++ /dev/null @@ -1,37 +0,0 @@ -module Webmachine - class ConvertRequestToRackEnv - def self.call(request) - env = { - 'REQUEST_METHOD' => request.method.upcase, - 'CONTENT_TYPE' => request.headers['Content-Type'], - 'PATH_INFO' => request.uri.path, - 'QUERY_STRING' => request.uri.query || "", - 'SERVER_NAME' => request.uri.host, - 'SERVER_PORT' => request.uri.port.to_s, - 'SCRIPT_NAME' => '', - 'rack.url_scheme' => request.uri.scheme, - 'rack.input' => request.body.to_io ? StringIO.new(request.body.to_s) : nil - }.merge(convert_headers(request)) - end - - def self.convert_headers(request) - request.headers.each_with_object({}) do | (key, value), env | - v = redact?(key) ? '[Filtered]' : value - env[convert_http_header_name_to_rack_header_name(key)] = v - end - end - - def self.redact?(http_header_name) - lower = http_header_name.downcase - lower == 'authorization' || lower.include?('token') - end - - def self.convert_http_header_name_to_rack_header_name(http_header_name) - if http_header_name.downcase == 'content-type' || http_header_name.downcase == 'content-length' - http_header_name.upcase.gsub('-', '_') - else - "HTTP_" + http_header_name.upcase.gsub('-', '_') - end - end - end -end diff --git a/lib/webmachine/rack_adapter_monkey_patch.rb b/lib/webmachine/rack_adapter_monkey_patch.rb new file mode 100644 index 000000000..62cc18ef1 --- /dev/null +++ b/lib/webmachine/rack_adapter_monkey_patch.rb @@ -0,0 +1,39 @@ +require 'webmachine/request' +require 'webmachine/adapters/rack' + +# Monkey patch to make the Rack env available on the Webmachine Request object + +module Webmachine + class RackRequest < Webmachine::Request + attr_reader :env + + def initialize(method, uri, headers, body, routing_tokens, base_uri, env) + super(method, uri, headers, body, routing_tokens, base_uri) + @env = env + end + end +end + + +unless Webmachine::Adapters::Rack.private_instance_methods.include?(:build_webmachine_request) + raise "Webmachine::Adapters::Rack no longer has the private instance method #build_webmachine_request - rack env monkey patch won't work" +end + +module Webmachine + module Adapters + class Rack < Adapter + private + + def build_webmachine_request(rack_req, headers) + Webmachine::RackRequest.new(rack_req.request_method, + rack_req.url, + headers, + RequestBody.new(rack_req), + routing_tokens(rack_req), + base_uri(rack_req), + rack_req.env + ) + end + end + end +end diff --git a/spec/lib/pact_broker/api/resources/error_handler_spec.rb b/spec/lib/pact_broker/api/resources/error_handler_spec.rb index 4522c91be..07c676e6f 100644 --- a/spec/lib/pact_broker/api/resources/error_handler_spec.rb +++ b/spec/lib/pact_broker/api/resources/error_handler_spec.rb @@ -15,14 +15,13 @@ module Resources let(:error) { StandardError.new('test error') } let(:thing) { double('thing', call: nil, another_call: nil) } let(:options) { { env: env, error_reference: "bYWfnyWPlf" } } - let(:request) { double('request' ) } + let(:request) { double('request', env: env ) } let(:response) { double('response', :body= => nil) } let(:env) { double('env') } subject { ErrorHandler.call(error, request, response) } before do - allow(Webmachine::ConvertRequestToRackEnv).to receive(:call).and_return(env) PactBroker.configuration.add_api_error_reporter do | error, options | thing.call(error, options) end diff --git a/spec/lib/webmachine/convert_request_to_rack_env_spec.rb b/spec/lib/webmachine/convert_request_to_rack_env_spec.rb deleted file mode 100644 index 584d39bc0..000000000 --- a/spec/lib/webmachine/convert_request_to_rack_env_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -require 'webmachine/convert_request_to_rack_env' -require 'webmachine/request' - -module Webmachine - describe ConvertRequestToRackEnv do - - let(:rack_env) do - { - "rack.input" => StringIO.new('foo'), - "REQUEST_METHOD" => "POST", - "SERVER_NAME" => "example.org", - "SERVER_PORT" => "80", - "QUERY_STRING" => "", - "PATH_INFO" => "/foo", - "rack.url_scheme" => "http", - "SCRIPT_NAME" => "", - "CONTENT_LENGTH" => "0", - "HTTP_HOST" => "example.org", - "CONTENT_TYPE" => "application/x-www-form-urlencoded", - "HTTP_AUTHORIZATION" => "auth", - "HTTP_TOKEN" => "foo" - } - end - - let(:expected_rack_env) do - { - "REQUEST_METHOD" => "POST", - "SERVER_NAME" => "example.org", - "SERVER_PORT" => "80", - "QUERY_STRING" => "", - "PATH_INFO" => "/foo", - "rack.url_scheme" => "http", - "SCRIPT_NAME" => "", - "CONTENT_LENGTH" => "0", - "HTTP_HOST" => "example.org", - "CONTENT_TYPE" => "application/x-www-form-urlencoded", - "HTTP_AUTHORIZATION" => "[Filtered]", - "HTTP_TOKEN" => "[Filtered]" - } - end - - let(:headers) do - Webmachine::Headers.from_cgi(rack_env) - end - - let(:rack_req) { ::Rack::Request.new(rack_env) } - let(:webmachine_request) do - Webmachine::Request.new(rack_req.request_method, - rack_req.url, - headers, - Webmachine::Adapters::Rack::RequestBody.new(rack_req), - nil, - nil - ) - end - - subject { ConvertRequestToRackEnv.call(webmachine_request) } - - describe ".call" do - it "returns a rack env hash created from the Webmachine::Request" do - actual_env = subject - actual_rack_input = actual_env.delete('rack.input') - expect(subject).to eq expected_rack_env - expect(actual_rack_input.string).to eq 'foo' - end - end - end -end diff --git a/spec/lib/webmachine/rack_adapter_monkey_patch_spec.rb b/spec/lib/webmachine/rack_adapter_monkey_patch_spec.rb new file mode 100644 index 000000000..1f69e8dc2 --- /dev/null +++ b/spec/lib/webmachine/rack_adapter_monkey_patch_spec.rb @@ -0,0 +1,50 @@ +require 'webmachine' +require 'webmachine/adapters/rack_mapped' +require 'webmachine/rack_adapter_monkey_patch' +require 'rack/test' + +module Webmachine + module Adapters + class TestResource < Webmachine::Resource + def allowed_methods + ["POST"] + end + + def process_post + response.body = request.env['FOO'] + true + end + end + + describe Rack do + include ::Rack::Test::Methods + + let(:app) do + pact_api = Webmachine::Application.new do |app| + app.routes do + add(['test'], TestResource) + end + end + + pact_api.configure do |config| + config.adapter = :RackMapped + end + + pact_api.adapter + end + + let(:rack_env) do + { + 'FOO' => 'foo' + } + end + + subject { post("/test", nil, rack_env) } + + it "passes the rack env through on the request" do + expect(subject.status).to eq 200 + expect(subject.body).to eq 'foo' + end + end + end +end