pact-provider-proxy 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 55eedb6b628b73d102ff6599b6daa8bddfcba3d8
4
- data.tar.gz: b81d06ca88af131656fd4b90b836311e10111e25
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Y2Y4Mjk3NGJjNDA0YTRhNGI3ZjgwODYxYTExOTcyMGE0Y2ZhYjYyNQ==
5
+ data.tar.gz: !binary |-
6
+ Y2E4OGQ2YzhkOTZlMjBkOTg1YThiNWUzOTU2ZmFiMzc2NjU4ZTg2MA==
5
7
  SHA512:
6
- metadata.gz: 39255f5cd6e5889421b7dc0ded99cbe811138aaa8630768932891ba88f9c05f6d9856de4cf01769a6b4a46ac55acf896d639c84b7c0697ee1ed1328374a08a78
7
- data.tar.gz: 1de33bbe1b09dc82b0e3e447ab820502eb00668ddd0e2dca6e60d3d98d009e2634cd266fca8aaa8fafc9109edfa8d1d1391267b214c9b9e553e0764f4e5d4c33
8
+ metadata.gz: !binary |-
9
+ ZWJiOWYxYjNiZmQxNmRlMTNiMmU2ZGIyZTEyZjczZGUyNWFhNDI1ZWM5Mjcw
10
+ MzMyYjlhMGQ0ZDJiOTM3MDI3MzU2NjI1MzNlNTUxMzk5ZTFjMzRhZmEwMjgy
11
+ MDg3ODRjNmRhYTdmMWJlMmU2MTMwNmIxYzAzNmY2NWMxNTZjNWQ=
12
+ data.tar.gz: !binary |-
13
+ YzI3N2M4Y2ZiODI4ODQ2OTExZWRlZjU5M2Q5YzI1ZWE4MmM0OGM2ZDU1OTJj
14
+ NzdlYmRkNTU2NmZiMDQ1MTZlNjViNDBhMDFkNWI3NjJkMGQ4NjJmZjBlZDNl
15
+ ZGUyNGU4YjA2YjAwOWFjZjhjYzhlMjAzZjk2MGU3NTNmZjJjOGM=
data/.gitignore CHANGED
@@ -17,3 +17,4 @@ test/version_tmp
17
17
  tmp
18
18
  reports
19
19
  log
20
+ spec/support/pact_helper.rb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  git log --pretty=format:' * %h - %s (%an, %ad)'
2
2
 
3
+ ### 1.2.0 (14 October 2014)
4
+
5
+ * 6a6695c - Forked and vendored rack-reverse-proxy because no one is maintaining or releasing the gem (bethesque, Tue Oct 14 11:41:37 2014 +1100)
6
+
3
7
  ### 1.1.0 (18 September 2014)
4
8
 
5
9
  * dd1117e - Updated pact version (bethesque, Thu Sep 18 16:16:12 2014 +1000)
@@ -1,7 +1,7 @@
1
1
  module Pact
2
2
  module Provider
3
3
  module Proxy
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
6
6
  end
7
7
  end
@@ -17,11 +17,14 @@ Gem::Specification.new do |spec|
17
17
  spec.files = `git ls-files`.split($/)
18
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
- spec.require_paths = ["lib"]
20
+ spec.require_paths = ["lib", "vendor/rack-reverse-proxy/lib"]
21
21
 
22
- spec.add_dependency "rack-reverse-proxy"
23
22
  spec.add_dependency "pact", ">=1.1.1", "~>1.0"
24
23
  spec.add_development_dependency "bundler", "~> 1.3"
25
24
  spec.add_development_dependency "rake"
26
25
  spec.add_development_dependency "pry"
26
+
27
+ # For rack-reverse-proxy
28
+ spec.add_dependency "rack", ">= 1.0.0"
29
+ spec.add_dependency "rack-proxy", "~> 0.5"
27
30
  end
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ echo "Updating rack-reverse-proxy from master at 'git@github.com:bethesque/rack-reverse-proxy.git'..."
5
+ git subtree pull --prefix vendor/rack-reverse-proxy git@github.com:bethesque/rack-reverse-proxy.git master --squash
6
+ echo "\033[32mDone!\033[0m"
@@ -6,7 +6,10 @@
6
6
  "description": "a request for the index",
7
7
  "provider_state": null,
8
8
  "request" : {
9
- "method" : "get", "path": "/"
9
+ "method" : "get", "path": "/",
10
+ "headers" : {
11
+ "X-Custom-Header" : "foo"
12
+ }
10
13
  },
