From 2156beed0c198a0c46f6f5a373a68c3de40117ed Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Mon, 6 Jul 2020 16:55:35 +0300 Subject: [PATCH] fix(service-worker): correctly serve `ngsw/state` with a non-root SW scope (#37922) The Angular ServiceWorker can serve requests to a special virtual path, `ngsw/state`, showing [information about its internal state][1], which can be useful for debugging. Previously, this would only work if the ServiceWorker's [scope][2] was the root directory (`/`). Otherwise, (e.g. when building the app with `--baseHref=/some/path/`), the ServiceWorker would fail to detect a request to `/some/path/ngsw/state` as matching `ngsw/state` and would not serve it with the debugging information. This commit fixes it by ensuring that the ServiceWorker's scope is taken into account when detecting a request to `ngsw/state`. [1]: https://angular.io/guide/service-worker-devops#locating-and-analyzing-debugging-information [2]: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/scope Fixes #30505 PR Close #37922 --- packages/service-worker/worker/src/driver.ts | 4 ++- .../service-worker/worker/test/happy_spec.ts | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/service-worker/worker/src/driver.ts b/packages/service-worker/worker/src/driver.ts index 5377dc4ff2..e3585fee50 100644 --- a/packages/service-worker/worker/src/driver.ts +++ b/packages/service-worker/worker/src/driver.ts @@ -99,6 +99,8 @@ export class Driver implements Debuggable, UpdateSource { */ private loggedInvalidOnlyIfCachedRequest: boolean = false; + private ngswStatePath = this.adapter.parseUrl('ngsw/state', this.scope.registration.scope).path; + /** * A scheduler which manages a queue of tasks that need to be executed when the SW is * not doing any other work (not processing any other requests). @@ -184,7 +186,7 @@ export class Driver implements Debuggable, UpdateSource { } // The only thing that is served unconditionally is the debug page. - if (requestUrlObj.path === '/ngsw/state') { + if (requestUrlObj.path === this.ngswStatePath) { // Allow the debugger to handle the request, but don't affect SW state in any other way. event.respondWith(this.debugger.handleFetch(req)); return; diff --git a/packages/service-worker/worker/test/happy_spec.ts b/packages/service-worker/worker/test/happy_spec.ts index fbb3d84eeb..44b12a1880 100644 --- a/packages/service-worker/worker/test/happy_spec.ts +++ b/packages/service-worker/worker/test/happy_spec.ts @@ -893,6 +893,34 @@ describe('Driver', () => { expect(await scope.caches.keys()).not.toEqual([]); }); + describe('serving ngsw/state', () => { + it('should show debug info (when in NORMAL state)', async () => { + expect(await makeRequest(scope, '/ngsw/state')) + .toMatch(/^NGSW Debug Info:\n\nDriver state: NORMAL/); + }); + + it('should show debug info (when in EXISTING_CLIENTS_ONLY state)', async () => { + driver.state = DriverReadyState.EXISTING_CLIENTS_ONLY; + expect(await makeRequest(scope, '/ngsw/state')) + .toMatch(/^NGSW Debug Info:\n\nDriver state: EXISTING_CLIENTS_ONLY/); + }); + + it('should show debug info (when in SAFE_MODE state)', async () => { + driver.state = DriverReadyState.SAFE_MODE; + expect(await makeRequest(scope, '/ngsw/state')) + .toMatch(/^NGSW Debug Info:\n\nDriver state: SAFE_MODE/); + }); + + it('should show debug info when the scope is not root', async () => { + const newScope = + new SwTestHarnessBuilder('http://localhost/foo/bar/').withServerState(server).build(); + new Driver(newScope, newScope, new CacheDatabase(newScope, newScope)); + + expect(await makeRequest(newScope, '/foo/bar/ngsw/state')) + .toMatch(/^NGSW Debug Info:\n\nDriver state: NORMAL/); + }); + }); + describe('cache naming', () => { // Helpers const cacheKeysFor = (baseHref: string) =>