fix(http): emit error on XMLHttpRequest abort event (#40767)
Before this change, when Google Chrome cancels a XMLHttpRequest, an Observable of the response never finishes. This happens, for example, when you put your computer to sleep or just press Ctrl+S to save the browser page. After this commit, if request is canceled or aborted an appropriate Observable will be completed with an error. Fixes #22324 PR Close #40767
This commit is contained in:
parent
ddff6b63d7
commit
38972653fa
|
@ -312,6 +312,7 @@ export class HttpXhrBackend implements HttpBackend {
|
|||
xhr.addEventListener('load', onLoad);
|
||||
xhr.addEventListener('error', onError);
|
||||
xhr.addEventListener('timeout', onError);
|
||||
xhr.addEventListener('abort', onError);
|
||||
|
||||
// Progress events are only enabled if requested.
|
||||
if (req.reportProgress) {
|
||||
|
@ -333,6 +334,7 @@ export class HttpXhrBackend implements HttpBackend {
|
|||
return () => {
|
||||
// On a cancellation, remove all registered event listeners.
|
||||
xhr.removeEventListener('error', onError);
|
||||
xhr.removeEventListener('abort', onError);
|
||||
xhr.removeEventListener('load', onLoad);
|
||||
xhr.removeEventListener('timeout', onError);
|
||||
if (req.reportProgress) {
|
||||
|
|
|
@ -55,6 +55,7 @@ export class MockXMLHttpRequest {
|
|||
listeners: {
|
||||
error?: (event: ErrorEvent) => void,
|
||||
timeout?: (event: ErrorEvent) => void,
|
||||
abort?: () => void,
|
||||
load?: () => void,
|
||||
progress?: (event: ProgressEvent) => void,
|
||||
uploadProgress?: (event: ProgressEvent) => void,
|
||||
|
@ -71,12 +72,13 @@ export class MockXMLHttpRequest {
|
|||
this.body = body;
|
||||
}
|
||||
|
||||
addEventListener(event: 'error'|'timeout'|'load'|'progress'|'uploadProgress', handler: Function):
|
||||
void {
|
||||
addEventListener(
|
||||
event: 'error'|'timeout'|'load'|'progress'|'uploadProgress'|'abort',
|
||||
handler: Function): void {
|
||||
this.listeners[event] = handler as any;
|
||||
}
|
||||
|
||||
removeEventListener(event: 'error'|'timeout'|'load'|'progress'|'uploadProgress'): void {
|
||||
removeEventListener(event: 'error'|'timeout'|'load'|'progress'|'uploadProgress'|'abort'): void {
|
||||
delete this.listeners[event];
|
||||
}
|
||||
|
||||
|
@ -137,6 +139,12 @@ export class MockXMLHttpRequest {
|
|||
}
|
||||
}
|
||||
|
||||
mockAbortEvent(): void {
|
||||
if (this.listeners.abort) {
|
||||
this.listeners.abort();
|
||||
}
|
||||
}
|
||||
|
||||
abort() {
|
||||
this.mockAborted = true;
|
||||
}
|
||||
|
|
|
@ -173,6 +173,13 @@ const XSSI_PREFIX = ')]}\'\n';
|
|||
factory.mock.abort = abort;
|
||||
factory.mock.mockFlush(HttpStatusCode.Ok, 'OK', 'Done');
|
||||
});
|
||||
it('emits an error when browser cancels a request', done => {
|
||||
backend.handle(TEST_POST).subscribe(undefined, (err: HttpErrorResponse) => {
|
||||
expect(err instanceof HttpErrorResponse).toBe(true);
|
||||
done();
|
||||
});
|
||||
factory.mock.mockAbortEvent();
|
||||
});
|
||||
describe('progress events', () => {
|
||||
it('are emitted for download progress', done => {
|
||||
backend.handle(TEST_POST.clone({reportProgress: true}))
|
||||
|
|
Loading…
Reference in New Issue