11
14
  "response": {
12
15
  "status" : 200
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
@@ -0,0 +1,8 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Jon Swope
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # A Reverse Proxy for Rack
2
+ [![TravisCI](https://secure.travis-ci.org/pex/rack-reverse-proxy.png "Build Status")](http://travis-ci.org/pex/rack-reverse-proxy "Build Status")
3
+
4
+ This is a simple reverse proxy for Rack that pretty heavily rips off Rack Forwarder. It is not meant for production systems (although it may work), as the webserver fronting your app is generally much better at this sort of thing.
5
+
6
+ ## Installation
7
+ The gem is available on gemcutter. Assuming you have a recent version of Rubygems you should just be able to install it via:
8
+
9
+ ```
10
+ gem install rack-reverse-proxy
11
+ ```
12
+
13
+ For your Gemfile use:
14
+
15
+ ```ruby
16
+ gem "rack-reverse-proxy", require: "rack/reverse_proxy"
17
+ ```
18
+
19
+ ## Usage
20
+ Matchers can be a regex or a string. If a regex is used, you can use the subcaptures in your forwarding url by denoting them with a `$`.
21
+
22
+ Right now if more than one matcher matches any given route, it throws an exception for an ambiguous match. This will probably change later. If no match is found, the call is forwarded to your application.
23
+
24
+ Below is an example for configuring the middleware:
25
+
26
+ ```ruby
27
+ require 'rack/reverse_proxy'
28
+
29
+ use Rack::ReverseProxy do
30
+ # Set :preserve_host to true globally (default is true already)
31
+ reverse_proxy_options preserve_host: true
32
+
33
+ # Forward the path /test* to http://example.com/test*
34
+ reverse_proxy '/test', 'http://example.com/'
35
+
36
+ # Forward the path /foo/* to http://example.com/bar/*
37
+ reverse_proxy /^\/foo(\/.*)$/, 'http://example.com/bar$1', username: 'name', password: 'basic_auth_secret'
38
+ end
39
+
40
+ app = proc do |env|
41
+ [ 200, {'Content-Type' => 'text/plain'}, "b" ]
42
+ end
43
+ run app
44
+ ```
45
+
46
+ reverse_proxy_options sets global options for all reverse proxies. Available options are:
47
+ * `:preserve_host` Set to false to omit Host headers
48
+ * `:username` username for basic auth
49
+ * `:password` password for basic auth
50
+ * `:matching` is a global only option, if set to :first the first matched url will be requested (no ambigous error). Default: :all.
51
+ * `:timeout` seconds to timout the requests
52
+
53
+ ## Note on Patches/Pull Requests
54
+ * Fork the project.
55
+ * Make your feature addition or bug fix.
56
+ * Add tests for it. This is important so I don't break it in a
57
+ future version unintentionally.
58
+ * Commit, do not mess with rakefile, version, or history.
59
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
60
+ * Send me a pull request. Bonus points for topic branches.
61
+
62
+ ## Copyright
63
+
64
+ Copyright (c) 2010 Jon Swope. See LICENSE for details.
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = 'spec/**/*_spec.rb'
8
+ end
9
+
10
+ task :default => :spec
@@ -0,0 +1 @@
1
+ 0.8.1
@@ -0,0 +1,31 @@
1
+ module Rack
2
+ class GenericProxyURI < Exception
3
+ attr_reader :url
4
+
5
+ def intialize(url)
6
+ @url = url
7
+ end
8
+
9
+ def to_s
10
+ %Q(Your URL "#{@url}" is too generic. Did you mean "http://#{@url}"?)
11
+ end
12
+ end
13
+
14
+ class AmbiguousProxyMatch < Exception
15
+ attr_reader :path, :matches
16
+ def initialize(path, matches)
17
+ @path = path
18
+ @matches = matches
19
+ end
20
+
21
+ def to_s
22
+ %Q(Path "#{path}" matched multiple endpoints: #{formatted_matches})
23
+ end
24
+
25
+ private
26
+
27
+ def formatted_matches
28
+ matches.map {|matcher| matcher.to_s}.join(', ')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,133 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require "rack-proxy"
4
+ require "rack/reverse_proxy_matcher"
5
+ require "rack/exception"
6
+
7
+ module Rack
8
+ class ReverseProxy
9
+ include NewRelic::Agent::Instrumentation::ControllerInstrumentation if defined? NewRelic
10
+
11
+ def initialize(app = nil, &b)
12
+ @app = app || lambda {|env| [404, [], []] }
13
+ @matchers = []
14
+ @global_options = {:preserve_host => true, :x_forwarded_host => true, :matching => :all, :replace_response_host => false}
15
+ instance_eval &b if block_given?
16
+ end
17
+
18
+ def call(env)
19
+ rackreq = Rack::Request.new(env)
20
+ matcher = get_matcher(rackreq.fullpath, extract_http_request_headers(rackreq.env), rackreq)
21
+ return @app.call(env) if matcher.nil?
22
+
23
+ if @global_options[:newrelic_instrumentation]
24
+ action_name = "#{rackreq.path.gsub(/\/\d+/,'/:id').gsub(/^\//,'')}/#{rackreq.request_method}" # Rack::ReverseProxy/foo/bar#GET
25
+ perform_action_with_newrelic_trace(:name => action_name, :request => rackreq) do
26
+ proxy(env, rackreq, matcher)
27
+ end
28
+ else
29
+ proxy(env, rackreq, matcher)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def proxy(env, source_request, matcher)
36
+ uri = matcher.get_uri(source_request.fullpath,env)
37
+ if uri.nil?
38
+ return @app.call(env)
39
+ end
40
+ options = @global_options.dup.merge(matcher.options)
41
+
42
+ # Initialize request
43
+ target_request = Net::HTTP.const_get(source_request.request_method.capitalize).new(uri.request_uri)
44
+
45
+ # Setup headers
46
+ target_request_headers = extract_http_request_headers(source_request.env)
47
+
48
+ if options[:preserve_host]
49
+ target_request_headers['HOST'] = "#{uri.host}:#{uri.port}"
50
+ end
51
+
52
+ if options[:x_forwarded_host]
53
+ target_request_headers['X-Forwarded-Host'] = source_request.host
54
+ target_request_headers['X-Forwarded-Port'] = "#{source_request.port}"
55
+ end
56
+
57
+ target_request.initialize_http_header(target_request_headers)
58
+
59
+ # Basic auth
60
+ target_request.basic_auth options[:username], options[:password] if options[:username] and options[:password]
61
+
62
+ # Setup body
63
+ if target_request.request_body_permitted? && source_request.body
64
+ source_request.body.rewind
65
+ target_request.body_stream = source_request.body
66
+ end
67
+
68
+ target_request.content_length = source_request.content_length || 0
69
+ target_request.content_type = source_request.content_type if source_request.content_type
70
+
71
+ # Create a streaming response (the actual network communication is deferred, a.k.a. streamed)
72
+ target_response = HttpStreamingResponse.new(target_request, uri.host, uri.port)
73
+
74
+ target_response.use_ssl = "https" == uri.scheme
75
+
76
+ # Let rack set the transfer-encoding header
77
+ response_headers = target_response.headers
78
+ response_headers.delete('transfer-encoding')
79
+
80
+ # Replace the location header with the proxy domain
81
+ if response_headers['location'] && options[:replace_response_host]
82
+ response_location = URI(response_headers['location'][0])
83
+ response_location.host = source_request.host
84
+ response_headers['location'] = response_location.to_s
85
+ end
86
+
87
+ [target_response.status, response_headers, target_response.body]
88
+ end
89
+
90
+ def extract_http_request_headers(env)
91
+ headers = env.reject do |k, v|
92
+ !(/^HTTP_[A-Z_]+$/ === k) || v.nil?
93
+ end.map do |k, v|
94
+ [reconstruct_header_name(k), v]
95
+ end.inject(Utils::HeaderHash.new) do |hash, k_v|
96
+ k, v = k_v
97
+ hash[k] = v
98
+ hash
99
+ end
100
+
101
+ x_forwarded_for = (headers["X-Forwarded-For"].to_s.split(/, +/) << env["REMOTE_ADDR"]).join(", ")
102
+
103
+ headers.merge!("X-Forwarded-For" => x_forwarded_for)
104
+ end
105
+
106
+ def reconstruct_header_name(name)
107
+ name.sub(/^HTTP_/, "").split("_").collect(&:capitalize).join("-")
108
+ end
109
+
110
+ def get_matcher(path, headers, rackreq)
111
+ matches = @matchers.select do |matcher|
112
+ matcher.match?(path, headers, rackreq)
113
+ end
114
+
115
+ if matches.length < 1
116
+ nil
117
+ elsif matches.length > 1 && @global_options[:matching] != :first
118
+ raise AmbiguousProxyMatch.new(path, matches)
119
+ else
120
+ matches.first
121
+ end
122
+ end
123
+
124
+ def reverse_proxy_options(options)
125
+ @global_options=options
126
+ end
127
+
128
+ def reverse_proxy(matcher, url=nil, opts={})
129
+ raise GenericProxyURI.new(url) if matcher.is_a?(String) && url.is_a?(String) && URI(url).class == URI::Generic
130
+ @matchers << ReverseProxyMatcher.new(matcher,url,opts)
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,53 @@
1
+ module Rack
2
+ class ReverseProxyMatcher
3
+ def initialize(matcher,url=nil,options)
4
+ @default_url=url
5
+ @url=url
6
+ @options=options
7
+
8
+ if matcher.kind_of?(String)
9
+ @matcher = /^#{matcher.to_s}/
10
+ elsif matcher.respond_to?(:match)
11
+ @matcher = matcher
12
+ else
13
+ raise "Invalid Matcher for reverse_proxy"
14
+ end
15
+ end
16
+
17
+ attr_reader :matcher,:url, :default_url,:options
18
+
19
+ def match?(path, *args)
20
+ match_path(path, *args) ? true : false
21
+ end
22
+
23
+ def get_uri(path,env)
24
+ return nil if url.nil?
25
+ _url=(url.respond_to?(:call) ? url.call(env) : url.clone)
26
+ if _url =~/\$\d/
27
+ match_path(path).to_a.each_with_index { |m, i| _url.gsub!("$#{i.to_s}", m) }
28
+ URI(_url)
29
+ else
30
+ default_url.nil? ? URI.parse(_url) : URI.join(_url, path)
31
+ end
32
+ end
33
+
34
+ def to_s
35
+ %Q("#{matcher.to_s}" => "#{url}")
36
+ end
37
+
38
+ private
39
+ def match_path(path, *args)
40
+ headers = args[0]
41
+ rackreq = args[1]
42
+ arity = matcher.method(:match).arity
43
+ if arity == -1
44
+ match = matcher.match(path)
45
+ else
46
+ params = [path, (@options[:accept_headers] ? headers : nil), rackreq]
47
+ match = matcher.match(*params[0..(arity - 1)])
48
+ end
49
+ @url = match.url(path) if match && default_url.nil?
50
+ match
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'rack-reverse-proxy'
3
+ s.version = "0.8.1"
4
+ s.authors = ["Jon Swope", "Ian Ehlert", "Roman Ernst"]
5
+ s.description = 'A Rack based reverse proxy for basic needs. Useful for testing or in cases where webserver configuration is unavailable.'
6
+ s.email = ["jaswope@gmail.com", "ehlertij@gmail.com", "rernst@farbenmeer.net"]
7
+ s.files = Dir['README.md', 'LICENSE', 'lib/**/*']
8
+ s.homepage = 'http://github.com/pex/rack-reverse-proxy'
9
+ s.require_paths = ["lib"]
10
+ s.summary = 'A Simple Reverse Proxy for Rack'
11
+
12
+ s.add_development_dependency "rspec", "~> 3.1"
13
+ s.add_development_dependency "rake", "~> 10.3"
14
+ s.add_development_dependency "rack-test", "~> 0.6"
15
+ s.add_development_dependency "webmock", "~> 1.18"
16
+ s.add_development_dependency "guard-rspec"
17
+ s.add_development_dependency "guard-bundler"
18
+
19
+ s.add_dependency "rack", ">= 1.0.0"
20
+ s.add_dependency "rack-proxy", "~> 0.5"
21
+ end
@@ -0,0 +1,365 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rack::ReverseProxy do
4
+ include Rack::Test::Methods
5
+
6
+ def app
7
+ Rack::ReverseProxy.new
8
+ end
9
+
10
+ def dummy_app
11
+ lambda { |env| [200, {}, ['Dummy App']] }
12
+ end
13
+
14
+ describe "as middleware" do
15
+ def app
16
+ Rack::ReverseProxy.new(dummy_app) do
17
+ reverse_proxy '/test', 'http://example.com/', {:preserve_host => true}
18
+ reverse_proxy '/2test', lambda{ |env| 'http://example.com/'}
19
+ end
20
+ end
21
+
22
+ it "should forward requests to the calling app when the path is not matched" do
23
+ get '/'
24
+ last_response.body.should == "Dummy App"
25
+ last_response.should be_ok
26
+ end
27
+
28
+ it "should proxy requests when a pattern is matched" do
29
+ stub_request(:get, 'http://example.com/test').to_return({:body => "Proxied App"})
30
+ get '/test'
31
+ last_response.body.should == "Proxied App"
32
+ end
33
+
34
+ it "should proxy requests to a lambda url when a pattern is matched" do
35
+ stub_request(:get, 'http://example.com/2test').to_return({:body => "Proxied App2"})
36
+ get '/2test'
37
+ last_response.body.should == "Proxied App2"
38
+ end
39
+
40
+ it "should set the Host header" do
41
+ stub_request(:any, 'example.com/test/stuff')
42
+ get '/test/stuff'
43
+ a_request(:get, 'http://example.com/test/stuff').with(:headers => {"Host" => "example.com:80"}).should have_been_made
44
+ end
45
+
46
+ it "should set the X-Forwarded-Host header to the proxying host by default" do
47
+ stub_request(:any, 'example.com/test/stuff')
48
+ get '/test/stuff'
49
+ a_request(:get, 'http://example.com/test/stuff').with(:headers => {'X-Forwarded-Host' => 'example.org'}).should have_been_made
50
+ end
51
+
52
+ it "should convert the RACK HTTP headers to standard HTTP headers" do
53
+ stub_request(:any, 'example.com/test/stuff')
54
+ get '/test/stuff', nil, {'HTTP_X_CUSTOM_HEADER' => 'foo'}
55
+ a_request(:get, 'http://example.com/test/stuff').with(:headers => {'X-Custom-Header' => 'foo'}).should have_been_made
56
+ end
57
+
58
+ it "should maintain the Content-Type header" do
59
+ stub_request(:any, 'example.com/test/stuff')
60
+ get '/test/stuff', nil, {'CONTENT_TYPE' => 'foo'}
61
+ a_request(:get, 'http://example.com/test/stuff').with(:headers => {'Content-Type' => 'foo'}).should have_been_made
62
+ end
63
+
64
+ it "supports PATCH requests" do
65
+ stub_request(:any, 'example.com/test/stuff')
66
+ patch '/test/stuff'
67
+ a_request(:patch, 'http://example.com/test/stuff').should have_been_made
68
+ end
69
+
70
+ describe "with preserve host turned off" do
71
+ def app
72
+ Rack::ReverseProxy.new(dummy_app) do
73
+ reverse_proxy '/test', 'http://example.com/', {:preserve_host => false}
74
+ end
75
+ end
76
+
77
+ it "should not set the Host header" do
78
+ stub_request(:any, 'example.com/test/stuff')
79
+ get '/test/stuff'
80
+ a_request(:get, 'http://example.com/test/stuff').with(:headers => {"Host" => "example.com"}).should_not have_been_made
81
+ a_request(:get, 'http://example.com/test/stuff').should have_been_made
82
+ end
83
+ end
84
+
85
+ describe "with x_forwarded_host turned off" do
86
+ def app
87
+ Rack::ReverseProxy.new(dummy_app) do
88
+ reverse_proxy_options :x_forwarded_host => false
89
+ reverse_proxy '/test', 'http://example.com/'
90
+ end
91
+ end
92
+
93
+ it "should not set the X-Forwarded-Host header to the proxying host" do
94
+ stub_request(:any, 'example.com/test/stuff')
95
+ get '/test/stuff'
96
+ a_request(:get, 'http://example.com/test/stuff').with(:headers => {'X-Forwarded-Host' => 'example.org'}).should_not have_been_made
97
+ a_request(:get, 'http://example.com/test/stuff').should have_been_made
98
+ end
99
+ end
100
+
101
+ describe "with basic auth turned on" do
102
+ def app
103
+ Rack::ReverseProxy.new(dummy_app) do
104
+ reverse_proxy '/test', 'http://example.com/', {:username => "joe", :password => "shmoe"}
105
+ end
106
+ end
107
+
108
+ it "should make request with basic auth" do
109
+ stub_request(:get, "http://joe:shmoe@example.com/test/stuff").to_return(:body => "secured content")
110
+ get '/test/stuff'
111
+ last_response.body.should == "secured content"
112
+ end
113
+ end
114
+
115
+ describe "with preserve response host turned on" do
116
+ def app
117
+ Rack::ReverseProxy.new(dummy_app) do
118
+ reverse_proxy '/test', 'http://example.com/', {:replace_response_host => true}
119
+ end
120
+ end
121
+
122
+ it "should replace the location response header" do
123
+ stub_request(:get, "http://example.com/test/stuff").to_return(:headers => {"location" => "http://test.com/bar"})
124
+ get 'http://example.com/test/stuff'
125
+ # puts last_response.headers.inspect
126
+ last_response.headers['location'].should == "http://example.com/bar"
127
+ end
128
+ end
129
+
130
+ describe "with ambiguous routes and all matching" do
131
+ def app
132
+ Rack::ReverseProxy.new(dummy_app) do
133
+ reverse_proxy_options :matching => :all
134
+ reverse_proxy '/test', 'http://example.com/'
135
+ reverse_proxy /^\/test/, 'http://example.com/'
136
+ end
137
+ end
138
+
139
+ it "should throw an exception" do
140
+ lambda { get '/test' }.should raise_error(Rack::AmbiguousProxyMatch)
141
+ end
142
+ end
143
+
144
+ describe "with ambiguous routes and first matching" do
145
+ def app
146
+ Rack::ReverseProxy.new(dummy_app) do
147
+ reverse_proxy_options :matching => :first
148
+ reverse_proxy '/test', 'http://example1.com/'
149
+ reverse_proxy /^\/test/, 'http://example2.com/'
150
+ end
151
+ end
152
+
153
+ it "should throw an exception" do
154
+ stub_request(:get, 'http://example1.com/test').to_return({:body => "Proxied App"})
155
+ get '/test'
156
+ last_response.body.should == "Proxied App"
157
+ end
158
+ end
159
+
160
+ describe "with a route as a regular expression" do
161
+ def app
162
+ Rack::ReverseProxy.new(dummy_app) do
163
+ reverse_proxy %r|^/test(/.*)$|, 'http://example.com$1'
164
+ end
165
+ end
166
+
167
+ it "should support subcaptures" do
168
+ stub_request(:get, 'http://example.com/path').to_return({:body => "Proxied App"})
169
+ get '/test/path'
170
+ last_response.body.should == "Proxied App"
171
+ end
172
+ end
173
+
174
+ describe "with a https route" do
175
+ def app
176
+ Rack::ReverseProxy.new(dummy_app) do
177
+ reverse_proxy '/test', 'https://example.com'
178
+ end
179
+ end
180
+
181
+ it "should make a secure request" do
182
+ stub_request(:get, 'https://example.com/test/stuff').to_return({:body => "Proxied Secure App"})
183
+ get '/test/stuff'
184
+ last_response.body.should == "Proxied Secure App"
185
+ end
186
+
187
+ end
188
+
189
+ describe "with a route as a string" do
190
+ def app
191
+ Rack::ReverseProxy.new(dummy_app) do
192
+ reverse_proxy '/test', 'http://example.com'
193
+ reverse_proxy '/path', 'http://example.com/foo$0'
194
+ end
195
+ end
196
+
197
+ it "should append the full path to the uri" do
198
+ stub_request(:get, 'http://example.com/test/stuff').to_return({:body => "Proxied App"})
199
+ get '/test/stuff'
200
+ last_response.body.should == "Proxied App"
201
+ end
202
+
203
+ end
204
+
205
+ describe "with a generic url" do
206
+ def app
207
+ Rack::ReverseProxy.new(dummy_app) do
208
+ reverse_proxy '/test', 'example.com'
209
+ end
210
+ end
211
+
212
+ it "should throw an exception" do
213
+ lambda{ app }.should raise_error(Rack::GenericProxyURI)
214
+ end
215
+ end
216
+
217
+ describe "with a matching route" do
218
+ def app
219
+ Rack::ReverseProxy.new(dummy_app) do
220
+ reverse_proxy '/test', 'http://example.com/'
221
+ end
222
+ end
223
+
224
+ %w|get head delete put post|.each do |method|
225
+ describe "and using method #{method}" do
226
+ it "should forward the correct request" do
227
+ stub_request(method.to_sym, 'http://example.com/test').to_return({:body => "Proxied App for #{method}"})
228
+ eval "#{method} '/test'"
229
+ last_response.body.should == "Proxied App for #{method}"
230
+ end
231
+
232
+ if %w|put post|.include?(method)
233
+ it "should forward the request payload" do
234
+ stub_request(method.to_sym, 'http://example.com/test').to_return { |req| {:body => req.body} }
235
+ eval "#{method} '/test', {:test => 'test'}"
236
+ last_response.body.should == "test=test"
237
+ end
238
+ end
239
+ end
240
+ end
241
+ end
242
+
243
+ describe "with a matching class" do
244
+ class Matcher
245
+ def self.match(path)
246
+ if path.match(/^\/(test|users)/)
247
+ Matcher.new
248
+ end
249
+ end
250
+
251
+ def url(path)
252
+ if path.include?("user")
253
+ 'http://users-example.com' + path
254
+ else
255
+ 'http://example.com' + path
256
+ end
257
+ end
258
+ end
259
+
260
+ def app
261
+ Rack::ReverseProxy.new(dummy_app) do
262
+ reverse_proxy Matcher
263
+ end
264
+ end
265
+
266
+ it "should forward requests to the calling app when the path is not matched" do
267
+ get '/'
268
+ last_response.body.should == "Dummy App"
269
+ last_response.should be_ok
270
+ end
271
+
272
+ it "should proxy requests when a pattern is matched" do
273
+ stub_request(:get, 'http://example.com/test').to_return({:body => "Proxied App"})
274
+ stub_request(:get, 'http://users-example.com/users').to_return({:body => "User App"})
275
+ get '/test'
276
+ last_response.body.should == "Proxied App"
277
+ get '/users'
278
+ last_response.body.should == "User App"
279
+ end
280
+ end
281
+
282
+ describe "with a matching class" do
283
+ class RequestMatcher
284
+ attr_accessor :rackreq
285
+
286
+ def initialize(rackreq)
287
+ self.rackreq = rackreq
288
+ end
289
+
290
+ def self.match(path, headers, rackreq)
291
+ if path.match(/^\/(test|users)/)
292
+ RequestMatcher.new(rackreq)
293
+ end
294
+ end
295
+
296
+ def url(path)
297
+ if rackreq.params["user"] == 'omer'
298
+ 'http://users-example.com' + path
299
+ end
300
+ end
301
+ end
302
+
303
+ def app
304
+ Rack::ReverseProxy.new(dummy_app) do
305
+ reverse_proxy RequestMatcher
306
+ end
307
+ end
308
+
309
+ it "should forward requests to the calling app when the path is not matched" do
310
+ get '/'
311
+ last_response.body.should == "Dummy App"
312
+ last_response.should be_ok
313
+ end
314
+
315
+ it "should proxy requests when a pattern is matched" do
316
+ stub_request(:get, 'http://users-example.com/users?user=omer').to_return({:body => "User App"})
317
+ get '/test', user: "mark"
318
+ last_response.body.should == "Dummy App"
319
+ get '/users', user: 'omer'
320
+ last_response.body.should == "User App"
321
+ end
322
+ end
323
+
324
+
325
+ describe "with a matching class that accepts headers" do
326
+ class MatcherHeaders
327
+ def self.match(path, headers)
328
+ if path.match(/^\/test/) && headers['ACCEPT'] && headers['ACCEPT'] == 'foo.bar'
329
+ MatcherHeaders.new
330
+ end
331
+ end
332
+
333
+ def url(path)
334
+ 'http://example.com' + path
335
+ end
336
+ end
337
+
338
+ def app
339
+ Rack::ReverseProxy.new(dummy_app) do
340
+ reverse_proxy MatcherHeaders, nil, {:accept_headers => true}
341
+ end
342
+ end
343
+
344
+ it "should proxy requests when a pattern is matched and correct headers are passed" do
345
+ stub_request(:get, 'http://example.com/test').to_return({:body => "Proxied App with Headers"})
346
+ get '/test', {}, {'HTTP_ACCEPT' => 'foo.bar'}
347
+ last_response.body.should == "Proxied App with Headers"
348
+ end
349
+
350
+ it "should not proxy requests when a pattern is matched and incorrect headers are passed" do
351
+ stub_request(:get, 'http://example.com/test').to_return({:body => "Proxied App with Headers"})
352
+ get '/test', {}, {'HTTP_ACCEPT' => 'bar.foo'}
353
+ last_response.body.should_not == "Proxied App with Headers"
354
+ end
355
+ end
356
+ end
357
+
358
+ describe "as a rack app" do
359
+ it "should respond with 404 when the path is not matched" do
360
+ get '/'
361
+ last_response.should be_not_found
362
+ end
363
+ end
364
+
365
+ end
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'rack/reverse_proxy'
3
+ require 'rspec'
4
+ require 'rack/test'
5
+ require 'webmock/rspec'
6
+ # Patch HttpStreamingResponse to make rack-proxy compatible with webmocks
7
+ require 'support/http_streaming_response_patch'
8
+
9
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
10
+ $LOAD_PATH << File.join(File.dirname(__FILE__))
11
+
12
+ RSpec.configure do |config|
13
+ config.expect_with :rspec do |expectations|
14
+ # This option will default to `true` in RSpec 4.
15
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
16
+ expectations.syntax = [:should]
17
+ end
18
+ config.mock_with :rspec do |mocks|
19
+ mocks.verify_doubled_constant_names = true
20
+ mocks.verify_partial_doubles = true
21
+ mocks.syntax = [:should]
22
+ # Prevents you from mocking or stubbing a method that does not exist on
23
+ # a real object. This is generally recommended, and will default to
24
+ # `true` in RSpec 4.
25
+ mocks.verify_partial_doubles = true
26
+ end
27
+
28
+ WebMock.disable_net_connect!
29
+ end
@@ -0,0 +1,32 @@
1
+ ##
2
+ # Patch HttpStreamingResponse
3
+ # in order to support webmocks and still use rack-proxy
4
+ #
5
+ # Inspired by @ehlertij commits on sportngin/rack-proxy:
6
+ # 616574e452fa731f5427d2ff2aff6823fcf28bde
7
+ # d8c377f7485997b229ced23c33cfef87d3fb8693
8
+ # 75b446a26ceb519ddc28f38b33309e9a2799074c
9
+ #
10
+ module Rack
11
+ class HttpStreamingResponse
12
+ def each(&block)
13
+ response.read_body(&block)
14
+ ensure
15
+ session.end_request_hacked unless mocking?
16
+ end
17
+
18
+ protected
19
+
20
+ def response
21
+ if mocking?
22
+ @response ||= session.request(@request)
23
+ else
24
+ super
25
+ end
26
+ end
27
+
28
+ def mocking?
29
+ defined?(WebMock) || defined?(FakeWeb)
30
+ end
31
+ end
32
+ end
metadata CHANGED
@@ -1,91 +1,105 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pact-provider-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Beth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-18 00:00:00.000000000 Z
11
+ date: 2014-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: rack-reverse-proxy
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: pact
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
- - - ">="
17
+ - - ! '>='
32
18
  - !ruby/object:Gem::Version
33
19
  version: 1.1.1
34
- - - "~>"
20
+ - - ~>
35
21
  - !ruby/object:Gem::Version
36
22
  version: '1.0'
37
23
  type: :runtime
38
24
  prerelease: false
39
25
  version_requirements: !ruby/object:Gem::Requirement
40
26
  requirements:
41
- - - ">="
27
+ - - ! '>='
42
28
  - !ruby/object:Gem::Version
43
29
  version: 1.1.1
44
- - - "~>"
30
+ - - ~>
45
31
  - !ruby/object:Gem::Version
46
32
  version: '1.0'
47
33
  - !ruby/object:Gem::Dependency
48
34
  name: bundler
49
35
  requirement: !ruby/object:Gem::Requirement
50
36
  requirements:
51
- - - "~>"
37
+ - - ~>
52
38
  - !ruby/object:Gem::Version
53
39
  version: '1.3'
54
40
  type: :development
55
41
  prerelease: false
56
42
  version_requirements: !ruby/object:Gem::Requirement
57
43
  requirements:
58
- - - "~>"
44
+ - - ~>
59
45
  - !ruby/object:Gem::Version
60
46
  version: '1.3'
61
47
  - !ruby/object:Gem::Dependency
62
48
  name: rake
63
49
  requirement: !ruby/object:Gem::Requirement
64
50
  requirements:
65
- - - ">="
51
+ - - ! '>='
66
52
  - !ruby/object:Gem::Version
67
53
  version: '0'
68
54
  type: :development
69
55
  prerelease: false
70
56
  version_requirements: !ruby/object:Gem::Requirement
71
57
  requirements:
72
- - - ">="
58
+ - - ! '>='
73
59
  - !ruby/object:Gem::Version
74
60
  version: '0'
75
61
  - !ruby/object:Gem::Dependency
76
62
  name: pry
77
63
  requirement: !ruby/object:Gem::Requirement
78
64
  requirements:
79
- - - ">="
65
+ - - ! '>='
80
66
  - !ruby/object:Gem::Version
81
67
  version: '0'
82
68
  type: :development
83
69
  prerelease: false
84
70
  version_requirements: !ruby/object:Gem::Requirement
85
71
  requirements:
86
- - - ">="
72
+ - - ! '>='
87
73
  - !ruby/object:Gem::Version
88
74
  version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rack
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: 1.0.0
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: 1.0.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: rack-proxy
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ~>
94
+ - !ruby/object:Gem::Version
95
+ version: '0.5'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ~>
101
+ - !ruby/object:Gem::Version
102
+ version: '0.5'
89
103
  description: See summary
90
104
  email:
91
105
  - beth@bethesque.com
@@ -93,7 +107,7 @@ executables: []
93
107
  extensions: []
94
108
  extra_rdoc_files: []
95
109
  files:
96
- - ".gitignore"
110
+ - .gitignore
97
111
  - CHANGELOG.md
98
112
  - Gemfile
99
113
  - LICENSE.txt
@@ -106,12 +120,29 @@ files:
106
120
  - lib/pact/provider/proxy/tasks/proxy_verification_task.rb
107
121
  - lib/pact/provider/proxy/version.rb
108
122
  - pact-provider-proxy.gemspec
123
+ - script/update-rack-reverse-proxy.sh
109
124
  - spec/fixtures/template_pact_helper.rb
110
125
  - spec/support/custom_pact_helper.rb
111
126
  - spec/support/pact-with-no-provider-states.json
112
127
  - spec/support/pact.json
113
- - spec/support/pact_helper.rb
114
128
  - spec/tasks.rake
129
+ - vendor/rack-reverse-proxy/.document
130
+ - vendor/rack-reverse-proxy/.gitignore
131
+ - vendor/rack-reverse-proxy/.rspec
132
+ - vendor/rack-reverse-proxy/Gemfile
133
+ - vendor/rack-reverse-proxy/Gemfile.lock
134
+ - vendor/rack-reverse-proxy/Guardfile
135
+ - vendor/rack-reverse-proxy/LICENSE
136
+ - vendor/rack-reverse-proxy/README.md
137
+ - vendor/rack-reverse-proxy/Rakefile
138
+ - vendor/rack-reverse-proxy/VERSION
139
+ - vendor/rack-reverse-proxy/lib/rack/exception.rb
140
+ - vendor/rack-reverse-proxy/lib/rack/reverse_proxy.rb
141
+ - vendor/rack-reverse-proxy/lib/rack/reverse_proxy_matcher.rb
142
+ - vendor/rack-reverse-proxy/rack-reverse-proxy.gemspec
143
+ - vendor/rack-reverse-proxy/spec/rack/reverse_proxy_spec.rb
144
+ - vendor/rack-reverse-proxy/spec/spec_helper.rb
145
+ - vendor/rack-reverse-proxy/spec/support/http_streaming_response_patch.rb
115
146
  homepage: https://github.com/bethesque/pact-provider-proxy
116
147
  licenses:
117
148
  - MIT
@@ -120,19 +151,20 @@ post_install_message:
120
151
  rdoc_options: []
121
152
  require_paths:
122
153
  - lib
154
+ - vendor/rack-reverse-proxy/lib
123
155
  required_ruby_version: !ruby/object:Gem::Requirement
124
156
  requirements:
125
- - - ">="
157
+ - - ! '>='
126
158
  - !ruby/object:Gem::Version
127
159
  version: '0'
128
160
  required_rubygems_version: !ruby/object:Gem::Requirement
129
161
  requirements:
130
- - - ">="
162
+ - - ! '>='
131
163
  - !ruby/object:Gem::Version
132
164
  version: '0'
133
165
  requirements: []
134
166
  rubyforge_project:
135
- rubygems_version: 2.2.2
167
+ rubygems_version: 2.1.11
136
168
  signing_key:
137
169
  specification_version: 4
138
170
  summary: Allows verification of a pact against a running provider
@@ -141,5 +173,4 @@ test_files:
141
173
  - spec/support/custom_pact_helper.rb
142
174
  - spec/support/pact-with-no-provider-states.json
143
175
  - spec/support/pact.json
144
- - spec/support/pact_helper.rb
145
176
  - spec/tasks.rake
@@ -1,7 +0,0 @@
1
- require 'pact/provider/rspec'
2
-
3
- Pact.provider_states_for "a consumer" do
4
- provider_state "some state" do
5
- no_op
6
- end
7
- end