rack-proxy 0.6.4 → 0.7.2

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: ce99adfb07beb9e42b72e91bd39860d2ec1efb7b
4
- data.tar.gz: dfb0ede7fc70291ba58a24c7a478691f2fa5558f
2
+ SHA256:
3
+ metadata.gz: 6cbdbb6efeff29ecbbd6dbebe7b67ac4c923fa0ab898d245a310fa872e6d9581
4
+ data.tar.gz: e21085cf4be6ec258b67ed91685086a8c0c5c0a83252a92c87853c5f3b79701e
5
5
  SHA512:
6
- metadata.gz: 602c219b1b8151a7b77f1e6751d0919cc320cc13c6b0c0ce2f4c2a7c16dca345688ad3b3a4a109480660856a0ee7125ec36d892c97a22fb92a973e8b0a7bc005
7
- data.tar.gz: 897c3d1db3ab71a70ce88bb9437b4a7be25cae6db20b2601f20e227b558a4a6b02416997dad68b03a7d38d0d6948bca74d3739fabfd877c0876043ea42a34dc6
6
+ metadata.gz: 5eed533bedea80e3a485b9a61e6f5e55ab9480146eed5793c0aeb520cb348e86bdfa4a514467300b626f0b016760ce8ecb1a3318272d7cdcc5649c24131d7134
7
+ data.tar.gz: 4aea216293ead6071d44a1460b7c0f3f865e53d5332c994c441cbe956db6f57d67aa7b9b80a17bbd593676b2f651860f11f284c698200dbe4acfb0385ac00a15
data/.travis.yml CHANGED
@@ -1,4 +1,3 @@
1
- sudo: false
2
1
  cache: bundler
3
2
  language: ruby
4
3
  before_install:
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.4)
4
+ rack-proxy (0.7.2)
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
@@ -6,7 +6,7 @@ Installation
6
6
  Add the following to your `Gemfile`:
7
7
 
8
8
  ```
9
- gem 'rack-proxy', '~> 0.6.4'
9
+ gem 'rack-proxy', '~> 0.7.2'
10
10
  ```
11
11
 
12
12
  Or install:
@@ -17,7 +17,8 @@ gem install rack-proxy
17
17
 
18
18
  Use Cases
19
19
  ----
20
- Below are some examples of real world use cases for Rack-Proxy, done something interesting add the list below and send a PR.
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.
21
22
 
22
23
  * Allowing one app to act as central trust authority
23
24
  * handle accepting self-sign certificates for internal apps
@@ -25,7 +26,7 @@ Below are some examples of real world use cases for Rack-Proxy, done something i
25
26
  * avoiding CORs complications by proxying from same domain to another backend
26
27
  * subdomain based pass-through to multiple apps
27
28
  * Complex redirect rules
28
- * redirect pages with different extensions (ex: `.php`) to another app
29
+ * redirect pages with different extensions (ex: `.php`) to another app
29
30
  * useful for handling awkward redirection rules for moved pages
30
31
  * fan Parallel Requests: turning a single API request to [multiple concurrent backend requests](https://github.com/typhoeus/typhoeus#making-parallel-requests) & merging results.
31
32
  * inserting or stripping headers required or problematic for certain clients
@@ -76,7 +77,7 @@ class ForwardHost < Rack::Proxy
76
77
 
77
78
  # example of inserting an additional header
78
79
  headers["X-Foo"] = "Bar"
79
-
80
+
80
81
  # if you rewrite env, it appears that content-length isn't calculated correctly
81
82
  # resulting in only partial responses being sent to users
82
83
  # you can remove it or recalculate it here
@@ -98,14 +99,14 @@ class TrustingProxy < Rack::Proxy
98
99
  def rewrite_env(env)
99
100
  env["HTTP_HOST"] = "self-signed.badssl.com"
100
101
 
101
- # We are going to trust the self-signed SSL
102
+ # We are going to trust the self-signed SSL
102
103
  env["rack.ssl_verify_none"] = true
103
104
  env
104
105
  end
105
106
 
106
107
  def rewrite_response(triplet)
107
108
  status, headers, body = triplet
108
-
109
+
109
110
  # if you rewrite env, it appears that content-length isn't calculated correctly
110
111
  # resulting in only partial responses being sent to users
111
112
  # you can remove it or recalculate it here
@@ -130,12 +131,12 @@ Test with `require 'rack_proxy_examples/example_service_proxy'`
130
131
  ```ruby
131
132
  ###
132
133
  # This is an example of how to use Rack-Proxy in a Rails application.
133
- #
134
+ #
134
135
  # Setup:
135
- # 1. rails new test_app
136
+ # 1. rails new test_app
136
137
  # 2. cd test_app
137
138
  # 3. install Rack-Proxy in `Gemfile`
138
- # a. `gem 'rack-proxy', '~> 0.6.3'`
139
+ # a. `gem 'rack-proxy', '~> 0.7.2'`
139
140
  # 4. install gem: `bundle install`
140
141
  # 5. create `config/initializers/proxy.rb` adding this line `require 'rack_proxy_examples/example_service_proxy'`
141
142
  # 6. run: `SERVICE_URL=http://guides.rubyonrails.org rails server`
@@ -157,7 +158,7 @@ class ExampleServiceProxy < Rack::Proxy
157
158
 
158
159
  # This is the only path that needs to be set currently on Rails 5 & greater
159
160
  env['PATH_INFO'] = ENV['SERVICE_PATH'] || '/configuring.html'
160
-
161
+
161
162
  # don't send your sites cookies to target service, unless it is a trusted internal service that can parse all your cookies
162
163
  env['HTTP_COOKIE'] = ''
163
164
  super(env)
@@ -185,14 +186,14 @@ class RackPhpProxy < Rack::Proxy
185
186
  if request.path =~ %r{\.php}
186
187
  env["HTTP_HOST"] = ENV["HTTP_HOST"] ? URI(ENV["HTTP_HOST"]).host : "localhost"
187
188
  ENV["PHP_PATH"] ||= '/manual/en/tutorial.firstpage.php'
188
-
189
+
189
190
  # Rails 3 & 4
190
191
  env["REQUEST_PATH"] = ENV["PHP_PATH"] || "/php/#{request.fullpath}"
191
192
  # Rails 5 and above
192
193
  env['PATH_INFO'] = ENV["PHP_PATH"] || "/php/#{request.fullpath}"
193
194
 
194
195
  env['content-length'] = nil
195
-
196
+
196
197
  super(env)
197
198
  else
198
199
  @app.call(env)
@@ -201,7 +202,7 @@ class RackPhpProxy < Rack::Proxy
201
202
 
202
203
  def rewrite_response(triplet)
203
204
  status, headers, body = triplet
204
-
205
+
205
206
  # if you proxy depending on the backend, it appears that content-length isn't calculated correctly
206
207
  # resulting in only partial responses being sent to users
207
208
  # you can remove it or recalculate it here
@@ -232,6 +233,71 @@ This will allow to run the other requests through the application and only proxy
232
233
 
233
234
  See tests for more examples.
234
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
+
235
301
  WARNING
236
302
  ----
237
303
 
@@ -242,4 +308,4 @@ Todos
242
308
 
243
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.
244
310
  * Improve and validate requirements for Host and Path rewrite rules
245
- * Ability to inject logger and set log level
311
+ * Ability to inject logger and set log level
@@ -4,7 +4,7 @@
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
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.4"
8
+ VERSION = "0.7.2"
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)
@@ -79,7 +89,7 @@ module Rack
79
89
  full_path = source_request.fullpath
80
90
  end
81
91
 
82
- target_request = Net::HTTP.const_get(source_request.request_method.capitalize).new(full_path)
92
+ target_request = Net::HTTP.const_get(source_request.request_method.capitalize, false).new(full_path)
83
93
 
84
94
  # Setup headers
85
95
  target_request.initialize_http_header(self.class.extract_http_request_headers(source_request.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
 
@@ -1,11 +1,11 @@
1
1
  ###
2
2
  # This is an example of how to use Rack-Proxy in a Rails application.
3
- #
3
+ #
4
4
  # Setup:
5
- # 1. rails new test_app
5
+ # 1. rails new test_app
6
6
  # 2. cd test_app
7
7
  # 3. install Rack-Proxy in `Gemfile`
8
- # a. `gem 'rack-proxy', '~> 0.6.3'`
8
+ # a. `gem 'rack-proxy', '~> 0.7.2'`
9
9
  # 4. install gem: `bundle install`
10
10
  # 5. create `config/initializers/proxy.rb` adding this line `require 'rack_proxy_examples/example_service_proxy'`
11
11
  # 6. run: `SERVICE_URL=http://guides.rubyonrails.org rails server`
@@ -27,7 +27,7 @@ class ExampleServiceProxy < Rack::Proxy
27
27
 
28
28
  # This is the only path that needs to be set currently on Rails 5 & greater
29
29
  env['PATH_INFO'] = ENV['SERVICE_PATH'] || '/configuring.html'
30
-
30
+
31
31
  # don't send your sites cookies to target service, unless it is a trusted internal service that can parse all your cookies
32
32
  env['HTTP_COOKIE'] = ''
33
33
  super(env)
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
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.4
4
+ version: 0.7.2
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: 2018-03-05 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
@@ -81,9 +81,10 @@ files:
81
81
  - test/rack_proxy_test.rb
82
82
  - test/test_helper.rb
83
83
  homepage: https://github.com/ncr/rack-proxy
84
- licenses: []
84
+ licenses:
85
+ - MIT
85
86
  metadata: {}
86
- post_install_message:
87
+ post_install_message:
87
88
  rdoc_options: []
88
89
  require_paths:
89
90
  - lib
@@ -98,9 +99,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
99
  - !ruby/object:Gem::Version
99
100
  version: '0'
100
101
  requirements: []
101
- rubyforge_project: rack-proxy
102
- rubygems_version: 2.5.2.2
103
- signing_key:
102
+ rubygems_version: 3.0.3
103
+ signing_key:
104
104
  specification_version: 4
105
105
  summary: A request/response rewriting HTTP proxy. A Rack app.
106
106
  test_files: