0

In my rails 4 app I'd like to response with html both for html and js request. At the moment when the request is html type the rendering works fine, but when the request is js then the html file doesn't get rendered on the screen (although in the command line it says it's rendered).

There are different scenarios for limiting requests so the throttle code can be triggered by html POST and js POST request as well.

Rack::Attack.throttle(key, limit: from_config(key, :limit), period: from_config(key, :period)) do |req|
  if req.path.ends_with?(from_config(key, :path).to_s) && from_config(key, :method) == req.env['REQUEST_METHOD']
    ### This is the snippet I try to change the req type with but not working
    if req.media_type == 'application/javascript'
      req.media_type = 'text/html'
    end
    ##### till here
    req.ip
  end
end

Here is what I'm trying to render. As you see this is html response.

Rack::Attack.throttled_response = lambda do |env|
  [429, {}, [ActionView::Base.new.render(file: 'public/429.html', content_type: 'text/html')]]
end

What should I do?

UPDATE

This is my newest version, but can't figure out how to check the request content_type:

Rack::Attack.throttled_response = lambda do |env|
  retry_after = (env['rack.attack.match_data'] || {})[10]
  if env['rack.attack.content_type'] == 'text/html'
    [429, {'Retry-After' => retry_after.to_s}, [ActionView::Base.new.render(file: 'public/429.html', content_type: 'text/html')]]
  elsif env['rack.attack.content_type'] == 'application/javascript'
    [429, {'Retry-After' => retry_after.to_s}, window.location.href = '/429.html']
  end
end

docs: https://github.com/kickstarter/rack-attack

Sean Magyar
  • 2,360
  • 1
  • 25
  • 57
  • Why on earth would you want to do that? It would make more sense to create a custom mime type or use headers to check if it is a XHR request rather than mess up one of the existing mime types. – max Mar 30 '16 at 09:59
  • Most browsers wont render the response as HTML either if the request has something other than `accept: text/html`. – max Mar 30 '16 at 10:02
  • max, can you show me how to do that? I don't know why this would mess anything up, since this happens only if sby exceeds the limit for some action. – Sean Magyar Mar 30 '16 at 10:16
  • I kind of missed the part about throttling, do you really need / want to return a html response? If a client has been throttled you should return `429` and either a blank response or javascript containing a comment as to not break clients that might actually be expecting a JS response and will try to parse the response as javascript. – max Mar 30 '16 at 10:22
  • 1
    As a developer I would find that a lot more helpful than my script blowing up due to a pretty error page. – max Mar 30 '16 at 10:23
  • max, the problem is that the request that will be throttled can be both js and html. For example logging in is an html request, but commenting on a post is js. If I set the js response as you say then it won't response to the html request. So this question is not about the error page (js response version is ok with me), but rather about how to response properly to different requests. – Sean Magyar Mar 30 '16 at 10:35
  • Any combination is okay: `1. html req => html resp, js req => html resp` (I'm trying this at the moment.), `2. html req => js resp, js req => js resp`, `3. html req => html resp, js req => js resp` (this one needs some conditional). The problem is I don't know how to code any of these. – Sean Magyar Mar 30 '16 at 10:35
  • max, my friend told me `window.location.href = '/429.html'` would work for js response, but to have that I have to figure out how to check the `request type` first. I went thru the docs but my ruby skills are not there yet. So at the moment `env['rack.attack.content_type']` is the piece of code that not working. Could you tell me how I can check the request type? – Sean Magyar Mar 31 '16 at 09:20

1 Answers1

1

I agree with @max. In principle, you should not respond with HTML to a request specifically for JS.

But to answer this part of the question:

how to check the request content_type:

Try checking this instead:

req.env['HTTP_ACCEPT']

Explanation

  1. req is an object that subclasses Rack::Request.
  2. Rack prepends HTTP_ to the client's HTTP request headers and adds them to the env hash.
  3. HTTP clients can indicate what MIME types they accept in the Accept header, as opposed to the Content-Type header, where they can indicate what type of data they are sending to you.
Community
  • 1
  • 1
monozok
  • 605
  • 1
  • 7
  • 15
  • monozok, if you wouldn't do html response then how would you solve this problem? If sby let's say tries to login 10 times (which an html post req) then he will be redirected to a page which says that he made too many requests. But the same should happen when sby comments too much on a post thread. The problem is that it's a js request since normally (within the req number limit) it should just response with a js snippet. So how can I respond with js if within req limit and with html over req limit? – Sean Magyar Sep 06 '16 at 21:31
  • Ok, rereading your newest version, I see you are responding with JS that tells the browser to redirect. So I don't have a problem with that. My bad! – monozok Sep 08 '16 at 13:37
  • accept works fine but it seems like req.env['HTTP_CONTENT-TYPE'] is not supported? even though its valid header – mirageglobe May 06 '21 at 11:14
  • Maybe it’s HTTP_CONTENT_TYPE with all underscores? – monozok May 07 '21 at 19:35