Permalink
Browse files

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 5603050)
  • Loading branch information...
1 parent ffd3289 commit 0cfa6b71f2a39ed92c83233d7f685ce21d481eb5 @pixeltrix pixeltrix committed May 2, 2012
View
4 actionpack/lib/action_dispatch/http/parameters.rb
@@ -35,6 +35,10 @@ def path_parameters
@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
2 actionpack/lib/action_dispatch/routing/mapper.rb
@@ -35,6 +35,8 @@ def matches?(env)
}
return true
+ ensure
+ req.reset_parameters
end
def call(env)
View
19 actionpack/test/dispatch/routing_test.rb
@@ -2552,3 +2552,22 @@ def expected_redirect_body(url)
%(<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

0 comments on commit 0cfa6b7

Please sign in to comment.