Throttling POST requests in rails application
Asked Answered
O

2

6

I'm using rack-throttle as a rate-limiting engine in my rails 3 application. I've created my own class based on the Rack::Throttle::Interval to define custom rate limiting logic. I'm checking if the request is made to exact controller and exact action. This works fine if I make GET request. However if i send POST request i get some problems.

class CustomLimiter < Rack::Throttle::Interval
  def allowed?(request)
    path_info = Rails.application.routes.recognize_path request.url rescue path_info = {} 
    if path_info[:controller] == "some_controller" and path_info[:action] == "some_action"
      super
    else
      true
    end
  end
end

Here are my controller actions

def question
  #user is redirected here
end

def check_answer
  #some logic to check answer
  redirect_to question_path
end

My routes

get "questions" => "application#question", :as => "question"
post "check_answer" => "application#check_answer", :as => "check_answer"

EDIT:

The problem is that POST requests are coming to application so that method allowed? is called. But when i call Rails.application.routes.recognize_path i get a Route set not finalized exception. How can i prevent a user from sending a lot of post requests on the exact action of the exact controller with the help of rack-throttle

The middleware is added in application.rb

class Application < Rails::Application
  #Set up rate limiting
  config.require "ip_limiter"
  config.require "ip_user_agent_limiter"
  config.middleware.use IpLimiter, :min => 0.2
  config.middleware.use IpUserAgentLimiter, :min => 2
end

Both IpLimiter and IpUserAgentLimiter are derived from custom limiter

Originally answered 12/3, 2012 at 6:48 Comment(5)
How have you insert your Rack::Throttle::Interval in your application ?Tyburn
@Tyburn it's included in application.rbOriginally
The allowed? method is call in POST method or not ? Can you pase the part where you add this middleware in your Application ?Tyburn
@Tyburn Please see edits in the questionOriginally
Did you figure this one out?Oldster
T
2

After reading the code of Rails.application.routes.recognize_path ( http://apidock.com/rails/ActionDispatch/Routing/RouteSet/recognize_path ), this methode get a second args where you can pass the METHOD.

Try with :

path_info = Rails.application.routes.recognize_path(request.url, {:method => request.request_method}) rescue path_info = {} 

After all method can works I suppose.

Tyburn answered 12/3, 2012 at 11:12 Comment(1)
I still get the following RuntimeError: route set not finalized from /home/rkapitonov/.rvm/gems/ruby-1.9.2-p290/gems/rack-mount-0.8.3/lib/rack/mount/route_set.rb:81:in recognize'` when tying to do the following Rails.application.routes.recognize_path(request.url, {:method => request.request_method})Originally
O
0

This one worked for me, to catch all POST requests, and ignore all GET requests:

class CustomLimiter < Rack::Throttle::Interval

  def allowed?(request)
    return true unless request.request_method == "POST"
    super request
  end

end
Oldster answered 4/12, 2013 at 16:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.