fix(service-worker): correctly handle relative base href (#37922)

In some cases, it is useful to use a relative base href in the app (e.g.
when an app has to be accessible on different URLs, such as on an
intranet and the internet - see #25055 for a related discussion).

Previously, the Angular ServiceWorker was not able to handle relative
base hrefs (for example when building the with `--base-href=./`).

This commit fixes this by normalizing all URLs from the ServiceWorker
configuration wrt the ServiceWorker's scope.

Fixes #25055

PR Close #37922
This commit is contained in:
George Kalpakas
2020-07-06 16:55:38 +03:00
committed by atscott
parent 667aba7508
commit d19ef6534f
5 changed files with 251 additions and 23 deletions

View File

@ -131,7 +131,10 @@ function matches(file: string, patterns: {positive: boolean, regex: RegExp}[]):
function urlToRegex(url: string, baseHref: string, literalQuestionMark?: boolean): string {
if (!url.startsWith('/') && url.indexOf('://') === -1) {
url = joinUrls(baseHref, url);
// Prefix relative URLs with `baseHref`.
// Strip a leading `.` from a relative `baseHref` (e.g. `./foo/`), since it would result in an
// incorrect regex (matching a literal `.`).
url = joinUrls(baseHref.replace(/^\.(?=\/)/, ''), url);
}
return globToRegex(url, literalQuestionMark);

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Generator} from '../src/generator';
import {Generator, processNavigationUrls} from '../src/generator';
import {AssetGroup} from '../src/in';
import {MockFilesystem} from '../testing/mock';
@ -255,4 +255,56 @@ describe('Generator', () => {
},
});
});
describe('processNavigationUrls()', () => {
const customNavigationUrls = [
'https://host/positive/external/**',
'!https://host/negative/external/**',
'/positive/absolute/**',
'!/negative/absolute/**',
'positive/relative/**',
'!negative/relative/**',
];
it('uses the default `navigationUrls` if not provided', () => {
expect(processNavigationUrls('/')).toEqual([
{positive: true, regex: '^\\/.*$'},
{positive: false, regex: '^\\/(?:.+\\/)?[^/]*\\.[^/]*$'},
{positive: false, regex: '^\\/(?:.+\\/)?[^/]*__[^/]*$'},
{positive: false, regex: '^\\/(?:.+\\/)?[^/]*__[^/]*\\/.*$'},
]);
});
it('prepends `baseHref` to relative URL patterns only', () => {
expect(processNavigationUrls('/base/href/', customNavigationUrls)).toEqual([
{positive: true, regex: '^https:\\/\\/host\\/positive\\/external\\/.*$'},
{positive: false, regex: '^https:\\/\\/host\\/negative\\/external\\/.*$'},
{positive: true, regex: '^\\/positive\\/absolute\\/.*$'},
{positive: false, regex: '^\\/negative\\/absolute\\/.*$'},
{positive: true, regex: '^\\/base\\/href\\/positive\\/relative\\/.*$'},
{positive: false, regex: '^\\/base\\/href\\/negative\\/relative\\/.*$'},
]);
});
it('strips a leading single `.` from a relative `baseHref`', () => {
expect(processNavigationUrls('./relative/base/href/', customNavigationUrls)).toEqual([
{positive: true, regex: '^https:\\/\\/host\\/positive\\/external\\/.*$'},
{positive: false, regex: '^https:\\/\\/host\\/negative\\/external\\/.*$'},
{positive: true, regex: '^\\/positive\\/absolute\\/.*$'},
{positive: false, regex: '^\\/negative\\/absolute\\/.*$'},
{positive: true, regex: '^\\/relative\\/base\\/href\\/positive\\/relative\\/.*$'},
{positive: false, regex: '^\\/relative\\/base\\/href\\/negative\\/relative\\/.*$'},
]);
// We can't correctly handle double dots in `baseHref`, so leave them as literal matches.
expect(processNavigationUrls('../double/dots/', customNavigationUrls)).toEqual([
{positive: true, regex: '^https:\\/\\/host\\/positive\\/external\\/.*$'},
{positive: false, regex: '^https:\\/\\/host\\/negative\\/external\\/.*$'},
{positive: true, regex: '^\\/positive\\/absolute\\/.*$'},
{positive: false, regex: '^\\/negative\\/absolute\\/.*$'},
{positive: true, regex: '^\\.\\.\\/double\\/dots\\/positive\\/relative\\/.*$'},
{positive: false, regex: '^\\.\\.\\/double\\/dots\\/negative\\/relative\\/.*$'},
]);
});
});
});