Search code examples
ruby-on-railsrubyruby-on-rails-3securityrack

Match request URL params with rails routes via recognize_path


I want to check if any incoming request actually exists in routes.rb as an entry via recognize_path like this

def path_exists?(path)
  Rails.application.routes.recognize_path(path)
  true
  rescue
   false
end

This works for most URLs but if the URL has a parameter, then it fails to recognize it.

Example:

In routes.rb, say I have an entry like this

put "foo/bar/:param" => "foo#bar"

and the incoming request URL is of the form /foo/bar/5

Then the function recognize_path doesn't recognize the URL as the value of the parameter is 5 but it is matched with :param

How do I match requests that have parameters to their entries in routes.rb using recognize_path or any other similar function?

Reason

I'm filtering out malicious attempts to hit the server using random URLs like /dump.sql.tar.gz, /conf.xz, etc using the gem rack::attack and throttling requests whose URLs are not a part of routes.rb. Hence the above problem.


Solution

  • You can accomplish that with the following snippet:

    Rails.application.routes.routes.to_a.reduce(false) do |exists, route|
     route.path.to_regexp.match?(path) || exists
    end
    

    But I do think the best choice is handling 404 errors using custom logic. Why doing what the router already does for you? Here's an example:

    config.exceptions_app = self.routes
    # This will route any exceptions caught to your router Rack app. Now you'll want to define routes to display those errors yourself:
    
    # config/routes.rb
    get "/404", :to => "errors#not_found"
    get "/422", :to => "errors#unacceptable"
    get "/500", :to => "errors#internal_error"
    

    (Extracted from http://web.archive.org/web/20141231234828/http://wearestac.com/blog/dynamic-error-pages-in-rails)

    Then you can do whatever logic you want to do on ErrorsController