webmock icon indicating copy to clipboard operation
webmock copied to clipboard

Make the ALLOWED_HOSTS threadsafe

Open nhorton opened this issue 1 year ago • 2 comments

Right now, the ALLOW list is global and meant to be set in initialization. We have some very good reasons we want to dynamically allow and disallow some hosts, namely with only a few tests needing to hit that endpoint, and not wanting others to do it accidentally.

I would be game to add the APIs myself for this, but I wanted to confirm that you are good with my approach first before I put in the time.

Proposal

  1. Leave the existing WebMock.disable_net_connect!(allow:) declaration unaltered fully
  2. Add a new `WebMock.with_allowed_connections(*allowed)
  3. That block method would set a thread-local var of the local allowances, and remove it in an ensure
  4. Replace the addr_accessor for allow on config with a version that joins the static variable with the thread variable

Workaround

The alternative I see is a workaround of using a proc as an arg to the static allow list, and having that check the Thread.current store for additional values and comparing. That is what I am about to do for now, but it feels pretty janky.

nhorton avatar Apr 10 '24 17:04 nhorton

@nhorton Thank you for the suggestion.

I believe this would be a useful feature. One of the things I would like to change in WebMock over time is to move away from globals, including stub declarations.

My main concern is that the configuration should be intuitive.

I wonder how the with_allowed_connections configuration should behave when allow_net_connect is already configured. Can with_allowed_connections be invoked without a previous disable_net_connect! invocation? My guess is that it should, but then with_allowed_connections needs to do more than just extend the allow set.

I'm also considering whether Thread.current is the right choice to store the additional allow values. While I understand the purpose and appreciate that the configuration won't leak between threads, it might not work as expected if the block starts any threads where each thread is expected to make a request, or if the HTTP client library uses threads for async requests (like the httpclient gem).

What are your thoughts on that?

bblimke avatar May 24 '24 10:05 bblimke