rack-proxy 0.8.0 → 0.8.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9520dd879490c3e4e00d0617a74994fd178488878cf149f44acc4795975609e
4
- data.tar.gz: 99c9ea6a98cbae6713c03f4ac4a6b87cf682a9189c073f29ecd5845d3ddc5c7e
3
+ metadata.gz: 40c24e4b559fc7669c3b675184af8d7f0b9ba693d3a7b41e6433274c16429adc
4
+ data.tar.gz: 6f8790c5c391e102275c11225a869e2572d109f2e52e4783cdc5cbbb50733579
5
5
  SHA512:
6
- metadata.gz: f5b53e01fef046f99405006fcb5b60f053ede10fc23bb231ad27deebbe52593d1ad1fcd1ba77471dcb76405c65a9d7a3a685ed13caea6bdb1dbf927ad19ffffc
7
- data.tar.gz: 940b3f2ba7a1248475799497e757a9a9be8875e933ef47b0fdc583181d0368804c56d0bd5b356860c169e4bdd9e68f2cfd6b7c6f273b9d542fd5bdd93b6e7f46
6
+ metadata.gz: 2885f787b2f08c712c99b938218749d7f5d35348588290414f058c446104e10ba80b7f0b439ea60c3fc4daea1a0b0f991c92e853a3a9de4ef238d5f864d85d20
7
+ data.tar.gz: 3f70b5ab5eee94517d10e82f72f517a7e4cd3fec346ba78142ed6d93bd34bb7d175f6e857c037c7b0beffd710889651f15d107920e38da7208bdc132f246f712
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rack-proxy (0.8.0)
4
+ rack-proxy (0.8.2)
5
5
  rack
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -43,6 +43,7 @@ Options can be set when initializing the middleware or overriding a method.
43
43
  * `:ssl_version` - tell `Net::HTTP` to set a specific `ssl_version`
44
44
  * `: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.
45
45
  * `:read_timeout` - set proxy timeout it defaults to 60 seconds
46
+ * `:logger` - any object responding to `#<<` (e.g. `$stdout`, a `StringIO`, or a Ruby `Logger`). Wired through to `Net::HTTP#set_debug_output` so the full HTTP wire-level conversation is written to the sink. Useful for debugging.
46
47
 
47
48
  To pass in options, when you configure your middleware you can pass them in as an optional hash.
48
49
 
@@ -10,7 +10,7 @@ module Rack
10
10
  304 => true
11
11
  }.freeze
12
12
 
13
- attr_accessor :use_ssl, :verify_mode, :read_timeout, :ssl_version, :cert, :key
13
+ attr_accessor :use_ssl, :verify_mode, :read_timeout, :ssl_version, :cert, :key, :logger
14
14
 
15
15
  def initialize(request, host, port = nil)
16
16
  @request, @host, @port = request, host, port
@@ -61,6 +61,7 @@ module Rack
61
61
  http.ssl_version = ssl_version if ssl_version
62
62
  http.cert = cert if cert
63
63
  http.key = key if key
64
+ http.set_debug_output(logger) if logger
64
65
  http.start
65
66
  end
66
67
  end
data/lib/rack/proxy.rb CHANGED
@@ -5,7 +5,7 @@ module Rack
5
5
 
6
6
  # Subclass and bring your own #rewrite_request and #rewrite_response
7
7
  class Proxy
8
- VERSION = "0.8.0".freeze
8
+ VERSION = "0.8.2".freeze
9
9
 
10
10
  HOP_BY_HOP_HEADERS = {
11
11
  'connection' => true,
@@ -39,7 +39,9 @@ module Rack
39
39
  end
40
40
 
41
41
  def build_header_hash(pairs)
42
- if Rack.const_defined?(:Headers)
42
+ # Pass inherit: false so we only check Rack's own constants — otherwise
43
+ # a top-level ::Headers defined by the host app would falsely match.
44
+ if Rack.const_defined?(:Headers, false)
43
45
  # Rack::Headers is only available from Rack 3 onward
44
46
  Headers.new.tap { |headers| pairs.each { |k, v| headers[k] = v } }
45
47
  else
@@ -83,6 +85,10 @@ module Rack
83
85
  @username = opts[:username]
84
86
  @password = opts[:password]
85
87
 
88
+ # Optional logger for Net::HTTP debug output. Accepts anything with a #<< method
89
+ # (e.g. $stdout, a StringIO, or a Ruby Logger instance).
90
+ @logger = opts[:logger]
91
+
86
92
  @opts = opts
87
93
  end
88
94
 
@@ -143,6 +149,7 @@ module Rack
143
149
  target_response.verify_mode = (@verify_mode || OpenSSL::SSL::VERIFY_PEER) if use_ssl
144
150
  target_response.cert = @cert if @cert
145
151
  target_response.key = @key if @key
152
+ target_response.logger = @logger if @logger
146
153
  else
147
154
  http = Net::HTTP.new(backend.host, backend.port)
148
155
  http.use_ssl = use_ssl if use_ssl
@@ -151,6 +158,7 @@ module Rack
151
158
  http.verify_mode = @verify_mode || OpenSSL::SSL::VERIFY_PEER if use_ssl
152
159
  http.cert = @cert if @cert
153
160
  http.key = @key if @key
161
+ http.set_debug_output(@logger) if @logger
154
162
 
155
163
  target_response = http.start do
156
164
  http.request(target_request)
@@ -226,6 +226,57 @@ class RackProxyTest < Test::Unit::TestCase
226
226
  assert last_response.ok?
227
227
  end
228
228
 
229
+ # Issue #80: a :logger option should pipe Net::HTTP debug output to the
230
+ # given sink (anything responding to #<<). We use a StringIO to capture it.
231
+ def test_logger_captures_request_in_non_streaming
232
+ sink = StringIO.new
233
+ with_webrick_proxy(streaming: false, logger: sink) do |port, proxy|
234
+ proxy.host = "127.0.0.1:#{port}"
235
+ get '/empty'
236
+ assert last_response.ok?
237
+ end
238
+ assert_match(/GET \/empty/, sink.string,
239
+ "expected debug output to include request line, got: #{sink.string.inspect}")
240
+ end
241
+
242
+ def test_logger_captures_request_in_streaming
243
+ sink = StringIO.new
244
+ with_webrick_proxy(streaming: true, logger: sink) do |port, proxy|
245
+ proxy.host = "127.0.0.1:#{port}"
246
+ get '/empty'
247
+ assert last_response.ok?
248
+ end
249
+ assert_match(/GET \/empty/, sink.string,
250
+ "expected debug output to include request line, got: #{sink.string.inspect}")
251
+ end
252
+
253
+ # Regression: build_header_hash must not match a top-level ::Headers
254
+ # constant defined by the host app (would happen with inherit: true).
255
+ def test_build_header_hash_ignores_toplevel_headers_constant
256
+ Object.send(:remove_const, :Headers) if Object.const_defined?(:Headers, false)
257
+ Object.const_set(:Headers, Class.new)
258
+ begin
259
+ result = Rack::Proxy.send(:build_header_hash, [['X-Test', 'value']])
260
+ # On Rack 3+ we get Rack::Headers; on Rack 2 we get Rack::Utils::HeaderHash.
261
+ # In neither case should we get the bogus top-level ::Headers.
262
+ assert_not_equal ::Headers, result.class,
263
+ "build_header_hash leaked into top-level ::Headers"
264
+ ensure
265
+ Object.send(:remove_const, :Headers)
266
+ end
267
+ end
268
+
269
+ def test_no_logger_means_no_debug_output
270
+ # Without a :logger option, Net::HTTP's set_debug_output should never be
271
+ # called. We can't directly assert that, but we can confirm requests still
272
+ # work when no logger is configured (covered by every other test).
273
+ with_webrick_proxy(streaming: false) do |port, proxy|
274
+ proxy.host = "127.0.0.1:#{port}"
275
+ get '/empty'
276
+ assert last_response.ok?
277
+ end
278
+ end
279
+
229
280
  private
230
281
 
231
282
  def assert_no_array_header_values(streaming:)
@@ -242,7 +293,7 @@ class RackProxyTest < Test::Unit::TestCase
242
293
 
243
294
  # Spin up a tiny WEBrick server with fixed routes so we can exercise the
244
295
  # proxy against real Net::HTTP requests without depending on a remote host.
245
- def with_webrick_proxy(streaming:)
296
+ def with_webrick_proxy(**proxy_opts)
246
297
  require 'webrick'
247
298
  server = WEBrick::HTTPServer.new(
248
299
  Port: 0,
@@ -260,7 +311,7 @@ class RackProxyTest < Test::Unit::TestCase
260
311
  Thread.new { server.start }
261
312
  port = server.config[:Port]
262
313
 
263
- proxy = HostProxy.new(streaming: streaming)
314
+ proxy = HostProxy.new(**proxy_opts)
264
315
  @app = proxy
265
316
  yield port, proxy
266
317
  ensure
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacek Becela