-
Notifications
You must be signed in to change notification settings - Fork 984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Guard against invalid middleware configuration? #685
Conversation
test/middleware_stack_test.rb
Outdated
@conn.use Orange | ||
@conn.adapter :test, &test_adapter | ||
assert_handlers %w[Apple Orange] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I touched this test while adding the guard feature as the test started failing with the new verification.
Originally, using the build_stack
helper, the order of the middlewares in this test ended-up being:
Apple
:test (adapter)
Orange
which I assume as being invalid according to the README. I figure this is tangental to the original intent of the test itself, which was to verify the builder is mutable, so I re-wrote the test to avoid the failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this test probably overlooked the fact that build_stack
always adds the adapter at the end, going against the README itself.
Your change works but I see that build_stack
and build_handlers_stack
are practically the same thing (and the latter accepts a block but doesn't use it).
Another, better in my opinion, approach would be to add an optional parameter to build_stack
to skip the adapter insertion at the end. This should reduce code duplication even further.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did look to parameterize build_stack
but the splat argument makes this awkward. If we were targeting Ruby >= 2.0 we could use keyword arguments like so:
def build_stack(*handlers, without_adapter: true)
But this fails on Ruby 1.9.3. I'll find another solution to reduce the duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah you're right, that makes it a little more difficult.
ActiveSupport comes with this handy extension:
class Hash
# By default, only instances of Hash itself are extractable.
# Subclasses of Hash may implement this method and return
# true to declare themselves as extractable. If a Hash
# is extractable, Array#extract_options! pops it from
# the Array when it is the last element of the Array.
def extractable_options?
instance_of?(Hash)
end
end
class Array
# Extracts options from a set of arguments. Removes and returns the last
# element in the array if it's a hash, otherwise returns a blank hash.
#
# def options(*args)
# args.extract_options!
# end
#
# options(1, 2) # => {}
# options(1, 2, a: :b) # => {:a=>:b}
def extract_options!
if last.is_a?(Hash) && last.extractable_options?
pop
else
{}
end
end
end
but you'll probably need to add it as it's not one of the gem dependencies.
At this point then having another method like you did is probably better, just check if you can reduce the duplication even further
Hi @odlp and thanks for your PR.
These are the main reasons I've been pushing back changes like this and postponed them to Faraday v1.0. |
Thanks for the quick reply @iMacTia. I completely support maintaining backwards compatibility & waiting for a 1.0 release!
I think this currently covers adding an adapter via
Could you elaborate when an adapter wouldn't inherit from |
lib/faraday/rack_builder.rb
Outdated
@@ -84,6 +84,7 @@ def use(klass, *args, &block) | |||
use_symbol(Faraday::Middleware, klass, *args, &block) | |||
else | |||
raise_if_locked | |||
raise_if_adapter_set unless is_adapter?(klass) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please explain this unless is_adapter?(klass)
?
Does that mean that I'm allowed to insert an adapter after another adapter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was unsure whether adapter overwrites should be allowed, so I erred on the side of it being permissive:
https://github.com/lostisland/faraday/pull/685/files#diff-39d210c7f4f77538e42199f60ce1d2f8R151
But I can see how it doesn't make sense, because #adapter=
twice means the stack has two adapters. Ideally setting that adapter again should be an overwrite (if permitted), not an additional adapter in the stack. This is a different kind of misconfiguration really.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the moment I can remove unless is_adapter?(klass)
and the associated test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep that's fine.
Leaving it there will cause multiple adapters to be inserted as you said, which is definitely something we don't want to happen 😃
Yes so you're currently covering both
Yes I'm referring to custom 3rd party adapters. Basically the only constrain is to have something that replies to Now both issues up here can be addressed putting some rules in place:
And I personally agree with both of them, but again we can't put such constraints in place now as it would break backward-compatibility. |
The documentation states the last middleware is the innermost one, and this should be the adapter. Any misconfiguration can be guarded against by throwing a ConfigurationError if a middleware is set after the adapter.
The additional
|
Thank you @odlp. I would suggest we do the same in this instance, unless you have any particular reason for using |
This is instead of raising an exception, based on feedback from #685
@iMacTia I've switched to |
Thank you @odlp, happy to merge this in. |
* Do not set the adapter on faraday prior the request Related to lostisland/faraday#685 and fixes #148 * adjusting farady middleware patch even more, since also the response configuration must come before any adapter is set * remove .idea, however this slipped through, sorry
Address the following message: ``` WARNING: Unexpected middleware set after the adapter. This won't be supported from Faraday 1.0. ``` Introduced by lostisland/faraday#685
I glossed over this important passage about Advanced middleware usage (emphasis mine):
This pull request proposes a guard against invalid / incorrect builder usage.
I hope this PR will save some other users who didn't fully read the instructions at first, like me, some head-scratching.