rack-proxy 0.6.3 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7cd49adb5cd0843a5467ecf9cacc3a5d7f3c903d
4
- data.tar.gz: 64cc29bbc91ee24fbe14e200b3b69b5e8b2c0e71
2
+ SHA256:
3
+ metadata.gz: a0454cf1f53d8a69931260ca29af2dd21fd4ca9a99d13cf11db158d60498ba0c
4
+ data.tar.gz: f619d7cbadaa186906a41c95960e8ce869c0f21ba3eb9c9b60282d79a810b71b
5
5
  SHA512:
6
- metadata.gz: 2986ff1e4178e92f172cdedcd38a8f7617f7d532018c1d687edecfe0bd694583a4ba409620c875b86b4d836a0e9926be078fd8aa99052c724b4fdb9f2468a774
7
- data.tar.gz: 0915046fbf017fee515398ca66f78515a4fcfa551f95a6c9134cceebf54e310040f0cfce2d325e75f8e95e0d386647a98cf61247396d321a98d56ff1f133f120
6
+ metadata.gz: fe0622a53d3c76ac11a170d7f71a78240474360614425eac3d1c4555f9d3bd712c16d1a93ecb103f8683b5d6d056d65e77858e0f106879bc342301e6c35f73bd
7
+ data.tar.gz: 476194bf06dd6f244a3070e79b8771879504919df0ef1de45bfc4f883c261f6642586c06a8b64dc2df3e213702f42140e81f012b2d3ca5226d81eb2709107733
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  gem 'rake'
4
4
 
data/Gemfile.lock CHANGED
@@ -1,17 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rack-proxy (0.6.2)
4
+ rack-proxy (0.7.1)
5
5
  rack
6
6
 
7
7
  GEM
8
- remote: http://rubygems.org/
8
+ remote: https://rubygems.org/
9
9
  specs:
10
10
  power_assert (0.2.6)
11
- rack (2.0.3)
11
+ rack (2.2.3)
12
12
  rack-test (0.5.6)
13
13
  rack (>= 1.0)
14
- rake (0.9.2.2)
14
+ rake (13.0.6)
15
15
  test-unit (3.1.5)
16
16
  power_assert
17
17
 
@@ -25,4 +25,4 @@ DEPENDENCIES
25
25
  test-unit
26
26
 
27
27
  BUNDLED WITH
28
- 1.16.0.pre.2
28
+ 1.17.2
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  A request/response rewriting HTTP proxy. A Rack app. Subclass `Rack::Proxy` and provide your `rewrite_env` and `rewrite_response` methods.
2
2
 
3
3
  Installation
4
- -------
4
+ ----
5
5
 
6
- Add the following to your Gemfile:
6
+ Add the following to your `Gemfile`:
7
7
 
8
8
  ```
9
- gem 'rack-proxy', '~> 0.6.3'
9
+ gem 'rack-proxy', '~> 0.7.1'
10
10
  ```
11
11
 
12
12
  Or install:
@@ -15,23 +15,74 @@ Or install:
15
15
  gem install rack-proxy
16
16
  ```
17
17
 
18
- Example
19
- -------
18
+ Use Cases
19
+ ----
20
+
21
+ Below are some examples of real world use cases for Rack-Proxy. If you have done something interesting, add it to the list below and send a PR.
22
+
23
+ * Allowing one app to act as central trust authority
24
+ * handle accepting self-sign certificates for internal apps
25
+ * authentication / authorization prior to proxying requests to a blindly trusting backend
26
+ * avoiding CORs complications by proxying from same domain to another backend
27
+ * subdomain based pass-through to multiple apps
28
+ * Complex redirect rules
29
+ * redirect pages with different extensions (ex: `.php`) to another app
30
+ * useful for handling awkward redirection rules for moved pages
31
+ * fan Parallel Requests: turning a single API request to [multiple concurrent backend requests](https://github.com/typhoeus/typhoeus#making-parallel-requests) & merging results.
32
+ * inserting or stripping headers required or problematic for certain clients
33
+
34
+ Options
35
+ ----
36
+
37
+ Options can be set when initializing the middleware or overriding a method.
38
+
39
+
40
+ * `:streaming` - defaults to `true`, but does not work on all Ruby versions, recommend to set to `false`
41
+ * `:ssl_verify_none` - tell `Net::HTTP` to not validate certs
42
+ * `:ssl_version` - tell `Net::HTTP` to set a specific `ssl_version`
43
+ * `:backend` - the URI parseable format of host and port of the target proxy backend. If not set it will assume the backend target is the same as the source.
44
+ * `:read_timeout` - set proxy timeout it defaults to 60 seconds
45
+
46
+ To pass in options, when you configure your middleware you can pass them in as an optional hash.
20
47
 
21
48
  ```ruby
