fix(service-worker): preserve redirect policy on reconstructed asset requests

Preserve the redirect mode when rebuilding asset requests in newRequestWithMetadata(). This keeps explicit redirect:error semantics intact across service-worker redirect handling.

Update the worker test mocks to model redirect defaults correctly and add focused regression coverage for redirected lazy assets with redirect:error.
This commit is contained in:
Yenya030
2026-03-06 11:14:14 -06:00
committed by Alex Rickabaugh
parent 591fa53bd2
commit 5fdfd8a998
4 changed files with 21 additions and 4 deletions
+5 -2
View File
@@ -501,7 +501,7 @@ export abstract class AssetGroup {
* Create a new `Request` based on the specified URL and `RequestInit` options, preserving only
* metadata that are known to be safe.
*
* Currently, only headers are preserved.
* Currently, only headers and redirect policy are preserved.
*
* NOTE:
* Things like credential inclusion are intentionally omitted to avoid issues with opaque
@@ -512,7 +512,10 @@ export abstract class AssetGroup {
* https://github.com/angular/angular/issues/41931#issuecomment-1227601347
*/
private newRequestWithMetadata(url: string, options: RequestInit): Request {
return this.adapter.newRequest(url, {headers: options.headers});
return this.adapter.newRequest(url, {
headers: options.headers,
redirect: options.redirect,
});
}
/**
@@ -1686,6 +1686,12 @@ import {envIsSupported} from '../testing/utils';
expect(redirectReq.mode).toBe('cors'); // The default value.
expect((redirectReq as any).unknownOption).toBeUndefined();
});
it('does not follow redirects when redirect policy is error', async () => {
await expectAsync(
makeRequest(scope, '/lazy/redirected.txt', undefined, {redirect: 'error'}),
).toBeRejected();
});
});
});
@@ -115,7 +115,7 @@ export class MockRequest extends MockBody implements Request {
readonly keepalive: boolean = true;
readonly method: string = 'GET';
readonly mode: RequestMode = 'cors';
readonly redirect: RequestRedirect = 'error';
readonly redirect: RequestRedirect = 'follow';
readonly referrer: string = '';
readonly referrerPolicy: ReferrerPolicy = 'no-referrer';
readonly signal: AbortSignal = null as any;
@@ -153,6 +153,9 @@ export class MockRequest extends MockBody implements Request {
if (init.method !== undefined) {
this.method = init.method;
}
if (init.redirect !== undefined) {
this.redirect = init.redirect;
}
if (init.destination !== undefined) {
this.destination = init.destination;
}
@@ -167,6 +170,7 @@ export class MockRequest extends MockBody implements Request {
mode: this.mode,
credentials: this.credentials,
headers: this.headers,
redirect: this.redirect,
});
}
}
@@ -165,7 +165,11 @@ export class MockServerState {
}
const url = req.url.split('?')[0];
if (this.resources.has(url)) {
return this.resources.get(url)!.clone();
const response = this.resources.get(url)!.clone();
if ((response as any).redirected && req.redirect === 'error') {
throw new Error('Redirect disallowed by request policy.');
}
return response;
}
if (this.errors.has(url)) {
throw new Error('Intentional failure!');