diff --git a/README.md b/README.md index 6a8f92a..1b9521a 100644 --- a/README.md +++ b/README.md @@ -103,9 +103,25 @@ proxy.stub('https://example.com:443/secure/').and_return(:text => 'secrets!!1!') # params: Query string parameters hash, CGI::escape-style # headers: Headers hash # body: Request body string -# -proxy.stub('https://example.com/proc/').and_return(Proc.new { |params, headers, body| - { :text => "Hello, #{params['name'][0]}"} +# url: The actual URL which was requested +# method: The HTTP verb which was requested +proxy.stub('https://example.com/proc/').and_return(Proc.new { |params, headers, body, url, method| + { + :code => 200, + :text => "Hello, #{params['name'][0]}" + } +}) + +# You can also use Puffing Billy to intercept requests and responses. Just pass +# a Proc and use the pass_request method. You can manipulate the request +# (headers, URL, HTTP method, etc) and also the response from the upstream +# server. +proxy.stub('http://example.com/').and_return(Proc.new { |*args| + response = pass_request(*args) + response[:headers]['Content-Type'] = 'text/plain' + response[:body] = 'Hello World!' + response[:code] = 200 + response }) # Stub out a POST. Don't forget to allow a CORS request and set the method to 'post' diff --git a/lib/billy/proxy_request_stub.rb b/lib/billy/proxy_request_stub.rb index 45f4cc6..d98cd22 100644 --- a/lib/billy/proxy_request_stub.rb +++ b/lib/billy/proxy_request_stub.rb @@ -21,7 +21,7 @@ def call(method, url, params, headers, body) push_request(method, url, params, headers, body) if @response.respond_to?(:call) - res = @response.call(params, headers, body) + res = instance_exec(params, headers, body, url, method, &@response) else res = @response end @@ -71,6 +71,16 @@ def matches?(method, url) end end + def pass_request(params, headers, body, url, method) + handler = Billy.proxy.request_handler.handlers[:proxy] + response = handler.handle_request(method, url, headers, body) + { + code: response[:status], + body: response[:content], + headers: response[:headers] + } + end + private attr_writer :requests diff --git a/spec/lib/billy/proxy_request_stub_spec.rb b/spec/lib/billy/proxy_request_stub_spec.rb index 7a119ab..7a52348 100644 --- a/spec/lib/billy/proxy_request_stub_spec.rb +++ b/spec/lib/billy/proxy_request_stub_spec.rb @@ -157,18 +157,51 @@ expected_headers = { 'header1' => 'three', 'header2' => 'four' } expected_body = 'body text' - subject.and_return(proc do |params, headers, body| + # Required due to the instance_exec implementation + subject.extend(RSpec::Matchers) + + subject.and_return(proc do |params, headers, body, url, method| expect(params).to eql expected_params expect(headers).to eql expected_headers expect(body).to eql 'body text' + expect(url).to eql 'url' + expect(method).to eql 'GET' { code: 418, text: 'success' } end) - expect(subject.call('', '', expected_params, expected_headers, expected_body)).to eql [ + expect(subject.call('GET', 'url', expected_params, expected_headers, expected_body)).to eql [ 418, { 'Content-Type' => 'text/plain' }, 'success' ] end + + it 'should use a callable with pass_request' do + # Add the missing em-synchrony call which is done by + # ProxyConnection#handle_request instead. + EM.synchrony do + # Required due to the instance_exec implementation + subject.extend(RSpec::Matchers) + + subject.and_return(proc do |*args| + response = pass_request(*args) + response[:body] = 'modified' + response[:code] = 205 + response + end) + + # The test server can't be used at this scenario due to the limitations + # of the Ruby GIL. We cannot use fibers (via eventmachine) and ask + # ourself on a different thread to serve a HTTP request. This results + # in +fiber called across threads (FiberError)+ errors. Unfortunately + # we have to ask an external resource. + url = 'http://google.com' + + expect(subject.call('GET', url, {}, {}, 'original')).to eql [ + 205, + 'modified' + ] + end + end end context '#stub_requests' do