22
- class Foo < Rack::Proxy
49
+ Rails.application.config.middleware.use ExampleServiceProxy, backend: 'http://guides.rubyonrails.org', streaming: false
50
+ ```
51
+
52
+ Examples
53
+ ----
54
+
55
+ See and run the examples below from `lib/rack_proxy_examples/`. To mount any example into an existing Rails app:
56
+
57
+ 1. create `config/initializers/proxy.rb`
58
+ 2. modify the file to require the example file
59
+ ```ruby
60
+ require 'rack_proxy_examples/forward_host'
61
+ ```
62
+
63
+ ### Forward request to Host and Insert Header
64
+
65
+ Test with `require 'rack_proxy_examples/forward_host'`
66
+
67
+ ```ruby
68
+ class ForwardHost < Rack::Proxy
23
69
 
24
70
  def rewrite_env(env)
25
71
  env["HTTP_HOST"] = "example.com"
26
-
27
72
  env
28
73
  end
29
74
 
30
75
  def rewrite_response(triplet)
31
76
  status, headers, body = triplet
32
77
 
78
+ # example of inserting an additional header
33
79
  headers["X-Foo"] = "Bar"
34
80
 
81
+ # if you rewrite env, it appears that content-length isn't calculated correctly
82
+ # resulting in only partial responses being sent to users
83
+ # you can remove it or recalculate it here
84
+ headers["content-length"] = nil
85
+
35
86
  triplet
36
87
  end
37
88
 
@@ -40,15 +91,30 @@ end
40
91
 
41
92
  ### Disable SSL session verification when proxying a server with e.g. self-signed SSL certs
42
93
 
94
+ Test with `require 'rack_proxy_examples/trusting_proxy'`
95
+
43
96
  ```ruby
44
97
  class TrustingProxy < Rack::Proxy
45
98
 
46
99
  def rewrite_env(env)
47
- env["rack.ssl_verify_none"] = true
100
+ env["HTTP_HOST"] = "self-signed.badssl.com"
48
101
 
102
+ # We are going to trust the self-signed SSL
103
+ env["rack.ssl_verify_none"] = true
49
104
  env
50
105
  end
51
106
 
107
+ def rewrite_response(triplet)
108
+ status, headers, body = triplet
109
+
110
+ # if you rewrite env, it appears that content-length isn't calculated correctly
111
+ # resulting in only partial responses being sent to users
112
+ # you can remove it or recalculate it here
113
+ headers["content-length"] = nil
114
+
115
+ triplet
116
+ end
117
+
52
118
  end
53
119
  ```
54
120
 
@@ -58,31 +124,98 @@ The same can be achieved for *all* requests going through the `Rack::Proxy` inst
58
124
  Rack::Proxy.new(ssl_verify_none: true)
