Grauw’s blog

Update: Note that this post talks about the XMLHttpRequest specification of April 2008. In the meanwhile, the specification has changed to require a default Accept header of */*.

According to the XMLHttpRequest specification (April 2008 working draft), [the User Agent] must not automatically set the Accept [header]. Currently, the browsers send the following headers:

Default XMLHttpRequest Accept header
Browser Accept header
Internet Explorer 7 */*
Firefox 3b5 text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Safari */*
Opera 9.x text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1

So from this we can conclude that none of the browsers do what the specification says they should do. Internet Explorer and Safari do reasonably ok (*/* is not very different from not sending the header at all), however Firefox and Opera’s headers are terrible.

You can try this testcase to see what your browser does:

Request headers:

If the textarea above is coloured red, it contains an HTTP_ACCEPT key, and your browser does not implement the XMLHttpRequest specification correctly.

The rationale behind the specification is that when an Accept header is not set explicitly, we do not know what the application expects the server to return. Setting a default Accept header effectively means that we are lying to the server, which breaks correct functioning of HTTP content negotiation.

For example, an application issues a request to http://example.com/users/423 without setting Accept: application/xml, expecting to receive an XML file describing the user. Now, say the server wants to implement a user-friendly HTML view of the data on the same address; it basically can not do this without updating the application, because when it returns the text/html view as the Accept header by default indicates is acceptable, the application will break. Had the browsers done the right thing, and not lied about what the application expects, this would not have been an issue and content negotiation could have worked the way it was designed.

Now of course one has to consider that the XMLHttpRequest specification comes after the fact, browsers. However, I wish browsers had taken more care with their implementations. It is especially odd that not all browsers mimick Internet Explorer in this regard (which was, after all, the browser that originally implemented the feature).

Update: Some more results of manipulating the Accept header on a XMLHttpRequest:

setRequestHeader('Accept', '') result
Browser Accept header
Internet Explorer 7 */*
Firefox 3b5 (removes Accept header)
Safari (sends empty Accept header)
Opera 9.x text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
setRequestHeader('Accept', null) result
Browser Accept header
Internet Explorer 7 null
Firefox 3b5 (removes Accept header)
Safari null
Opera 9.x text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1

Update: Note that in case of headers other than Accept, Opera 9.x sets the string ‘null’ like Safari and IE7.

Grauw

4 comments [reply]

Comments

by Martijn at 2008-04-28 16:07

Could you file a bug on this? Or perhaps this is an already known bug?

Mozilla bug created by Grauw at 2008-05-15 13:39

Hi Martijn,

I’ve filed bug 433859.

Latest Draft by Santiago Gala at 2010-04-19 15:08

According to the latest draft, as of today http://www.w3.org/TR/2009/WD-XMLHttpRequest-20091119/ :

If the user agent implements server-driven content-negotiation it should set Accept-Encoding and Accept-Charset headers as appropriate. For Accept and Accept-Language the user agent must follow these constraints:
* Both headers must not be modified if they are already set through setRequestHeader().
* If not set through setRequestHeader() Accept-Language should set as appropriate.
* If not set through setRequestHeader() Accept must be set with as value */*.”

So the post should be updated, specially the live demo. My browser, for instance, is flagged as non-compliant but it is sending the *right* */* value...

Re: Latest Draft by Grauw at 2010-04-22 23:01

Hey Santiago,

Yeah, actually I know :), it was changed partially at my request. See these posts and this thread. Although not in the way I had preferred, but still in an acceptable manner.

Thanks for pointing it out though, I’ve added a note at the top to clarify the current status, and also updated the link to explicitly point to the April 2008 draft, instead of the latest.

» Add a comment…