mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(http): cancel oversized fetch response bodies
Cancel the unread response body before reporting NG02825 when its declared Content-Length exceeds the configured buffer limit. Without cancellation, SSR can finish while the underlying connection remains open.
Add regression coverage for the declared-length rejection path.
(cherry picked from commit 1a006a8f97)
This commit is contained in:
committed by
Jessica Janiuk
parent
5def30e945
commit
0cd635e9e2
@@ -191,6 +191,7 @@ export class FetchBackend implements HttpBackend {
|
||||
Number.isFinite(contentLengthValue) &&
|
||||
contentLengthValue > this.maxResponseSize
|
||||
) {
|
||||
await response.body.cancel();
|
||||
throwBodyTooLargeError(this.maxResponseSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -708,6 +708,19 @@ describe('FetchBackend', () => {
|
||||
expect(infiniteStreamFactory.cancelCount).toBe(1);
|
||||
});
|
||||
|
||||
it('cancels an unread response stream when the declared size exceeds the limit', async () => {
|
||||
infiniteStreamFactory.declaredContentLength = 2049;
|
||||
|
||||
const req = new HttpRequest('GET', '/test', {responseType: 'text'});
|
||||
const events = await trackEvents(backend.handle(req));
|
||||
const error = events[1] as HttpErrorResponse;
|
||||
|
||||
expect(events.length).toBe(2);
|
||||
expect(error instanceof HttpErrorResponse).toBeTrue();
|
||||
expect(error.error.code).toBe(RuntimeErrorCode.FETCH_RESPONSE_BODY_TOO_LARGE);
|
||||
expect(infiniteStreamFactory.cancelCount).toBe(1);
|
||||
});
|
||||
|
||||
it('allows disabling the size limit via dependency injection', async () => {
|
||||
TestBed.resetTestingModule();
|
||||
TestBed.configureTestingModule({
|
||||
@@ -854,6 +867,7 @@ class MockFetchRequest {
|
||||
|
||||
class InfiniteStreamFetchFactory extends FetchFactory {
|
||||
public cancelCount = 0;
|
||||
public declaredContentLength?: number;
|
||||
|
||||
override fetch = async (_input: RequestInfo | URL, _init?: RequestInit): Promise<Response> => {
|
||||
const stream = new ReadableStream<Uint8Array>({
|
||||
@@ -868,7 +882,12 @@ class InfiniteStreamFetchFactory extends FetchFactory {
|
||||
return new Response(stream, {
|
||||
status: HttpStatusCode.Ok,
|
||||
statusText: 'OK',
|
||||
headers: {'Content-Type': 'text/plain'},
|
||||
headers: {
|
||||
'Content-Type': 'text/plain',
|
||||
...(this.declaredContentLength === undefined
|
||||
? {}
|
||||
: {'Content-Length': `${this.declaredContentLength}`}),
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -885,7 +904,7 @@ class FiniteChunkFetchFactory extends FetchFactory {
|
||||
return new Response(stream, {
|
||||
status: HttpStatusCode.Ok,
|
||||
statusText: 'OK',
|
||||
headers: {'Content-Type': 'text/plain'},
|
||||
headers: {'Content-Type': 'text/plain', 'Content-Length': '2'},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user