59
125
  ```
60
126
 
61
- Using it as a middleware:
62
- -------------------------
127
+ ### Rails middleware example
128
+
129
+ Test with `require 'rack_proxy_examples/example_service_proxy'`
130
+
131
+ ```ruby
132
+ ###
133
+ # This is an example of how to use Rack-Proxy in a Rails application.
134
+ #
135
+ # Setup:
136
+ # 1. rails new test_app
137
+ # 2. cd test_app
138
+ # 3. install Rack-Proxy in `Gemfile`
139
+ # a. `gem 'rack-proxy', '~> 0.7.1'`
140
+ # 4. install gem: `bundle install`
141
+ # 5. create `config/initializers/proxy.rb` adding this line `require 'rack_proxy_examples/example_service_proxy'`
142
+ # 6. run: `SERVICE_URL=http://guides.rubyonrails.org rails server`
143
+ # 7. open in browser: `http://localhost:3000/example_service`
144
+ #
145
+ ###
146
+ ENV['SERVICE_URL'] ||= 'http://guides.rubyonrails.org'
147
+
148
+ class ExampleServiceProxy < Rack::Proxy
149
+ def perform_request(env)
150
+ request = Rack::Request.new(env)
151
+
152
+ # use rack proxy for anything hitting our host app at /example_service
153
+ if request.path =~ %r{^/example_service}
154
+ backend = URI(ENV['SERVICE_URL'])
155
+ # most backends required host set properly, but rack-proxy doesn't set this for you automatically
156
+ # even when a backend host is passed in via the options
157
+ env["HTTP_HOST"] = backend.host
158
+
159
+ # This is the only path that needs to be set currently on Rails 5 & greater
160
+ env['PATH_INFO'] = ENV['SERVICE_PATH'] || '/configuring.html'
161
+
162
+ # don't send your sites cookies to target service, unless it is a trusted internal service that can parse all your cookies
163
+ env['HTTP_COOKIE'] = ''
164
+ super(env)
165
+ else
166
+ @app.call(env)
167
+ end
168
+ end
169
+ end
170
+ ```
171
+
172
+ ### Using as middleware to forward only some extensions to another Application
173
+
174
+ Test with `require 'rack_proxy_examples/rack_php_proxy'`
63
175
 
64
176
  Example: Proxying only requests that end with ".php" could be done like this:
65
177
 
66
178
  ```ruby
67
- require 'rack/proxy'
179
+ ###
180
+ # Open http://localhost:3000/test.php to trigger proxy
181
+ ###
68
182
  class RackPhpProxy < Rack::Proxy
69
183
 
70
184
  def perform_request(env)
71
185
  request = Rack::Request.new(env)
72
186
  if request.path =~ %r{\.php}
73
- env["HTTP_HOST"] = "localhost"
74
- env["REQUEST_PATH"] = "/php/#{request.fullpath}"
187
+ env["HTTP_HOST"] = ENV["HTTP_HOST"] ? URI(ENV["HTTP_HOST"]).host : "localhost"
188
+ ENV["PHP_PATH"] ||= '/manual/en/tutorial.firstpage.php'
189
+
190
+ # Rails 3 & 4
191
+ env["REQUEST_PATH"] = ENV["PHP_PATH"] || "/php/#{request.fullpath}"
192
+ # Rails 5 and above
193
+ env['PATH_INFO'] = ENV["PHP_PATH"] || "/php/#{request.fullpath}"
194
+
195
+ env['content-length'] = nil
196
+
75
197
  super(env)
76
198
  else
77
199
  @app.call(env)
78
200
  end
79
201
  end
202
+
203
+ def rewrite_response(triplet)
204
+ status, headers, body = triplet
205
+
206
+ # if you proxy depending on the backend, it appears that content-length isn't calculated correctly
207
+ # resulting in only partial responses being sent to users
208
+ # you can remove it or recalculate it here
209
+ headers["content-length"] = nil
210
+
211
+ triplet
212
+ end
80
213
  end
81
214
  ```
82
215
 
83
216
  To use the middleware, please consider the following:
84
217
 
85
- 1) For Rails we could add a configuration in config/application.rb
218
+ 1) For Rails we could add a configuration in `config/application.rb`
86
219
 
87
220
  ```ruby
88
221
  config.middleware.use RackPhpProxy, {ssl_verify_none: true}
@@ -100,12 +233,79 @@ This will allow to run the other requests through the application and only proxy
100
233
 
101
234
  See tests for more examples.
102
235
 
