Skip to main content

Bug Tracker

Side navigation

#13654 closed bug (notabug)

Opened March 23, 2013 08:54PM UTC

Closed March 26, 2013 11:55PM UTC

Last modified March 27, 2013 04:46PM UTC

Ajax response with status code 204 triggers fail() on cross-domain requests

Reported by: ojak Owned by: ojak
Priority: undecided Milestone: None
Component: unfiled Version: 1.9.1
Keywords: Cc: jaubourg
Blocked by: Blocking:
Description

Ajax response with status code 204 triggers fail() on cross-domain requests. Example

http://localhost:8080/served_page.html
  >> .ajax() to localhost:8080 with response 204 triggers .done()
  >> .ajax() to localhost:8081 with response 204 triggers .fail() with xhr.status = 0
Attachments (0)
Change History (15)

Changed March 23, 2013 08:57PM UTC by ojak comment:1

A fix was attempted in ticket:13261 that seems to have only solved same domain requests.

Changed March 23, 2013 09:10PM UTC by ojak comment:2

_comment0: One note, the ajax request works when 'script' or 'jsonp' is specified as the dataType, but fails on 'text'. Since 204 is a success with No Content, a 204 response should always trigger a success unless there is any content, which would be an invalid 204. \ \ I think the most correct way to handle this would probably be to define an expected dataType return of 'none' or 'empty'. Any thoughts? \ 1364073107655813

One note, the ajax request works when 'script' is specified as the dataType, but fails on 'text'. Since 204 is a success with No Content, a 204 response should always trigger a success unless there is any content, which would be an invalid 204.

I think the most correct way to handle this would probably be to define an expected dataType return of 'none' or 'empty'. Any thoughts?

Changed March 25, 2013 02:13PM UTC by dmethvin comment:3

cc: → jaubourg

Julian can you take a look?

Changed March 25, 2013 02:37PM UTC by jaubourg comment:4

I'm ready to look into this, with a proper test case ;)

Off the top of my head, if it's cross-domain, using script tag injection, then we don't get the status code anyway, so we just cannot handle it appropriately.

I'm really confused about the dataType juggling described but I cannot draw any conclusion out of vague descriptions: test cases are mandatory especially for ajax bugs.

Also, which browser ? What is the error triggered (the args given to the error callbacks) ? etc etc

Changed March 25, 2013 02:52PM UTC by dmethvin comment:5

owner: → ojak
status: newpending

We're awaiting a test case from the reporter then; @ojak please provide more information as requested above.

Changed March 25, 2013 10:16PM UTC by ojak comment:6

_comment0: Here's a test example code, firebug console logs, and sample nginx.conf to setup 204's: \ \ https://gist.github.com/ojak/52412731364250261617965
_comment1: Here's a test example code, firebug console logs, and sample nginx.conf to setup 204's: \ \ https://gist.github.com/ojak/5241273 \ \ I tested on Firefox 19 and Chrome 25.0.1364.172 (although Chrome needs to be run with flags to avoid Access-Control-Allow-Origin issues).1364250309685894
status: pendingnew

Here's some example code with 4 tests, the resulting firebug console logs, and sample nginx.conf to setup 204's on localhost:

https://gist.github.com/ojak/5241273

I tested on Firefox 19 and Chrome 25.0.1364.172 (although Chrome needs to be run with flags to avoid Access-Control-Allow-Origin issues).

Changed March 25, 2013 10:52PM UTC by jaubourg comment:7

All right:

  • for dataType "script", a script tag is used as a transport, so jQuery **cannot** access the actual status code, so it assumes 200 for success, 404 for error. There is no way around it. It is working as expected. If you wanna avoid the script transport, force crossDomain to false.
  • for dataType "text", could you log the actual arguments in the fail callback ? Logging "Fail" doesn't give much information as to why the request actually fails.

Thanks for the follow up btw. If you can log the arguments given to the fail handler in TEST4, I may be able to assess what's going on without having to setup the env you've already setup yourself.

Changed March 25, 2013 10:53PM UTC by jaubourg comment:8

status: newpending

Changed March 25, 2013 11:25PM UTC by ojak comment:9

status: pendingnew

I updated the gist on the fail with some xhr response information:

https://gist.github.com/ojak/5241273


--- TEST4: Test different port with 'text' dataType
GET http://localhost:8082/204 204 No Content
Fail
- xhr.status : 0
- xhr.statusText : error
- xhr.response : undefined
- xhr.responseText :
- xhr.responseXML : undefined
- textStatus : error
- errorThrown :
=== FAIL AND INCORRECT STATUSCODE

Changed March 25, 2013 11:48PM UTC by jaubourg comment:10

status: newpending

Hmmm, looks a lot like a network error (status code 0, no errorThrown). At least we know it's not the conversion logic going wrong.

Just out of curiosity, and before I dive deeper in there, does the request work using pure xhr?

Something along the lines of the following snippet (untested):

var xhr = $.ajaxSettings.xhr();

xhr.open( "GET", "http://localhost:8082/204" );

xhr.onsuccess = function() {
   console.log( "success", xhr, arguments );
};

xhr.onerror = function() {
   console.log( "error", xhr, arguments );
};

xhr.onabort = function() {
   console.log( "abort", xhr, arguments );
};

xhr.ontimeout = function() {
   console.log( "abort", xhr, arguments );
};

xhr.send();

Also, you should test with http://code.jquery.com/jquery-git.js so that you use jQuery latest (not that it should matter much but you never know).

Changed March 26, 2013 05:08PM UTC by ojak comment:11

_comment0: Interesting. Tried that out and here are the results: \ \ Screenshot of firebug results: \ http://s3.amazonaws.com/ojak/screenshot-jquery-xhr.png \ \ Code to reproduce: \ https://gist.github.com/ojak/5247073 \ \ 1364317973143701
status: pendingnew

Interesting. Tried that out and here are the results:

Screenshot of firebug results:

http://s3.amazonaws.com/ojak/screenshot-jquery-xhr.png

Code to reproduce:

https://gist.github.com/ojak/5247073

Same results against the current jQuery dist built from the master branch.

Changed March 26, 2013 05:37PM UTC by jaubourg comment:12

My guess is you have a Content-Type in your response headers that trigger the xml parsing logic in FF. Same in Chrome?

Sounds less and less like a jQuery bug...

Changed March 26, 2013 09:10PM UTC by ojak comment:13

_comment0: I still think it's a jQuery bug since 204s should not return a "Content-Type" from the server, since by definition there should be no content, so maybe that's the problem?: \ \ http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5 \ \ The attached screenshot shows the Response Header, which show that the response headers do not have a Content-Type: \ \ http://s3.amazonaws.com/ojak/screenshot-xhr-response-headers.png \ 1364332397281296

The attached screenshot shows the Response Header, which show that the response headers do not have a Content-Type:

http://s3.amazonaws.com/ojak/screenshot-xhr-response-headers.png

I still think it's a jQuery bug since 204s should not return a "Content-Type" from the server, since by definition there should be no content:

http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5

But in the end, both Chrome and Firefox are seeing failures, so maybe that's the problem? There should probably be a dataType of "none" defined in jQuery, since the response is not failing.

Changed March 26, 2013 11:55PM UTC by jaubourg comment:14

resolution: → notabug
status: newclosed

I think you should take this discussion into the forums or stackoverflow.

From what you showed, the response is **not** successful. The error handler is triggered on the native XHR. The native XHR is not part of jQuery just replace $.ajaxSettings.xhr() by new XMLHttpRequest() to convince yourself no jQuery code is used here.

What this means is that browsers seem to have a problem with your 204 responses. From what I gather from the error message in firebug, it seems as if Firefox is trying to parse the response as XML (not jQuery but Firefox itself), hence why I made the wild guess you had a Content-Type response header (a header that is provided by the server, not something jQuery would incante out of thin air). It doesn't seem to be the problem though. Maybe your 204 response has a body (I see an XML tab in http://s3.amazonaws.com/ojak/screenshot-xhr-response-headers.png which doesn't seem right at all), again something that is provided by the **server** not client-side code.

I dunno if it's a configuration problem server-side, a bug in the browsers, a problem specific to CORS or some convoluted behaviour that makes no sense but is actually standard. What's clear though is that jQuery is not responsible for the problem and no action on our part is needed nor possible: if the native XHR notifies an error with the wrong status code, jQuery just cannot "guess" what the original status code was.

I'll close this as notabug but, please, feel free to add a link to any forum or stackoverflow discussion/question related to the issue.

Changed March 27, 2013 04:46PM UTC by ojak comment:15

_comment0: Gotcha, thanks. \ \ Just for a little extra color on the issue, there appears to be a 3+ year old bug in Firefox for this behavior: \ \ https://bugzilla.mozilla.org/show_bug.cgi?id=521301 \ \ Anyhow, thanks so much for helping track down these issues. I think the best advice going forward for others coming across this issue is: '''"don't use 204's for AJAX requests, use 200's with empty content"'''... which is a bummer. \ \ Might be worth updating the jQuery docs to mention this note?1364402810139103

Gotcha, thanks.

Just for a little extra color on the issue, there appears to be a 3+ year old bug in Firefox for this behavior:

https://bugzilla.mozilla.org/show_bug.cgi?id=521301

Anyhow, thanks so much for helping track down these issues. I think the best advice going forward for others coming across this issue is: '''"don't use 204's for AJAX requests, use 200's with empty content"'''... which is a bummer.

Might be worth updating the jQuery docs to mention this behavior as a warning?