Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Order of an accept header should not matter to respond_to (Rails 3.0.0.rc)

#5278

If a client supplies an "Accept: text/html,*/*" header, this should be equivalent to "Accept: */*,text/html". In the patch to add a (failing) test attached, this is not the case.

Example:

class AdvancedController < ActionController::Base
  def xml_only
    respond_to do |format|
      format.xml do
        render :content_type => 'application/xml', 
               :text => "invalid xml" and return
      end
    end
  end
end

If a client requests this with "Accept: */*, text/html", the format.xml block is used, but if the client requests "Accept: text/html,*/*", it is not.

My apologies that I cannot currently supply a fix. Thank you!

Reported by Erik Hetzner · August 2nd, 2010 @ 11:19 PM

State: resolved
Milestone: 3.x
Assigned to: José Valim José Valim
Importance: Low

Activity

  1. trevmex
    trevmex
    • Tag set to http accepts mime action_dispatch

    It seems that this is as planned. See the post at http://geminstallthat.wordpress.com/2008/05/14/ie6-accept-header-is...
    There is a regex in actionpack/lib/action_dispatch/http/mime_negotiation.rb that checks for this (line 51):

     xhr? || (accept && accept !~ /,\s**\/*/)
    

    Although the HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) says it is allowed, the patch is in place for IE6. Thoughts?

    August 3rd, 2010 @ 12:26 AM

  2. Erik Hetzner
    Erik Hetzner

    Thanks for adding the appropriate tags; I wasn't sure which to add.

    I don't have a lot of experience with the latest Rails, so take what I have to say with a grain of salt.

    While IE's Accept header is a little strange, it is basically equivalent to "/", which is not a ridiculous header to send if your client really can accept most formats.

    In this case it is the server's responsibility to choose the preferred format to return to the client. Since format.html is the first in the respond_to block, shouldn't it have higher priority than a format.any catch-all response?

    Thanks.

    August 3rd, 2010 @ 01:15 AM

  3. Erik Hetzner
    Erik Hetzner

    Above, third paragraph should be:

    While IE's Accept header is a little strange, it is basically equivalent to "*/*", which is not a ridiculous header to send if your client really can accept most formats.

    Markdown stole my *s.

    August 4th, 2010 @ 12:31 AM

  4. Erik Hetzner
    Erik Hetzner

    As background, I encountered this bug when attempting to create & view a resource that only had an Atom representation:

    def recent
      respond_to do |format|
        format.atom do
          render :content_type => 'application/atom+xml', 
                 :text => "invalid atom" and return
        end
      end
    end
    

    Which does not work as expected (by displaying an atom feed) with a Firefox Accept header: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, but instead returns a 406 Not Acceptable. So this bug has potential real world impact.

    August 4th, 2010 @ 12:43 AM

  5. Rohit Arondekar
    Rohit Arondekar
    • Importance changed from to Low

    Any updates here?

    Also Erik can you make that failing test patch according to http://rails.lighthouseapp.com/projects/8994/sending-patches so that you get credit for commit.

    October 7th, 2010 @ 06:15 AM

  6. Erik Hetzner
    Erik Hetzner

    Hi Rohit,

    Here you go; hope I did things right.

    October 9th, 2010 @ 01:21 AM

  7. Rohit Arondekar
    Rohit Arondekar
    • State changed from new to open
    • Assigned user set to Santiago Pastorino

    October 9th, 2010 @ 01:32 AM

  8. Santiago Pastorino
    Santiago Pastorino
    • Milestone set to 3.x
    • Assigned user changed from Santiago Pastorino to José Valim

    November 7th, 2010 @ 12:31 PM

  9. José Valim
    José Valim
    • State changed from open to resolved

    We have changed this behavior on master. Please read: http://www.neeraj.name/2010/11/23/mime-type-resolution-in-rails.html for more information.

    December 4th, 2010 @ 05:48 PM

  10. Erik Hetzner
    Erik Hetzner

    Thanks!

    A quick read of that blog post reveals:

    I am going to assume that in this case HTTP_ACCEPT sent by browser looks really simple like this text/javascript, text/html, text/plain

    [...]

    So browser is saying that I prefer documents in following order js html plain

    This is not correct, as this bug report states. Order does not matter in an accept header, only q values matter in deciding which the client prefers. I don't know if the implementation is effected, but the blog post should probably be corrected.

    December 4th, 2010 @ 06:10 PM

  11. Neeraj Singh
    Neeraj Singh

    rails currently does take q value into account.

    However if there is no q value specified then what. In that case rails gives preference to the ones specified earlier in the HTTP_ACCEPT value.

    Hope that clears your question.

    December 4th, 2010 @ 06:22 PM

  12. Erik Hetzner
    Erik Hetzner

    Hi Neeraj,

    Of course rails is free to return whatever it wants from the set of possible values supplied by the accept header, if they have equal q values.

    But the client has not preferred, in the above example, javascript over html. If rails returns javascript, it is because rails prefers it, not the client.

    As an application author I would like to be able to specify in some way that I would rather return HTML than, say, javascript, or the other way round, if the client has not specified a preference. And the order of the accept header does not specify a preference.

    In any case, thank you for working on this!

    December 4th, 2010 @ 09:26 PM

  13. José Valim
    José Valim

    Exactly Erik, I believe this scenario is fixed in Rails master. The blog post explains why and how it is fixed.

    December 4th, 2010 @ 09:32 PM

  14. Erik Hetzner
    Erik Hetzner

    Maybe we can start over. I posted a comment on the blog post. Quotations are from the blog post.

    For all documents that have same q value give high priority to the one that came first in the list.

    An HTTP client does not mean to prioritize mime types by their ordering in the accept header; nothing in the spec says that order matters.

    So browser is saying that I prefer documents in following order

    js html plain

    Again, the client is not saying that it prefers documents in any order; js, html & plain have the same q value; order does not matter.

    Now, rails can do whatever it wants with these headers, as long as it honors q values. But order of accept headers is basically random,
    and using it to make decisions will, in my opinion, lead to strange errors.

    Here is a real world problem with this.

    "Accept: /" is treated differently from "Accept: text/xml, text/html" in terms of which respond_to block is used. In other words, if the respond_to block contains:

    format.xml { ... } format.html { ... }

    If the client uses "Accept: /", the html block will be used. If the client uses
    "Accept: text/xml, text/html", the xml block will be used. This would be suprising to the application author, as well as the client.

    I know that there are real world problems with bad accept headers being sent by the client, but I don't see how this solution solves those problems.

    December 5th, 2010 @ 06:39 PM