Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 6a02655

Browse files
committed
fixup! set correct xhrStatus for xhr.abort() and non-timeout promise in http.timeout
1 parent 904cc39 commit 6a02655

File tree

4 files changed

+64
-14
lines changed

4 files changed

+64
-14
lines changed

src/ng/httpBackend.js

+19-10
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
7070
} else {
7171

7272
var xhr = createXhr(method, url);
73+
var abortedByTimeout = false;
7374

7475
xhr.open(method, url, true);
7576
forEach(headers, function(value, key) {
@@ -110,7 +111,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
110111
};
111112

112113
var requestAborted = function() {
113-
completeRequest(callback, -1, null, null, '', 'abort');
114+
completeRequest(callback, -1, null, null, '', abortedByTimeout ? 'timeout' : 'abort');
114115
};
115116

116117
var requestTimeout = function() {
@@ -121,11 +122,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
121122

122123
xhr.onerror = requestError;
123124
xhr.ontimeout = requestTimeout;
124-
125-
// The timeout behavior follows standard XMLHttpRequest logic.
126-
// xhr.timeout = ontimeout (numerical timeout or $timeout)
127-
// xhr.abort() = onabort (resolving a promise)
128-
xhr.onabort = timeout > 0 || (timeout && timeout.$$timeoutId >= 0) ? requestTimeout : requestAborted;
125+
xhr.onabort = requestAborted;
129126

130127
forEach(eventHandlers, function(value, key) {
131128
xhr.addEventListener(key, value);
@@ -159,14 +156,26 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
159156
xhr.send(isUndefined(post) ? null : post);
160157
}
161158

159+
// Since we are using xhr.abort() when a request times out, we have to set a flag that
160+
// indicates to onabort if the request timed out or was aborted
161+
//
162+
// http.timeout = numerical timeout timeout
163+
// http.timeout = $timeout timeout
164+
// http.timeout = promise abort
165+
// xhr.abort() abort (The xhr object is normally inaccessible, but
166+
// can be exposed with the xhrFactory)
162167
if (timeout > 0) {
163-
var timeoutId = $browserDefer(timeoutRequest, timeout);
168+
var timeoutId = $browserDefer(function() {
169+
timeoutRequest('timeout');
170+
}, timeout);
164171
} else if (isPromiseLike(timeout)) {
165-
timeout.then(timeoutRequest);
172+
timeout.then(function() {
173+
timeoutRequest(isDefined(timeout.$$timeoutId) ? 'timeout' : 'abort');
174+
});
166175
}
167176

168-
169-
function timeoutRequest() {
177+
function timeoutRequest(reason) {
178+
abortedByTimeout = reason === 'timeout';
170179
if (jsonpDone) {
171180
jsonpDone();
172181
}

src/ngMock/angular-mocks.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -2114,7 +2114,11 @@ function MockXhr() {
21142114
return lines.join('\n');
21152115
};
21162116

2117-
this.abort = angular.noop;
2117+
this.abort = function() {
2118+
if (isFunction(this.onabort)) {
2119+
this.onabort();
2120+
};
2121+
};
21182122

21192123
// This section simulates the events on a real XHR object (and the upload object)
21202124
// When we are testing $httpBackend (inside the AngularJS project) we make partial use of this

test/ng/httpBackendSpec.js

+38-3
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ describe('$httpBackend', function() {
244244
expect(callback).toHaveBeenCalledOnce();
245245
});
246246

247-
it('should abort request on timeout', function() {
247+
it('should abort request on numerical timeout', function() {
248248
callback.and.callFake(function(status, response) {
249249
expect(status).toBe(-1);
250250
});
@@ -264,9 +264,10 @@ describe('$httpBackend', function() {
264264
});
265265

266266

267-
it('should abort request on timeout promise resolution', inject(function($timeout) {
268-
callback.and.callFake(function(status, response) {
267+
it('should abort request on $timeout promise resolution', inject(function($timeout) {
268+
callback.and.callFake(function(status, response, headers, statusText, xhrStatus) {
269269
expect(status).toBe(-1);
270+
expect(xhrStatus).toBe('timeout');
270271
});
271272

272273
$backend('GET', '/url', null, callback, {}, $timeout(noop, 2000));
@@ -300,6 +301,24 @@ describe('$httpBackend', function() {
300301
}));
301302

302303

304+
it('should abort request on canceler promise resolution', inject(function($q, $browser) {
305+
var canceler = $q.defer();
306+
307+
callback.and.callFake(function(status, response, headers, statusText, xhrStatus) {
308+
expect(status).toBe(-1);
309+
expect(xhrStatus).toBe('abort');
310+
});
311+
312+
$backend('GET', '/url', null, callback, {}, canceler.promise);
313+
xhr = MockXhr.$$lastInstance;
314+
315+
canceler.resolve();
316+
$browser.defer.flush();
317+
318+
expect(callback).toHaveBeenCalledOnce();
319+
}));
320+
321+
303322
it('should cancel timeout on completion', function() {
304323
callback.and.callFake(function(status, response) {
305324
expect(status).toBe(200);
@@ -320,6 +339,22 @@ describe('$httpBackend', function() {
320339
});
321340

322341

342+
it('should call callback with xhrStatus "abort" on explicit xhr.abort() when $timeout is set', inject(function($timeout) {
343+
callback.and.callFake(function(status, response, headers, statusText, xhrStatus) {
344+
expect(status).toBe(-1);
345+
expect(xhrStatus).toBe('abort');
346+
});
347+
348+
$backend('GET', '/url', null, callback, {}, $timeout(noop, 2000));
349+
xhr = MockXhr.$$lastInstance;
350+
spyOn(xhr, 'abort').and.callThrough();
351+
352+
xhr.abort();
353+
354+
expect(callback).toHaveBeenCalledOnce();
355+
}));
356+
357+
323358
it('should set withCredentials', function() {
324359
$backend('GET', '/some.url', null, callback, {}, null, true);
325360
expect(MockXhr.$$lastInstance.withCredentials).toBe(true);

test/ng/httpSpec.js

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
/* global MockXhr: false */
44

5+
// The http specs run against the mocked httpBackend
6+
57
describe('$http', function() {
68

79
var callback, mockedCookies;

0 commit comments

Comments
 (0)