236
+ ### SSL proxy for SpringBoot applications debugging
237
+
238
+ Whenever you need to debug communication with external services with HTTPS protocol (like OAuth based) you have to be able to access to your local web app through HTTPS protocol too. Typical way is to use nginx or Apache httpd as a reverse proxy but it might be inconvinuent for development environment. Simple proxy server is a better way in this case. The only what we need is to unpack incoming SSL queries and proxy them to a backend. We can prepare minimal set of files to create autonomous proxy server.
239
+
240
+ Create `config.ru` file:
241
+ ```ruby
242
+ #
243
+ # config.ru
244
+ #
245
+ require 'rack'
246
+ require 'rack-proxy'
247
+
248
+ class ForwardHost < Rack::Proxy
249
+ def rewrite_env(env)
250
+ env['HTTP_X_FORWARDED_HOST'] = env['SERVER_NAME']
251
+ env['HTTP_X_FORWARDED_PROTO'] = env['rack.url_scheme']
252
+ env
253
+ end
254
+ end
255
+
256
+ run ForwardHost.new(backend: 'http://localhost:8080')
257
+ ```
258
+
259
+ Create `Gemfile` file:
260
+ ```ruby
261
+ source "https://rubygems.org"
262
+
263
+ gem 'thin'
264
+ gem 'rake'
265
+ gem 'rack-proxy'
266
+ ```
267
+
268
+ Create `config.yml` file with configuration of web server `thin`:
269
+ ```yml
270
+ ---
271
+ ssl: true
272
+ ssl-key-file: keys/domain.key
273
+ ssl-cert-file: keys/domain.crt
274
+ ssl-disable-verify: false
275
+ ```
276
+
277
+ Create 'keys' directory and generate SSL key and certificates files `domain.key` and `domain.crt`
278
+
279
+ Run `bundle exec thin start` for running it with `thin`'s default port.
280
+
281
+ Or use `sudo -E thin start -C config.yml -p 443` for running with default for `https://` port.
282
+
283
+ Don't forget to enable processing of `X-Forwarded-...` headers on your application side. Just add following strings to your `resources/application.yml` file.
284
+ ```yml
285
+ ---
286
+ server:
287
+ tomcat:
288
+ remote-ip-header: x-forwarded-for
289
+ protocol-header: x-forwarded-proto
290
+ use-forward-headers: true
291
+ ```
292
+
293
+ Add some domain name like `debug.your_app.com` into your local `/etc/hosts` file like
294
+ ```
295
+ 127.0.0.1 debug.your_app.com
296
+ ```
297
+
298
+ Next start the proxy and your app. And now you can access to your Spring application through SSL connection via `https://debug.your_app.com` URI in a browser.
299
+
300
+
103
301
  WARNING
104
- -------
302
+ ----
105
303
 
106
- Doesn't work with fakeweb/webmock. Both libraries monkey-patch net/http code.
304
+ Doesn't work with `fakeweb`/`webmock`. Both libraries monkey-patch net/http code.
107
305
 
108
306
  Todos
109
- -----
307
+ ----
110
308
 
111
- - Make the docs up to date with the current use case for this code: everything except streaming which involved a rather ugly monkey patch and only worked in 1.8, but does not work now.
309
+ * Make the docs up to date with the current use case for this code: everything except streaming which involved a rather ugly monkey patch and only worked in 1.8, but does not work now.
310
+ * Improve and validate requirements for Host and Path rewrite rules
311
+ * Ability to inject logger and set log level
@@ -4,11 +4,11 @@
4
4
  #
5
5
  # [status, headers, streamable_body]
6
6
  #
7
- # See http://github.com/aniero/rack-streaming-proxy
7
+ # See http://github.com/zerowidth/rack-streaming-proxy
8
8
  # for alternative that uses additional process.
9
9
  #
10
10
  # BTW I don't like monkey patching either
11
- # but this is not real monkey patching.
11
+ # but this is not real monkey patching.
12
12
  # I just added some methods and named them very uniquely
13
13
  # to avoid eventual conflicts. You're safe. Trust me.
14
14
  #
@@ -45,7 +45,7 @@ class Net::HTTP
45
45
  #
46
46
  # res
47
47
  # end
48
-
48
+
49
49
  def begin_request_hacked(req)
50
50
  begin_transport req
51
51
  req.exec @socket, @curr_http_version, edit_path(req.path)
@@ -56,7 +56,7 @@ class Net::HTTP
56
56
  @req_hacked, @res_hacked = req, res
57
57
  @res_hacked
58
58
  end
59
-
59
+
60
60
  def end_request_hacked
61
61
  @res_hacked.end_reading_body_hacked
62
62
  end_transport @req_hacked, @res_hacked
@@ -77,12 +77,12 @@ class Net::HTTPResponse
77
77
  # @socket = nil
78
78
  # end
79
79
  # end
80
-
80
+
81
81
  def begin_reading_body_hacked(sock, reqmethodallowbody)
82
82
  @socket = sock
83
83
  @body_exist = reqmethodallowbody && self.class.body_permitted?
84
84
  end
85
-
85
+
86
86
  def end_reading_body_hacked
87
87
  self.body
88
88
  @socket = nil
data/lib/rack/proxy.rb CHANGED
@@ -5,12 +5,12 @@ module Rack
5
5
 
6
6
  # Subclass and bring your own #rewrite_request and #rewrite_response
7
7
  class Proxy
8
- VERSION = "0.6.3"
8
+ VERSION = "0.7.1"
9
9
 
10
10
  class << self
11
11
  def extract_http_request_headers(env)
12
12
  headers = env.reject do |k, v|
13
- !(/^HTTP_[A-Z0-9_]+$/ === k) || v.nil?
13
+ !(/^HTTP_[A-Z0-9_\.]+$/ === k) || v.nil?
14
14
  end.map do |k, v|
15
15
  [reconstruct_header_name(k), v]
16
16
  end.inject(Utils::HeaderHash.new) do |hash, k_v|
@@ -26,7 +26,7 @@ module Rack
26
26
 
27
27
  def normalize_headers(headers)
28
28
  mapped = headers.map do |k, v|
29
- [k, if v.is_a? Array then v.join("\n") else v end]
29
+ [titleize(k), if v.is_a? Array then v.join("\n") else v end]
30
30
  end
31
31
  Utils::HeaderHash.new Hash[mapped]
32
32
  end
@@ -34,7 +34,11 @@ module Rack
34
34
  protected
35
35
 
36
36
  def reconstruct_header_name(name)
37
- name.sub(/^HTTP_/, "").gsub("_", "-")
37
+ titleize(name.sub(/^HTTP_/, "").gsub("_", "-"))
38
+ end
39
+
40
+ def titleize(str)
41
+ str.split("-").map(&:capitalize).join("-")
38
42
  end
39
43
  end
40
44
 
@@ -46,11 +50,17 @@ module Rack
46
50
  else
47
51
  @app = app
48
52
  end
53
+
49
54
  @streaming = opts.fetch(:streaming, true)
50
55
  @ssl_verify_none = opts.fetch(:ssl_verify_none, false)
51
- @backend = URI(opts[:backend]) if opts[:backend]
56
+ @backend = opts[:backend] ? URI(opts[:backend]) : nil
52
57
  @read_timeout = opts.fetch(:read_timeout, 60)
53
- @ssl_version = opts[:ssl_version] if opts[:ssl_version]
58
+ @ssl_version = opts[:ssl_version]
59
+
60
+ @username = opts[:username]
61
+ @password = opts[:password]
62
+
63
+ @opts = opts
54
64
  end
55
65
 
56
66
  def call(env)
@@ -92,6 +102,9 @@ module Rack
92
102
  target_request.body_stream.rewind
93
103
  end
94
104
 
105
+ # Use basic auth if we have to
106
+ target_request.basic_auth(@username, @password) if @username && @password
107
+
95
108
  backend = env.delete('rack.backend') || @backend || source_request
96
109
  use_ssl = backend.scheme == "https"
97
110
  ssl_verify_none = (env.delete('rack.ssl_verify_none') || @ssl_verify_none) == true
@@ -117,7 +130,7 @@ module Rack
117
130
  end
118
131
  end
119
132
 
120
- headers = (target_response.respond_to?(:headers) && target_response.headers) || self.class.normalize_headers(target_response.to_hash)
133
+ headers = self.class.normalize_headers(target_response.respond_to?(:headers) ? target_response.headers : target_response.to_hash)
121
134
  body = target_response.body || [""]
122
135
  body = [body] unless body.respond_to?(:each)
123
136
 
