Bug Tracker

Opened 7 years ago

Closed 6 years ago

Last modified 5 years ago

#6230 closed bug (fixed)

WEBKIT: xhr.setRequestHeader("Accept", ...) *appends* the value instead of replacing it

Reported by: jpzwarte Owned by:
Priority: low Milestone: 1.5
Component: ajax Version: 1.4.2
Keywords: ajax, header, beforesend, ajaxrewrite Cc:
Blocked by: Blocking:


dataType: 'html', beforeSend: function(xhr) {

xhr.setRequestHeader("Accept", "text/javascript, */*");


I have the above options in my $.ajax call to a Rails application. The html dataType is to prevent errors from jQuery trying to parse the response as script (which it isn't, it's html). The beforeSend callback is to get Rails to see the request as an AJAX request (respond_to handler in rails).

This works fine in Firefox: the "Accept" request header is set to the above value. In Webkit however (tested in Safari 4.0.4 and Webkit nightly) it appends the above value to the already existing value set by jQuery itself ("text/html, */*" based on the dataType). The end result being an Accept value of: "text/html, */*, text/javascript, */*" . This causes Rails to see the request as a normal, non-ajax request, triggering the wrong response.

I checked the Prototype source and it seems to prevent the Webkit behavior from becoming an issue by having the "Accept" header as an option in the ajax call. See http://api.prototypejs.org/ajax_section.html (the requestHeaders common option).

It seems that the W3C spec on XmlHttpRequest is vague. http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader-method states:

  1. If header is in the author request headers list either use multiple headers, *combine the values* or use a combination of those (section 4.2, RFC 2616). [RFC2616]

Emphasis added by me.

Could be that Webkit does the right thing and that Firefox is wrong, or the other way around. Can we adopt the same behavior in jQuery (requestHeaders option) as in Prototype to workaround the different browser behaviors?

Change History (5)

comment:1 Changed 7 years ago by jonespm

I think the bigger problem is there is no way to override the defaults that are appended, even though there *are* ways to override these without using the beforeSend. This is because "*/*" is always appended to the setRequestHeader. I'd suggest changing it to append a default rather than a hardcoded value.

@@ -5139,7 +5139,7 @@
                        // Set the Accepts header for the server, depending on the dataType
                        xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
-                               s.accepts[ s.dataType ] + ", */*" :
+                               s.accepts[ s.dataType ] + "," + s._default :
                                s.accepts._default );
                } catch(e) {}

Then you can at least override it in $.ajaxSetup with a new "accepts"

        $.ajaxSetup ({
                accepts: {
                        xml: "application/xml, text/xml",
                        html: "text/html",
                        script: "text/javascript, application/javascript",
                        json: "application/json, text/javascript",
                        text: "text/plain",
                        // Hack for Chrome/Safari
                        _default: ""

comment:2 Changed 7 years ago by SlexAxton

Keywords: ajax header beforesend added
Priority: low
Status: newopen

comment:3 Changed 6 years ago by Rick Waldron

Keywords: ajaxrewrite added

comment:4 Changed 6 years ago by jaubourg

Could this be checked against the code in the repository? Headers are put in a temporary map before being set on the native xhr object now so I'm pretty confident this is fixed.

comment:5 Changed 6 years ago by jaubourg

Resolution: fixed
Status: openclosed

Fixes #6230. Added a unit test to control that, since the ajax rewrite, setting the Accept header actually replaced the previous value and didn't append to it (tested in Safari 4.0.4 for which the problem was specifically reported).

Changeset: 6504d4f7005c99ea4064068f3d712322a064b97a

Note: See TracTickets for help on using tickets.