diff --git a/src/ng/http.js b/src/ng/http.js index b8d350ea3143..dca49b892dac 100644 --- a/src/ng/http.js +++ b/src/ng/http.js @@ -1268,9 +1268,9 @@ function $HttpProvider() { } else { // serving from cache if (isArray(cachedResp)) { - resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]); + resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3], cachedResp[4]); } else { - resolvePromise(cachedResp, 200, {}, 'OK'); + resolvePromise(cachedResp, 200, {}, 'OK', 'success'); } } } else { @@ -1327,10 +1327,10 @@ function $HttpProvider() { * - resolves the raw $http promise * - calls $apply */ - function done(status, response, headersString, statusText) { + function done(status, response, headersString, statusText, xhrStatus) { if (cache) { if (isSuccess(status)) { - cache.put(url, [status, response, parseHeaders(headersString), statusText]); + cache.put(url, [status, response, parseHeaders(headersString), statusText, xhrStatus]); } else { // remove promise from the cache cache.remove(url); @@ -1338,7 +1338,7 @@ function $HttpProvider() { } function resolveHttpPromise() { - resolvePromise(response, status, headersString, statusText); + resolvePromise(response, status, headersString, statusText, xhrStatus); } if (useApplyAsync) { @@ -1353,7 +1353,7 @@ function $HttpProvider() { /** * Resolves the raw $http promise. */ - function resolvePromise(response, status, headers, statusText) { + function resolvePromise(response, status, headers, statusText, xhrStatus) { //status: HTTP response status code, 0, -1 (aborted by timeout / promise) status = status >= -1 ? status : 0; @@ -1362,12 +1362,13 @@ function $HttpProvider() { status: status, headers: headersGetter(headers), config: config, - statusText: statusText + statusText: statusText, + xhrStatus: xhrStatus }); } function resolvePromiseWithResult(result) { - resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText); + resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText, result.xhrStatus); } function removePendingReq() { diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index 501c1de86c73..aaeb9def4388 100644 --- a/src/ng/httpBackend.js +++ b/src/ng/httpBackend.js @@ -64,7 +64,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc var jsonpDone = jsonpReq(url, callbackPath, function(status, text) { // jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING) var response = (status === 200) && callbacks.getResponse(callbackPath); - completeRequest(callback, status, response, '', text); + completeRequest(callback, status, response, '', text, ''); callbacks.removeCallback(callbackPath); }); } else { @@ -99,18 +99,27 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc status, response, xhr.getAllResponseHeaders(), - statusText); + statusText, + 'success'); }; var requestError = function() { // The response is always empty // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error - completeRequest(callback, -1, null, null, ''); + completeRequest(callback, -1, null, null, '', 'error'); + }; + + var requestAborted = function() { + completeRequest(callback, -1, null, null, '', 'abort'); + }; + + var requestTimedOut = function() { + completeRequest(callback, -1, null, null, '', 'timeout'); }; xhr.onerror = requestError; - xhr.onabort = requestError; - xhr.ontimeout = requestError; + xhr.onabort = requestAborted; + xhr.ontimeout = requestTimedOut; forEach(eventHandlers, function(value, key) { xhr.addEventListener(key, value); @@ -160,14 +169,14 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc } } - function completeRequest(callback, status, response, headersString, statusText) { + function completeRequest(callback, status, response, headersString, statusText, xhrStatus) { // cancel timeout and subsequent timeout promise resolution if (isDefined(timeoutId)) { $browserDefer.cancel(timeoutId); } jsonpDone = xhr = null; - callback(status, response, headersString, statusText); + callback(status, response, headersString, statusText, xhrStatus); } }; diff --git a/test/ng/httpBackendSpec.js b/test/ng/httpBackendSpec.js index fbc58072894f..f0f3a65d6dc8 100644 --- a/test/ng/httpBackendSpec.js +++ b/test/ng/httpBackendSpec.js @@ -155,11 +155,12 @@ describe('$httpBackend', function() { }); it('should not try to read response data when request is aborted', function() { - callback.and.callFake(function(status, response, headers, statusText) { + callback.and.callFake(function(status, response, headers, statusText, xhrStatus) { expect(status).toBe(-1); expect(response).toBe(null); expect(headers).toBe(null); expect(statusText).toBe(''); + expect(xhrStatus).toBe('abort'); }); $backend('GET', '/url', null, callback, {}, 2000); xhr = MockXhr.$$lastInstance; @@ -174,11 +175,12 @@ describe('$httpBackend', function() { }); it('should complete the request on timeout', function() { - callback.and.callFake(function(status, response, headers, statusText) { + callback.and.callFake(function(status, response, headers, statusText, xhrStatus) { expect(status).toBe(-1); expect(response).toBe(null); expect(headers).toBe(null); expect(statusText).toBe(''); + expect(xhrStatus).toBe('timeout'); }); $backend('GET', '/url', null, callback, {}); xhr = MockXhr.$$lastInstance; @@ -511,4 +513,3 @@ describe('$httpBackend', function() { }); }); }); -