Reset the request parameters after a constraints check

A callable object passed as a constraint for a route may access the request
parameters as part of its check. This causes the combined parameters hash
to be cached in the environment hash. If the constraint fails then any subsequent
access of the request parameters will be against that stale hash.

To fix this we delete the cache after every call to `matches?`. This may have a
negative performance impact if the contraint wraps a large number of routes as the
parameters hash is built by merging GET, POST and path parameters.

Fixes #2510.
(cherry picked from commit 56030506563352944fed12a6bb4793bb2462094b)
This commit is contained in:
Andrew White
2012-05-02 23:42:43 +01:00
parent ebe994f83c
commit 7c7fb3a862
3 changed files with 25 additions and 0 deletions

View File

@@ -35,6 +35,10 @@ module ActionDispatch
@env["action_dispatch.request.path_parameters"] ||= {}
end
def reset_parameters #:nodoc:
@env.delete("action_dispatch.request.parameters")
end
private
# TODO: Validate that the characters are UTF-8. If they aren't,

View File

@@ -34,6 +34,8 @@ module ActionDispatch
}
return true
ensure
req.reset_parameters
end
def call(env)

View File

@@ -2702,3 +2702,22 @@ private
%(<html><body>You are being <a href="#{ERB::Util.h(url)}">redirected</a>.</body></html>)
end
end
class TestConstraintsAccessingParameters < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
app.draw do
ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
get "/:foo" => ok, :constraints => lambda { |r| r.params[:foo] == 'foo' }
get "/:bar" => ok
end
end
def app; Routes end
test "parameters are reset between constraint checks" do
get "/bar"
assert_equal nil, @request.params[:foo]
assert_equal "bar", @request.params[:bar]
end
end