this is driving me nutters.
jQuery 1.4.2, windows XP sp3
Here is my test.
Load firefox 3.5+
http://plungjan.name/test/testcors.html
works
Save the file to harddisk and run from there
From my office the external works and the internal does not
What is also interesting is that I cannot run both in one go.
Background: I do a GET to an internal web service that uses CORS. Please do NOT post any answers about FF not handling cross domain request when it does since v3.5 as detailed here and here
It works in IE8 and FF3.6.6 from one server to the other and now almost from file system (file:///) to service. Only from file system and only when FF 3.6.6 needs to negotiate (the user is already logged in, authorised and sends the credentials!) do I not get the data after negotiation. jQuery xhr returns status 0 and no data/responseText or whatever Seems to me, jQuery reacts and saves the xhr from the 401 rather than from the 200 OK later
Here is the result I get at the end of the communication when I alert the XHR object:
Status:success
Data:[]
XHR:
some native functions,
readyState:4
status:0
responseXML:null
responseText:
withCredentials:true
if I make a call to the same server but without needing credentials, the data is returned just fine cross domain
So the communication is as follows:
GET /restapplicationusingcors/authenticationneeded-internal/someid
Accept: application/json
Accept-Language: en
.
.
Origin: null
Cookie: LtpaToken=...
the return is
HTTP/1.1 401 Unauthorized
Server: Apache
Pragma: No-cache
Cache-Control: no-cache
Expires: Thu, 01 Jan 1970 01:00:00 CET
WWW-Authenticate: Negotiate
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
Then FF sends
GET /restapplicationusingcors/authenticationneeded-internal/someid HTTP/1.1
Host: myhost.myintranet.bla
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6
Accept: application/json
Accept-Language: en
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: null
Cookie: LtpaToken=....
Authorization: Negotiate ....
and is rewarded with the file I need, but cannot get at in FF:
HTTP/1.1 200 OK
Date: Tue, 20 Jul 2010 12:08:39 GMT
Pragma: No-cache
Cache-Control: no-cache, max-age=600, s-maxage=3600
Expires: Thu, 01 Jan 1970 01:00:00 CET
X-Powered-By: ...
Content-Disposition: inline;filename=nnnnnn.json
Content-Language: en
Access-Control-Allow-Origin: ...
Keep-Alive: timeout=6, max=70
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
THE DATA SENT FROM THE SERVER IS NOT IN THE XHR OBJECT
Here is my code
function getJSON(url,func,lang) {
accept = 'application/json';
lang=lang?lang:"*";
// gruesome hack to handle that APPENDS the mime header to */* !!!
// NOW HANDLED by first setting Accept to "" !!!
// if ($.browser.msie && url.indexOf('serveAsMime')==-1) {
// url+= '?serveAsMime='+accept;
// }
if (currentRequest != null) currentRequest.abort();
var requestObjectJSON = {
url : url,
// dataType: "json",
method : 'get',
beforeSend: function(xhr){
xhr.setRequestHeader('Accept', ""); // IE hack
xhr.setRequestHeader('Accept', accept);
xhr.setRequestHeader('Accept-Language', lang);
if (url.indexOf('-internal') !=-1) {
try {
xhr.withCredentials = true;
alert('set credentials')
}
catch(e) {
alert('cannot set xhr with credentials')
}
}
},
success: function(data,status,xhr) {
var responseText = xhr.responseText;
var responseJSON = xhr.responseJSON;
var t = "";
try{
for (var o in xhr) t += '\n'+o+':'+xhr[o];
}
catch(e) {
if (e.message.indexOf('.channel')==-1)alert(e.message);
}
alert('Status:'+status+'\nData:['+data+']\nXHR:'+t);
func(responseText);
},
}
currentRequest = $.ajax(requestObjectJSON);
}
CORS with
file://
If you have problems by allowing origins from the
file://
protocol, according to The Web Origin Concept it should be done the same way as any other origins. I could not find information about the browser support, but I think every browser which is supporting CORS does support this one either.The Web Origin Concept tells us the following about the file URI scheme:
According to wikipedia the domain by the file URI scheme is localhost. It is omittable by the address bar, but I don't think it is omittable in the allow origin headers. So if your browser implementation allows origin with a file URI scheme, then you should add
file://localhost
to your allowed origins, and everything should work properly after that.This was how it should work, now meet reality:
file://
protocol is transformed intonull
origin by this implementation. So by firefox thenull
works. I tried with a wider domain list, but I did not manage to allow multiple domains. It seems like firefox does not support a list with multiple domains currently.allow blocked content
button, even by not allowing the null origin. By other domains it works the same way as the previous browsers.HTTP basic auth:
The credentials part I tried out with PHP and HTTP basic auth.
http://test.loc
Displays :-) when logged in and :-( when unauthorized.
So this code changes the location by login and logout.
Cross domain CORS with HTTP basic auth
http://todo.loc
Gets the content of http://test.loc with cross domain XHR and displays it.
Requires headers by http://test.loc:
Cross scheme CORS with HTTP basic auth
file:///path/x.html
Gets the content of http://test.loc with cross scheme XHR and displays it.
Requires headers by http://test.loc:
Conclusion:
I tested cross-sheme CORS with credentials called from
file://
and it works pretty well in firefox, chrome and msie.So you need to set an ajax prefilter in your model/collection in order to use CORS. Otherwise it doesn't send the cookie.
I put this in my Model/Collection initialize function.
This is a stab in the dark since I don't fully understand your problem, but I think you might be having a problem with
file:
URLs, which are not treated as having any origin. I'm not sure it's even possible to authorize CORS from a file URL.These are the conditions to be met to make CORS working with secured services:
Access-Control-Allow-Credentials: true
(see Requests with credentials and Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true).Access-Control-Allow-Origin
should not be*
. The idea is to return the value passed by client in headerOrigin
(see examples in this post).OPTIONS
method should return HTTP code 200, thus it cannot be secured (see The CORS).PUT
/POST
that need to pass certain request headers to service (likeContent-Type
orAccept
), these headers need to be listed inAccess-Control-Allow-Headers
(see jQuery AJAX fails to work when headers are specified)XMLHttpRequest
property:xhr.withCredentials = true;
(as answered by Kirby)Altogether configuration for Apache: