There is an outstanding pull request for this - i pulled out the changes and made this function to patch my angular. Hopefully the pr is sorted out sometime, or maybe patching is the best approach (just needs maintaining)
I just run this over my main application module. Im not sure if it breaks anything, but its working for me.
function patchAngular (mod) {
function noop() {}
noop.$inject = [];
var IS_SAME_DOMAIN_URL_MATCH = /^(([^:]+):)?\/\/(\w+:{0,1}\w*@)?([\w\.-]*)?(:([0-9]+))?(.*)$/;
var XHR = window.XMLHttpRequest || function() {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw new Error("This browser does not support XMLHttpRequest.");
}, XDR = !window.msPerformance && window.XDomainRequest || null;
function createHttpBackend($browser, XHR, XDR, $browserDefer, callbacks, rawDocument, locationProtocol) {
// TODO(vojta): fix the signature
return function(method, url, post, callback, headers, timeout, withCredentials, useXDomain) {
$browser.$$incOutstandingRequestCount();
url = url || $browser.url();
if (angular.lowercase(method) == 'jsonp') {
var callbackId = '_' + (callbacks.counter++).toString(36);
callbacks[callbackId] = function(data) {
callbacks[callbackId].data = data;
};
jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
function() {
if (callbacks[callbackId].data) {
completeRequest(callback, 200, callbacks[callbackId].data);
} else {
completeRequest(callback, -2);
}
delete callbacks[callbackId];
});
} else {
var status;
if (true && XDR) {
var xdr = new XDR();
xdr.open(method.toLowerCase(), url);
// Required to XDomainRequest works
xdr.timeout = timeout;
xdr.onprogress = function() {};
xdr.ontimeout = function() {
completeRequest(callback, 408, 'Timeout', 'Content-Type: text/plain');
xdr.abort();
};
xdr.onload = function() {
completeRequest(callback, 200, xdr.responseText, 'Content-Type: ' + xdr.contentType);
};
xdr.onerror = function() {
completeRequest(callback, 500, 'Error', 'Content-Type: text/plain');
xdr.abort();
};
$browserDefer(function () {
xdr.send();
}, 0); //fix IE bug that raises '$apply already in progress' on cached requests
if (timeout > 0) {
$browserDefer(function() {
status = -1;
xdr.abort();
}, timeout);
}
} else {
var xhr = new XHR();
xhr.open(method, url, true);
angular.forEach(headers, function(value, key) {
if (value) {xhr.setRequestHeader(key, value);}
});
// In IE6 and 7, this might be called synchronously when xhr.send below is called and the
// response is in the cache. the promise api will ensure that to the app code the api is
// always async
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
completeRequest(
callback, status || xhr.status, xhr.responseText, xhr.getAllResponseHeaders());
}
};
if (withCredentials) {
xhr.withCredentials = true;
}
xhr.send(post || '');
if (timeout > 0) {
$browserDefer(function() {
status = -1;
xhr.abort();
}, timeout);
}
}
}
function completeRequest(callback, status, response, headersString) {
// URL_MATCH is defined in src/service/location.js
var protocol = (url.match(IS_SAME_DOMAIN_URL_MATCH) || ['', locationProtocol])[1];
// fix status code for file protocol (it's always 0)
status = (protocol == 'file') ? (response ? 200 : 404) : status;
status = status == 1223 ? 204 : status;
callback(status, response, headersString);
$browser.$$completeOutstandingRequest(noop);
}
};
function jsonpReq(url, done) {
// we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
// - fetches local scripts via XHR and evals them
// - adds and immediately removes script elements from the document
var script = rawDocument.createElement('script'),
doneWrapper = function() {
rawDocument.body.removeChild(script);
if (done) {
done();
}
};
script.type = 'text/javascript';
script.src = url;
if (msie) {
script.onreadystatechange = function() {
if (/loaded|complete/.test(script.readyState)) doneWrapper();
};
} else {
script.onload = script.onerror = doneWrapper;
}
rawDocument.body.appendChild(script);
}
}
mod.config(['$httpBackendProvider', function($httpBackendProvider) {
$httpBackendProvider.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
return createHttpBackend($browser, XHR, XDR, $browser.defer, $window.angular.callbacks,
$document[0], $window.location.protocol.replace(':', ''), true);
}];
}]);
};