@@ -0,0 +1,40 @@
1
+ ###
2
+ # This is an example of how to use Rack-Proxy in a Rails application.
3
+ #
4
+ # Setup:
5
+ # 1. rails new test_app
6
+ # 2. cd test_app
7
+ # 3. install Rack-Proxy in `Gemfile`
8
+ # a. `gem 'rack-proxy', '~> 0.7.1'`
9
+ # 4. install gem: `bundle install`
10
+ # 5. create `config/initializers/proxy.rb` adding this line `require 'rack_proxy_examples/example_service_proxy'`
11
+ # 6. run: `SERVICE_URL=http://guides.rubyonrails.org rails server`
12
+ # 7. open in browser: `http://localhost:3000/example_service`
13
+ #
14
+ ###
15
+ ENV['SERVICE_URL'] ||= 'http://guides.rubyonrails.org'
16
+
17
+ class ExampleServiceProxy < Rack::Proxy
18
+ def perform_request(env)
19
+ request = Rack::Request.new(env)
20
+
21
+ # use rack proxy for anything hitting our host app at /example_service
22
+ if request.path =~ %r{^/example_service}
23
+ backend = URI(ENV['SERVICE_URL'])
24
+ # most backends required host set properly, but rack-proxy doesn't set this for you automatically
25
+ # even when a backend host is passed in via the options
26
+ env["HTTP_HOST"] = backend.host
27
+
28
+ # This is the only path that needs to be set currently on Rails 5 & greater
29
+ env['PATH_INFO'] = ENV['SERVICE_PATH'] || '/configuring.html'
30
+
31
+ # don't send your sites cookies to target service, unless it is a trusted internal service that can parse all your cookies
32
+ env['HTTP_COOKIE'] = ''
33
+ super(env)
34
+ else
35
+ @app.call(env)
36
+ end
37
+ end
38
+ end
39
+
40
+ Rails.application.config.middleware.use ExampleServiceProxy, backend: ENV['SERVICE_URL'], streaming: false
@@ -0,0 +1,24 @@
1
+ class ForwardHost < Rack::Proxy
2
+
3
+ def rewrite_env(env)
4
+ env["HTTP_HOST"] = "example.com"
5
+ env
6
+ end
7
+
8
+ def rewrite_response(triplet)
9
+ status, headers, body = triplet
10
+
11
+ # example of inserting an additional header
12
+ headers["X-Foo"] = "Bar"
13
+
14
+ # if you rewrite env, it appears that content-length isn't calculated correctly
15
+ # resulting in only partial responses being sent to users
16
+ # you can remove it or recalculate it here
17
+ headers["content-length"] = nil
18
+
19
+ triplet
20
+ end
21
+
22
+ end
23
+
24
+ Rails.application.config.middleware.use ForwardHost, backend: 'http://example.com', streaming: false
@@ -0,0 +1,37 @@
1
+ ###
2
+ # Open http://localhost:3000/test.php to trigger proxy
3
+ ###
4
+ class RackPhpProxy < Rack::Proxy
5
+
6
+ def perform_request(env)
7
+ request = Rack::Request.new(env)
8
+ if request.path =~ %r{\.php}
9
+ env["HTTP_HOST"] = ENV["HTTP_HOST"] ? URI(ENV["HTTP_HOST"]).host : "localhost"
10
+ ENV["PHP_PATH"] ||= '/manual/en/tutorial.firstpage.php'
11
+
12
+ # Rails 3 & 4
13
+ env["REQUEST_PATH"] = ENV["PHP_PATH"] || "/php/#{request.fullpath}"
14
+ # Rails 5 and above
15
+ env['PATH_INFO'] = ENV["PHP_PATH"] || "/php/#{request.fullpath}"
16
+
17
+ env['content-length'] = nil
18
+
19
+ super(env)
20
+ else
21
+ @app.call(env)
22
+ end
23
+ end
24
+
25
+ def rewrite_response(triplet)
26
+ status, headers, body = triplet
27
+
28
+ # if you proxy depending on the backend, it appears that content-length isn't calculated correctly
29
+ # resulting in only partial responses being sent to users
30
+ # you can remove it or recalculate it here
31
+ headers["content-length"] = nil
32
+
33
+ triplet
34
+ end
35
+ end
36
+
37
+ Rails.application.config.middleware.use RackPhpProxy, backend: ENV["HTTP_HOST"]='http://php.net', streaming: false
@@ -0,0 +1,24 @@
1
+ class TrustingProxy < Rack::Proxy
2
+
3
+ def rewrite_env(env)
4
+ env["HTTP_HOST"] = "self-signed.badssl.com"
5
+
6
+ # We are going to trust the self-signed SSL
7
+ env["rack.ssl_verify_none"] = true
8
+ env
9
+ end
10
+
11
+ def rewrite_response(triplet)
12
+ status, headers, body = triplet
13
+
14
+ # if you rewrite env, it appears that content-length isn't calculated correctly
15
+ # resulting in only partial responses being sent to users
16
+ # you can remove it or recalculate it here
17
+ headers["content-length"] = nil
18
+
19
+ triplet
20
+ end
21
+
22
+ end
23
+
24
+ Rails.application.config.middleware.use TrustingProxy, backend: 'https://self-signed.badssl.com', streaming: false
data/rack-proxy.gemspec CHANGED
@@ -6,14 +6,13 @@ Gem::Specification.new do |s|
6
6
  s.name = "rack-proxy"
7
7
  s.version = Rack::Proxy::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
+ s.license = 'MIT'
9
10
  s.authors = ["Jacek Becela"]
10
11
  s.email = ["jacek.becela@gmail.com"]
11
- s.homepage = "http://rubygems.org/gems/rack-proxy"
12
+ s.homepage = "https://github.com/ncr/rack-proxy"
12
13
  s.summary = %q{A request/response rewriting HTTP proxy. A Rack app.}
13
14
  s.description = %q{A Rack app that provides request/response rewriting proxy capabilities with streaming.}
14
15
 
15
- s.rubyforge_project = "rack-proxy"
16
-
17
16
  s.files = `git ls-files`.split("\n")
18
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
@@ -4,23 +4,24 @@ require "rack/http_streaming_response"
4
4
  class HttpStreamingResponseTest < Test::Unit::TestCase
5
5
 
6
6
  def setup
7
- host, req = "www.trix.pl", Net::HTTP::Get.new("/")
8
- @response = Rack::HttpStreamingResponse.new(req, host)
7
+ host, req = "mockapi.io", Net::HTTP::Get.new("/")
8
+ @response = Rack::HttpStreamingResponse.new(req, host, 443)
9
+ @response.use_ssl = true
9
10
  end
10
11
 
11
12
  def test_streaming
12
13
  # Response status
13
- assert @response.code == 200
14
- assert @response.status == 200
14
+ assert_equal 200, @response.status
15
+ assert_equal 200, @response.status
15
16
 
16
17
  # Headers
17
18
  headers = @response.headers
18
19
 
19
- assert headers.size > 0
20
+ assert headers.size.positive?
20
21
 
21
- assert headers["content-type"] == ["text/html;charset=utf-8"]
22
- assert headers["CoNtEnT-TyPe"] == headers["content-type"]
23
- assert headers["content-length"].first.to_i > 0
22
+ assert_match %r{text/html; ?charset=utf-8}, headers["content-type"].first.downcase
23
+ assert_equal headers["content-type"], headers["CoNtEnT-TyPe"]
24
+ assert headers["content-length"].first.to_i.positive?
24
25
 
25
26
  # Body
26
27
  chunks = []
@@ -28,7 +29,7 @@ class HttpStreamingResponseTest < Test::Unit::TestCase
28
29
  chunks << chunk
29
30
  end
30
31
 
31
- assert chunks.size > 0
32
+ assert chunks.size.positive?
32
33
  chunks.each do |chunk|
33
34
  assert chunk.is_a?(String)
34
35
  end
@@ -6,7 +6,7 @@ class RackProxyTest < Test::Unit::TestCase
6
6
  attr_accessor :host
7
7
 
8
8
  def rewrite_env(env)
9
- env["HTTP_HOST"] = self.host || 'www.trix.pl'
9
+ env["HTTP_HOST"] = self.host || 'example.com'
10
10
  env
11
11
  end
12
12
  end
@@ -18,14 +18,15 @@ class RackProxyTest < Test::Unit::TestCase
18
18
  def test_http_streaming
19
19
  get "/"
20
20
  assert last_response.ok?
21
- assert_match(/Jacek Becela/, last_response.body)
21
+
22
+ assert_match(/Example Domain/, last_response.body)
22
23
  end
23
24
 
24
25
  def test_http_full_request
25
26
  app(:streaming => false)
26
27
  get "/"
27
28
  assert last_response.ok?
28
- assert_match(/Jacek Becela/, last_response.body)
29
+ assert_match(/Example Domain/, last_response.body)
29
30
  end
30
31
 
31
32
  def test_http_full_request_headers
@@ -77,10 +78,10 @@ class RackProxyTest < Test::Unit::TestCase
77
78
  proxy_class = Rack::Proxy
78
79
 
79
80
  header = proxy_class.send(:reconstruct_header_name, "HTTP_ABC")
80
- assert header == "ABC"
81
+ assert header == "Abc"
81
82
 
82
83
  header = proxy_class.send(:reconstruct_header_name, "HTTP_ABC_D")
83
- assert header == "ABC-D"
84
+ assert header == "Abc-D"
84
85
  end
85
86
 
86
87
  def test_extract_http_request_headers
@@ -89,12 +90,14 @@ class RackProxyTest < Test::Unit::TestCase
89
90
  'NOT-HTTP-HEADER' => 'test-value',
90
91
  'HTTP_ACCEPT' => 'text/html',
91
92
  'HTTP_CONNECTION' => nil,
92
- 'HTTP_CONTENT_MD5' => 'deadbeef'
93
+ 'HTTP_CONTENT_MD5' => 'deadbeef',
94
+ 'HTTP_HEADER.WITH.PERIODS' => 'stillmooing'
93
95
  }
94
96
 
95
97
  headers = proxy_class.extract_http_request_headers(env)
96
98
  assert headers.key?('ACCEPT')
97
99
  assert headers.key?('CONTENT-MD5')
100
+ assert headers.key?('HEADER.WITH.PERIODS')
98
101
  assert !headers.key?('CONNECTION')
99
102
  assert !headers.key?('NOT-HTTP-HEADER')
100
103
  end
@@ -117,7 +120,7 @@ class RackProxyTest < Test::Unit::TestCase
117
120
  end
118
121
 
119
122
  def test_response_header_included_Hop_by_hop
120
- app({:streaming => true}).host = 'auth.goeasyship.com'
123
+ app({:streaming => true}).host = 'mockapi.io'
121
124
  get 'https://example.com/oauth2/token/info?access_token=123'
122
125
  assert !last_response.headers.key?('transfer-encoding')
123
126
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacek Becela
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-08 00:00:00.000000000 Z
11
+ date: 2022-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -71,15 +71,20 @@ files:
71
71
  - lib/rack-proxy.rb
72
72
  - lib/rack/http_streaming_response.rb
73
73
  - lib/rack/proxy.rb
74
+ - lib/rack_proxy_examples/example_service_proxy.rb
75
+ - lib/rack_proxy_examples/forward_host.rb
76
+ - lib/rack_proxy_examples/rack_php_proxy.rb
77
+ - lib/rack_proxy_examples/trusting_proxy.rb
74
78
  - rack-proxy.gemspec
75
79
  - test/http_streaming_response_test.rb
76
80
  - test/net_http_hacked_test.rb
77
81
  - test/rack_proxy_test.rb
78
82
  - test/test_helper.rb
79
- homepage: http://rubygems.org/gems/rack-proxy
80
- licenses: []
83
+ homepage: https://github.com/ncr/rack-proxy
84
+ licenses:
85
+ - MIT
81
86
  metadata: {}
82
- post_install_message:
87
+ post_install_message:
83
88
  rdoc_options: []
84
89
  require_paths:
85
90
  - lib
@@ -94,9 +99,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
99
  - !ruby/object:Gem::Version
95
100
  version: '0'
96
101
  requirements: []
97
- rubyforge_project: rack-proxy
98
- rubygems_version: 2.5.1
99
- signing_key:
102
+ rubygems_version: 3.0.3
103
+ signing_key:
100
104
  specification_version: 4
101
105
  summary: A request/response rewriting HTTP proxy. A Rack app.
102
106
  test_files: