rack-reverse-proxy-pact 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 266ec4e7f0ec590e1cc7b632cb434c061ecd4caac4959ade57b63c483b083483
4
+ data.tar.gz: dc24cc984e0ca19a848e27a880a695214ed832a2950cf7af0313d4f642594a96
5
+ SHA512:
6
+ metadata.gz: bea8e5c559239d1fb6a7915787aa8d12dcd509e4ace2822d7c51c0f1b414a9233f388e324b903f692227c63a92337013d658f3011b550cc3d8e32cca35ac9d93
7
+ data.tar.gz: 545e1b83c39cbfef470f6389466abd46a0a930d454bbe1ae159bd9fa8ae04fa2914ecd4fd1f7ce1a74e78b4d9b1e4d50e9edf21f2670aa01c335ec68e8c30477
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,22 @@
1
+ name: Test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ ruby_version: ["2.7", "3.0", "3.1", "3.2", "3.3"]
11
+ os: ["ubuntu-latest","windows-latest","macos-latest"]
12
+ rack_version: ["2", "3"]
13
+ runs-on: ${{ matrix.os }}
14
+ env:
15
+ RACK_VERSION: ${{ matrix.rack_version }}
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: ruby/setup-ruby@v1
19
+ with:
20
+ ruby-version: ${{ matrix.ruby_version }}
21
+ - run: "bundle install"
22
+ - run: "bundle exec rake"
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /spec/examples.txt
10
+ /tmp/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
16
+ tests.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,21 @@
1
+ Style/StringLiterals:
2
+ EnforcedStyle: double_quotes
3
+
4
+ Metrics/LineLength:
5
+ Max: 100
6
+
7
+ #begin ruby 1.8 support
8
+ Style/HashSyntax:
9
+ EnforcedStyle: hash_rockets
10
+
11
+ Style/Lambda:
12
+ Enabled: false
13
+
14
+ Style/TrailingCommaInLiteral:
15
+ EnforcedStyleForMultiline: no_comma
16
+
17
+ Style/TrailingCommaInArguments:
18
+ EnforcedStyleForMultiline: no_comma
19
+
20
+ Style/EachWithObject:
21
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,19 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.5
4
+ - 2.3.1
5
+ - 2.4.1
6
+ - jruby-9.0.5.0
7
+ - rbx
8
+
9
+ before_install:
10
+ - gem install bundler
11
+
12
+ bundler_args: --without development
13
+
14
+ script:
15
+ - bundle exec rspec
16
+
17
+ matrix:
18
+ allow_failures:
19
+ - rvm: rbx
data/CHANGELOG.md ADDED
@@ -0,0 +1,41 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (UNRELEASED)
4
+
5
+ - Breaking Change: Never modify Location headers that are only paths without hosts. [John Bachir](https://github.com/jjb) [#46](https://github.com/waterlink/rack-reverse-proxy/pull/46)
6
+ - Breaking Change: Previously, the Accept-Encoding header was stripped by default, unless the
7
+ `preserve_encoding` option was set to true. Now, no headers are stripped by default, and an array
8
+ of headers that should be stripped can be specified with the `stripped_headers` option.
9
+ - Breaking Change: Previously, rack-reverse-proxy had the behavior/bug that when reverse_proxy_options
10
+ was invoked, all options that weren't set in the invokation would be set to nil. Now, those options will remain set at their default values - [Krzysztof Knapik](https://github.com/knapo) [#37](https://github.com/waterlink/rack-reverse-proxy/pull/37) and [John Bachir](https://github.com/jjb) [#47](https://github.com/waterlink/rack-reverse-proxy/pull/47)
11
+ - Breaking Change: Previously, when invoking reverse_proxy_options multiple times, only the
12
+ final invocation would have any effect. Now, the invocations will have a commulative effect.
13
+ [John Bachir](https://github.com/jjb) [#47](https://github.com/waterlink/rack-reverse-proxy/pull/47)
14
+ - Bugfix: Fix rack response body for https redirects [John Bachir](https://github.com/jjb) [#43](https://github.com/waterlink/rack-reverse-proxy/pull/43)
15
+
16
+ ## 0.12.0
17
+
18
+ - Enhancement: Set "X-Forwarded-Proto" header to the proxying scheme. [Motonobu Kuryu](https://github.com/arc279) [#32](https://github.com/waterlink/rack-reverse-proxy/pull/32)
19
+ - Bugfix: Upgrade to a version of rack-proxy with the bug fix for the unclosed network resources. [John Bachir](https://github.com/jjb) [#45](https://github.com/waterlink/rack-reverse-proxy/pull/45)
20
+
21
+ ## 0.11.0
22
+
23
+ - Breaking Change: Rename option x_forwarded_host option to x_forwarded_headers, as it controls both X-Forwarded-Port and X-Forwarded-Host - [Aurelien Derouineau](https://github.com/aderouineau) [#26](https://github.com/waterlink/rack-reverse-proxy/pull/26)
24
+ - Breaking Change: Strip Accept-Encoding header before forwarding request. [Max Gulyaev](https://github.com/maxilev) [#27](https://github.com/waterlink/rack-reverse-proxy/pull/27)
25
+
26
+ ## 0.10.0
27
+
28
+ - Feature: `options[:verify_mode]` to set SSL verification mode. - [Marv Cool](https://github.com/MrMarvin) [#24](https://github.com/waterlink/rack-reverse-proxy/pull/24) and [#25](https://github.com/waterlink/rack-reverse-proxy/pull/25)
29
+
30
+ ## 0.9.1
31
+
32
+ - Enhancement: Remove `Status` key from response headers as per Rack protocol (see [rack/lint](https://github.com/rack/rack/blob/master/lib/rack/lint.rb#L639)) - [Jan Raasch](https://github.com/janraasch) [#7](https://github.com/waterlink/rack-reverse-proxy/pull/7)
33
+
34
+ ## 0.9.0
35
+
36
+ - Bugfix: Timeout option matches the documentation - [Paul Hepworth](https://github.com/peppyheppy)
37
+ - Ruby 1.8 compatibility - [anujdas](https://github.com/anujdas)
38
+ - Bugfix: Omit port in host header for default ports (80, 443), so that it doesn't break some web servers, like "Apache Coyote" - [Peter Suschlik](https://github.com/splattael)
39
+ - Bugfix: Don't drop source request's port in response's location header - [Eric Koslow](https://github.com/ekosz)
40
+ - Bugfix: Capitalize headers correctly to prevent duplicate headers when used together with other proxies - [Eric Koslow](https://github.com/ekosz)
41
+ - Bugfix: Normalize headers from HttpStreamingResponse in order not to break other middlewares - [Jan Raasch](https://github.com/janraasch)
data/Gemfile ADDED
@@ -0,0 +1,20 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ ruby_version = RUBY_VERSION.to_f
6
+ rubocop_platform = [:ruby_20, :ruby_21, :ruby_22, :ruby_23, :ruby_24]
7
+ rubocop_platform = [:ruby_20, :ruby_21] if ruby_version < 2.0
8
+
9
+ group :test do
10
+ gem "rspec"
11
+ gem "rack-test"
12
+ gem "webmock"
13
+ gem "rubocop", :platform => rubocop_platform
14
+
15
+ gem "addressable", "< 2.4" if ruby_version < 1.9
16
+ end
17
+
18
+ group :development, :test do
19
+ gem "simplecov"
20
+ end
data/LICENSE ADDED
@@ -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.
data/README.md ADDED
@@ -0,0 +1,129 @@
1
+ # A Reverse Proxy for Rack
2
+ [![TravisCI](https://secure.travis-ci.org/waterlink/rack-reverse-proxy.svg "Build Status")](http://travis-ci.org/waterlink/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
+ ## Forked Repository Details
7
+
8
+ This repository was forked from source - https://github.com/waterlink/rack-reverse-proxy in order to apply Rack 3 compatibility, alongside Rack 2 backwards-compatibility.
9
+
10
+ Changes are applied against the branch [`rack_2_and_3_compat`](https://github.com/pact-foundation/rack-reverse-proxy/tree/feat/rack_2_and_3_compat)
11
+
12
+ The upstream PR is [here](https://github.com/waterlink/rack-reverse-proxy/pull/74).
13
+
14
+ It also includes [changes merged](https://github.com/waterlink/rack-reverse-proxy/pull/52) but not released to the original project, as requested by @bethesque [here](https://github.com/waterlink/rack-reverse-proxy/issues/67)
15
+
16
+ ## Installation
17
+ The gem is available on rubygems. Assuming you have a recent version of Rubygems you should just be able to install it via:
18
+
19
+ ```
20
+ gem install rack-reverse-proxy
21
+ ```
22
+
23
+ For your Gemfile use:
24
+
25
+ ```ruby
26
+ gem "rack-reverse-proxy", require: "rack/reverse_proxy"
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ `Rack::ReverseProxy` should ideally be the very first middleware in your
32
+ stack. In a typical use case it is being used to proxy an entirely
33
+ different website through your application, so it's unlikely that you will want
34
+ any other middleware to modify the requests or responses. The examples below
35
+ reflect this.
36
+
37
+
38
+ ### Generic Rack app example
39
+
40
+ ```ruby
41
+ require 'rack/reverse_proxy'
42
+
43
+ use Rack::ReverseProxy do
44
+ # Set :preserve_host to true globally (default is true already)
45
+ reverse_proxy_options preserve_host: true
46
+
47
+ # Forward the path /test* to http://example.com/test*
48
+ reverse_proxy '/test', 'http://example.com/'
49
+
50
+ # Forward the path /foo/* to http://example.com/bar/*
51
+ reverse_proxy /^\/foo(\/.*)$/, 'http://example.com/bar$1', username: 'name', password: 'basic_auth_secret'
52
+ end
53
+
54
+ app = proc do |env|
55
+ [ 200, {'Content-Type' => 'text/plain'}, ["b"] ]
56
+ end
57
+ run app
58
+ ```
59
+
60
+ ### Ruby on Rails app example
61
+
62
+ This example use `config.middleware.insert(0` to ensure that
63
+ `Rack::ReverseProxy` is first in the stack. It is possible that
64
+ other code in your app (usually in application.rb, development.rb, or production.rb)
65
+ will take over this position in the stack. To ensure
66
+ that this is not the case, view the stack by running `rails middleware`. You should see
67
+ `Rack::ReverseProxy` at the top. Note that
68
+ the middleware stack will likely differ slightly in each environment. All that said, it's a pretty
69
+ safe bet to put the below code into application.rb.
70
+
71
+ ```ruby
72
+ # config/application.rb
73
+ config.middleware.insert(0, Rack::ReverseProxy) do
74
+ reverse_proxy_options preserve_host: true
75
+ reverse_proxy '/wiki', 'http://wiki.example.com/'
76
+ end
77
+ ```
78
+
79
+ ### Rules
80
+
81
+ As seen in the Rack example above, `reverse_proxy` can be invoked multiple times with
82
+ different rules, which will be commulatively added.
83
+
84
+ Rules 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 `$`.
85
+
86
+ Right now if more than one rule 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.
87
+
88
+
89
+ ### Options
90
+
91
+ `reverse_proxy_options` sets global options for all reverse proxies. Available options are:
92
+
93
+ * `:preserve_host` Set to false to omit Host headers
94
+ * `:username` username for basic auth
95
+ * `:password` password for basic auth
96
+ * `:matching` is a global only option, if set to :first the first matched url will be requested (no ambigous error). Default: :all.
97
+ * `:timeout` seconds to timout the requests
98
+ * `:force_ssl` redirects to ssl version, if not already using it (requires `:replace_response_host`). Default: false.
99
+ * `:verify_mode` the `OpenSSL::SSL` verify mode passed to Net::HTTP. Default: `OpenSSL::SSL::VERIFY_PEER`.
100
+ * `:x_forwarded_headers` sets up proper `X-Forwarded-*` headers. Default: true.
101
+ * `:stripped_headers` Array of headers that should be stripped before forwarding reqeust. Default: nil.
102
+ e.g. `stripped_headers: ["Accept-Encoding", "Foo-Bar"]`
103
+
104
+ If `reverse_proxy_options` is invoked multiple times, the invocations will have a commulative effect,
105
+ only overwritting the values which they specify. Example of how this could be useful:
106
+
107
+ ```ruby
108
+ config.middleware.insert(0, Rack::ReverseProxy) do
109
+ reverse_proxy_options preserve_host: false
110
+ if Rails.env.production? or Rails.env.staging?
111
+ reverse_proxy_options force_ssl: true, replace_response_host: true
112
+ end
113
+ reverse_proxy /^\/blog(\/?.*)$/, 'http://blog.example.com/blog$1'
114
+ end
115
+ ```
116
+
117
+ ## Note on Patches/Pull Requests
118
+ * Fork the project.
119
+ * Make your feature addition or bug fix.
120
+ * Add tests for it. This is important so I don't break it in a
121
+ future version unintentionally.
122
+ * Commit, do not mess with rakefile, version, or history.
123
+ (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)
124
+ * Send me a pull request. Bonus points for topic branches.
125
+
126
+ ## Contributors
127
+
128
+ - Jon Swope, creator
129
+ - Oleksii Fedorov, maintainer
data/Rakefile ADDED
@@ -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,6 @@
1
+ require "rack_reverse_proxy"
2
+
3
+ # Re-opening Rack module only to define ReverseProxy constant
4
+ module Rack
5
+ ReverseProxy = RackReverseProxy::Middleware
6
+ end
@@ -0,0 +1,36 @@
1
+ module RackReverseProxy
2
+ module Errors
3
+ # GenericURI indicates that url is too generic
4
+ class GenericURI < RuntimeError
5
+ attr_reader :url
6
+
7
+ def intialize(url)
8
+ @url = url
9
+ end
10
+
11
+ def to_s
12
+ %(Your URL "#{@url}" is too generic. Did you mean "http://#{@url}"?)
13
+ end
14
+ end
15
+
16
+ # AmbiguousMatch indicates that path matched more than one endpoint
17
+ class AmbiguousMatch < RuntimeError
18
+ attr_reader :path, :matches
19
+
20
+ def initialize(path, matches)
21
+ @path = path
22
+ @matches = matches
23
+ end
24
+
25
+ def to_s
26
+ %(Path "#{path}" matched multiple endpoints: #{formatted_matches})
27
+ end
28
+
29
+ private
30
+
31
+ def formatted_matches
32
+ matches.map(&:to_s).join(", ")
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ require "net/http"
2
+ require "net/https"
3
+ require "rack-proxy"
4
+ require "rack_reverse_proxy/roundtrip"
5
+
6
+ module RackReverseProxy
7
+ # Rack middleware for handling reverse proxying
8
+ class Middleware
9
+ include NewRelic::Agent::Instrumentation::ControllerInstrumentation if defined? NewRelic
10
+
11
+ DEFAULT_OPTIONS = {
12
+ :preserve_host => true,
13
+ :stripped_headers => nil,
14
+ :x_forwarded_headers => true,
15
+ :matching => :all,
16
+ :replace_response_host => false
17
+ }
18
+
19
+ def initialize(app = nil, &b)
20
+ @app = app || lambda { |_| [404, rack_version_less_than_three ? [] : {}, []] }
21
+ @rules = []
22
+ @global_options = DEFAULT_OPTIONS
23
+ instance_eval(&b) if block_given?
24
+ end
25
+
26
+ def call(env)
27
+ RoundTrip.new(@app, env, @global_options, @rules).call
28
+ end
29
+
30
+ private
31
+
32
+ def rack_version_less_than_three
33
+ Rack.release.split('.').first.to_i < 3
34
+ end
35
+
36
+ def reverse_proxy_options(options)
37
+ @global_options = @global_options.merge(options)
38
+ end
39
+
40
+ def reverse_proxy(rule, url = nil, opts = {})
41
+ if rule.is_a?(String) && url.is_a?(String) && URI(url).class == URI::Generic
42
+ raise Errors::GenericURI.new, url
43
+ end
44
+ @rules << Rule.new(rule, url, opts)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,60 @@
1
+ module RackReverseProxy
2
+ # ResponseBuilder knows target response building process
3
+ class ResponseBuilder
4
+ def initialize(target_request, uri, options)
5
+ @target_request = target_request
6
+ @uri = uri
7
+ @options = options
8
+ end
9
+
10
+ def fetch
11
+ setup_response
12
+ target_response
13
+ end
14
+
15
+ private
16
+
17
+ def setup_response
18
+ set_read_timeout
19
+ handle_https
20
+ handle_verify_mode
21
+ end
22
+
23
+ def set_read_timeout
24
+ return unless read_timeout?
25
+ target_response.read_timeout = options[:timeout]
26
+ end
27
+
28
+ def read_timeout?
29
+ options[:timeout].to_i > 0
30
+ end
31
+
32
+ def handle_https
33
+ return unless https?
34
+ target_response.use_ssl = true
35
+ end
36
+
37
+ def https?
38
+ "https" == uri.scheme
39
+ end
40
+
41
+ def handle_verify_mode
42
+ return unless verify_mode?
43
+ target_response.verify_mode = options[:verify_mode]
44
+ end
45
+
46
+ def verify_mode?
47
+ options.key?(:verify_mode)
48
+ end
49
+
50
+ def target_response
51
+ @_target_response ||= Rack::HttpStreamingResponse.new(
52
+ target_request,
53
+ uri.host,
54
+ uri.port
55
+ )
56
+ end
57
+
58
+ attr_reader :target_request, :uri, :options
59
+ end
60
+ end