bblimke / webmock

Library for stubbing and setting expectations on HTTP requests in Ruby.
MIT License
3.94k stars 554 forks source link

Conflict with rack-proxy (undefined method `closed?' for nil:NilClass) #883

Open strayer opened 4 years ago

strayer commented 4 years ago

This is related to https://github.com/bblimke/webmock/issues/374

We use rack-reverse-proxy to access our webpack-dev-server when running the tests. Since there is some kind of conflict between rack-proxy (used by rack-reverse-proxy) and webmock I decided to open a new issue specific to this use-case – I hope you don't mind.

As soon as webmock is added to the mix, something in rack-proxy or Net::HTTP seems to break, although I'm not able to grasp the specific root of the problem.

I created a very simple Rails app that demonstrates the issue: https://github.com/Strayer/rack-proxy-webmock-conflict

To reproduce the issue, simply start the server (rails s) and then try to access something in the reverse-proxy URL: curl http://localhost:3000/gh/README.md

The request will fail with this stacktrace:

NoMethodError (undefined method `closed?' for nil:NilClass):

/Users/strayer/.asdf/installs/ruby/2.6.6/lib/ruby/2.6.0/net/http.rb:1547:in `begin_transport'
rack-proxy (0.6.5) lib/net_http_hacked.rb:50:in `begin_request_hacked'
rack-proxy (0.6.5) lib/rack/http_streaming_response.rb:60:in `response'
rack-proxy (0.6.5) lib/rack/http_streaming_response.rb:29:in `headers'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/roundtrip.rb:166:in `rack_response_headers'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/roundtrip.rb:157:in `build_response_headers'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/roundtrip.rb:153:in `response_headers'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/roundtrip.rb:182:in `need_replace_location?'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/roundtrip.rb:172:in `replace_location_header'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/roundtrip.rb:197:in `setup_response_headers'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/roundtrip.rb:209:in `proxy'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/roundtrip.rb:21:in `call'
rack-reverse-proxy (0.12.0) lib/rack_reverse_proxy/middleware.rb:25:in `call'
rack (2.2.2) lib/rack/etag.rb:27:in `call'
rack (2.2.2) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.2) lib/rack/head.rb:12:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport (6.0.2.2) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (6.0.2.2) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
railties (6.0.2.2) lib/rails/rack/logger.rb:38:in `call_app'
railties (6.0.2.2) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:80:in `block in tagged'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:28:in `tagged'
activesupport (6.0.2.2) lib/active_support/tagged_logging.rb:80:in `tagged'
railties (6.0.2.2) lib/rails/rack/logger.rb:26:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/request_id.rb:27:in `call'
rack (2.2.2) lib/rack/runtime.rb:22:in `call'
activesupport (6.0.2.2) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/static.rb:126:in `call'
rack (2.2.2) lib/rack/sendfile.rb:110:in `call'
actionpack (6.0.2.2) lib/action_dispatch/middleware/host_authorization.rb:83:in `call'
railties (6.0.2.2) lib/rails/engine.rb:526:in `call'
puma (4.3.3) lib/puma/configuration.rb:228:in `call'
puma (4.3.3) lib/puma/server.rb:682:in `handle_request'
puma (4.3.3) lib/puma/server.rb:472:in `process_client'
puma (4.3.3) lib/puma/server.rb:328:in `block in run'
puma (4.3.3) lib/puma/thread_pool.rb:134:in `block in spawn_thread'
strayer commented 4 years ago

This seems to be related to net_http_connect_on_start. When adding WebMock.disable_net_connect!(net_http_connect_on_start: true) to the webmock initializer in my example project, the proxy requests work again. Reading the README I don't see any negative side effects of setting this, so I assume this is a reasonable workaround for this use case.

bblimke commented 3 years ago

Thanks for submitting the issue.

Webmock also modifies Net::HTTP therefore it doesn't play nicely with other libraries that modify Net::HTTP as well.

rack-proxy (0.6.5) lib/net_http_hacked.rb:50:inbegin_request_hacked'`

geoffyoungs commented 2 years ago

In case anyone else comes across this, I've added the following monkey patch, which works for my test case:

module WebMock
    module HttpLibAdapters
      class NetHttpAdapter
        @webMockNetHTTP.define_method(:begin_request_hacked) { |req| request(req) }
      end
    end
end