diff --git a/src/ng/http.js b/src/ng/http.js index deeb6cbb2621..06ad57d690fd 100644 --- a/src/ng/http.js +++ b/src/ng/http.js @@ -381,6 +381,7 @@ function $HttpProvider() { * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5 * requests with credentials} for more information. + * - **useXDomain** 0 `{boolean}` - use XDomainRequest in IE requests * * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the * standard `then` method and two http specific methods: `success` and `error`. The `then` @@ -697,7 +698,7 @@ function $HttpProvider() { // if we won't have the response in cache, send the request to the backend if (!cachedResp) { $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, - config.withCredentials); + config.withCredentials, config.useXDomain || $http.defaults.useXDomain); } return promise; diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index 0a12aa23b4a5..36b8a50a32e1 100644 --- a/src/ng/httpBackend.js +++ b/src/ng/httpBackend.js @@ -3,7 +3,7 @@ var XHR = window.XMLHttpRequest || function() { 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; /** @@ -25,14 +25,14 @@ var XHR = window.XMLHttpRequest || function() { */ function $HttpBackendProvider() { this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) { - return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, + return createHttpBackend($browser, XHR, XDR, $browser.defer, $window.angular.callbacks, $document[0], $window.location.protocol.replace(':', '')); }]; } -function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) { +function createHttpBackend($browser, XHR, XDR, $browserDefer, callbacks, rawDocument, locationProtocol) { // TODO(vojta): fix the signature - return function(method, url, post, callback, headers, timeout, withCredentials) { + return function(method, url, post, callback, headers, timeout, withCredentials, useXDomain) { $browser.$$incOutstandingRequestCount(); url = url || $browser.url(); @@ -44,43 +44,80 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, 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 xhr = new XHR(); - xhr.open(method, url, true); - forEach(headers, function(value, key) { - if (value) xhr.setRequestHeader(key, value); - }); - + if (callbacks[callbackId].data) { + completeRequest(callback, 200, callbacks[callbackId].data); + } else { + completeRequest(callback, -2); + } + delete callbacks[callbackId]; + }); + } else { var status; + if (useXDomain && 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); + }; - // 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()); + 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); } - }; - if (withCredentials) { - xhr.withCredentials = true; - } + } else { + var xhr = new XHR(); + xhr.open(method, url, true); + + 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 || ''); + xhr.send(post || ''); + + if (timeout > 0) { + $browserDefer(function() { + status = -1; + xhr.abort(); + }, timeout); + } - if (timeout > 0) { - $browserDefer(function() { - status = -1; - xhr.abort(); - }, timeout); } } @@ -93,7 +130,7 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, status = (protocol == 'file') ? (response ? 200 : 404) : status; // normalize IE bug (http://bugs.jquery.com/ticket/1450) - status = status == 1223 ? 204 : status; + status = status == 1223 ? 204 : status; callback(status, response, headersString); $browser.$$completeOutstandingRequest(noop); diff --git a/src/ngResource/resource.js b/src/ngResource/resource.js index 5bf3e07a0757..5eb52c49055f 100644 --- a/src/ngResource/resource.js +++ b/src/ngResource/resource.js @@ -362,7 +362,8 @@ angular.module('ngResource', ['ng']). $http({ method: action.method, url: route.url(extend({}, extractParams(data), action.params || {}, params)), - data: data + data: data, + useXDomain: $http.defaults.useXDomain || false }).then(function(response) { var data = response.data; diff --git a/test/ng/httpBackendSpec.js b/test/ng/httpBackendSpec.js index 06b63c3c8c8d..99b80d2a5769 100644 --- a/test/ng/httpBackendSpec.js +++ b/test/ng/httpBackendSpec.js @@ -1,7 +1,7 @@ describe('$httpBackend', function() { var $backend, $browser, callbacks, - xhr, fakeDocument, callback; + xhr, xdr, fakeDocument, callback; // TODO(vojta): should be replaced by $defer mock function fakeTimeout(fn, delay) { @@ -38,7 +38,7 @@ describe('$httpBackend', function() { }) } }; - $backend = createHttpBackend($browser, MockXhr, fakeTimeout, callbacks, fakeDocument); + $backend = createHttpBackend($browser, MockXhr, MockXhr, fakeTimeout, callbacks, fakeDocument); callback = jasmine.createSpy('done'); })); @@ -234,7 +234,7 @@ describe('$httpBackend', function() { it('should convert 0 to 200 if content', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'http'); + $backend = createHttpBackend($browser, MockXhr, null, null, null, null, 'http'); $backend('GET', 'file:///whatever/index.html', null, callback); respond(0, 'SOME CONTENT'); @@ -245,7 +245,7 @@ describe('$httpBackend', function() { it('should convert 0 to 200 if content - relative url', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'file'); + $backend = createHttpBackend($browser, MockXhr, null, null, null, null, 'file'); $backend('GET', '/whatever/index.html', null, callback); respond(0, 'SOME CONTENT'); @@ -256,7 +256,7 @@ describe('$httpBackend', function() { it('should convert 0 to 404 if no content', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'http'); + $backend = createHttpBackend($browser, MockXhr, null, null, null, null, 'http'); $backend('GET', 'file:///whatever/index.html', null, callback); respond(0, ''); @@ -267,7 +267,7 @@ describe('$httpBackend', function() { it('should convert 0 to 200 if content - relative url', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'file'); + $backend = createHttpBackend($browser, MockXhr, null, null, null, null, 'file'); $backend('GET', '/whatever/index.html', null, callback); respond(0, ''); @@ -276,5 +276,4 @@ describe('$httpBackend', function() { expect(callback.mostRecentCall.args[0]).toBe(404); }); }); -}); - +}); \ No newline at end of file