(request: HttpRequest<any>)
| 82 | private readonly maxResponseSize = inject(HTTP_FETCH_MAX_RESPONSE_SIZE); |
| 83 | |
| 84 | handle(request: HttpRequest<any>): Observable<HttpEvent<any>> { |
| 85 | return new Observable((observer) => { |
| 86 | const aborter = new AbortController(); |
| 87 | let done = false; |
| 88 | const wrappedObserver: Observer<HttpEvent<any>> = { |
| 89 | next: (val) => { |
| 90 | if (val.type === HttpEventType.Response) { |
| 91 | done = true; |
| 92 | } |
| 93 | observer.next(val); |
| 94 | }, |
| 95 | error: (err) => { |
| 96 | done = true; |
| 97 | observer.error(err); |
| 98 | }, |
| 99 | complete: () => { |
| 100 | done = true; |
| 101 | observer.complete(); |
| 102 | }, |
| 103 | }; |
| 104 | |
| 105 | this.doRequest(request, aborter.signal, wrappedObserver).then(noop, (error) => |
| 106 | wrappedObserver.error(new HttpErrorResponse({error})), |
| 107 | ); |
| 108 | |
| 109 | let timeoutId: ReturnType<typeof setTimeout> | undefined; |
| 110 | if (request.timeout) { |
| 111 | // TODO: Replace with AbortSignal.any([aborter.signal, AbortSignal.timeout(request.timeout)]) |
| 112 | // when AbortSignal.any support is Baseline widely available (NET nov. 2026) |
| 113 | timeoutId = this.ngZone.runOutsideAngular(() => |
| 114 | setTimeout(() => { |
| 115 | if (!aborter.signal.aborted) { |
| 116 | aborter.abort(new DOMException('signal timed out', 'TimeoutError')); |
| 117 | } |
| 118 | }, request.timeout), |
| 119 | ); |
| 120 | } |
| 121 | |
| 122 | return () => { |
| 123 | if (timeoutId !== undefined) { |
| 124 | clearTimeout(timeoutId); |
| 125 | } |
| 126 | if (!done && !aborter.signal.aborted) { |
| 127 | aborter.abort(); |
| 128 | } |
| 129 | }; |
| 130 | }); |
| 131 | } |
| 132 | |
| 133 | private async doRequest( |
| 134 | request: HttpRequest<any>, |
nothing calls this directly
no test coverage detected