From 94a0d669b603bbfa1de22f5ce2f7479579fb6cfd Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Thu, 2 Jun 2022 17:16:19 -0700 Subject: [PATCH] browser(firefox): expose Response.fromServiceWorker (#14606) This property is "true" when network response was fulfilled by the service worker. --- browser_patches/firefox-beta/BUILD_NUMBER | 4 ++-- .../firefox-beta/juggler/NetworkObserver.js | 14 ++++++++++++++ .../firefox-beta/juggler/protocol/Protocol.js | 1 + browser_patches/firefox/BUILD_NUMBER | 4 ++-- browser_patches/firefox/juggler/NetworkObserver.js | 14 ++++++++++++++ .../firefox/juggler/protocol/Protocol.js | 1 + tests/page/interception.spec.ts | 10 +++++++++- 7 files changed, 43 insertions(+), 5 deletions(-) diff --git a/browser_patches/firefox-beta/BUILD_NUMBER b/browser_patches/firefox-beta/BUILD_NUMBER index 58ff75ee61..2685268958 100644 --- a/browser_patches/firefox-beta/BUILD_NUMBER +++ b/browser_patches/firefox-beta/BUILD_NUMBER @@ -1,2 +1,2 @@ -1328 -Changed: yurys@chromium.org Wed 01 Jun 2022 08:28:56 PM PDT +1329 +Changed: dgozman@gmail.com Thu Jun 2 16:19:39 PDT 2022 diff --git a/browser_patches/firefox-beta/juggler/NetworkObserver.js b/browser_patches/firefox-beta/juggler/NetworkObserver.js index fa7feead44..7f59f311e1 100644 --- a/browser_patches/firefox-beta/juggler/NetworkObserver.js +++ b/browser_patches/firefox-beta/juggler/NetworkObserver.js @@ -533,6 +533,9 @@ class NetworkRequest { // remoteAddress is not defined for cached requests. } + const fromServiceWorker = this._networkObserver._channelIdsFulfilledByServiceWorker.has(this.requestId); + this._networkObserver._channelIdsFulfilledByServiceWorker.delete(this.requestId); + pageNetwork.emit(PageNetwork.Events.Response, { requestId: this.requestId, securityDetails: getSecurityDetails(this.httpChannel), @@ -543,6 +546,7 @@ class NetworkRequest { status, statusText, timing, + fromServiceWorker, }, this._frameId); } @@ -591,6 +595,7 @@ class NetworkObserver { this._channelToRequest = new Map(); // http channel -> network request this._expectedRedirect = new Map(); // expected redirect channel id (string) -> network request + this._channelIdsFulfilledByServiceWorker = new Set(); // http channel ids that were fulfilled by service worker const protocolProxyService = Cc['@mozilla.org/network/protocol-proxy-service;1'].getService(); this._channelProxyFilter = { @@ -636,6 +641,7 @@ class NetworkObserver { helper.addObserver(this._onResponse.bind(this, false /* fromCache */), 'http-on-examine-response'), helper.addObserver(this._onResponse.bind(this, true /* fromCache */), 'http-on-examine-cached-response'), helper.addObserver(this._onResponse.bind(this, true /* fromCache */), 'http-on-examine-merged-response'), + helper.addObserver(this._onServiceWorkerResponse.bind(this), 'service-worker-synthesized-response'), ]; } @@ -700,6 +706,14 @@ class NetworkObserver { request._sendOnResponse(fromCache); } + _onServiceWorkerResponse(channel, topic) { + if (!(channel instanceof Ci.nsIHttpChannel)) + return; + const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); + const channelId = httpChannel.channelId + ''; + this._channelIdsFulfilledByServiceWorker.add(channelId); + } + dispose() { this._activityDistributor.removeObserver(this); const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); diff --git a/browser_patches/firefox-beta/juggler/protocol/Protocol.js b/browser_patches/firefox-beta/juggler/protocol/Protocol.js index afb153d2f6..55ed6f819b 100644 --- a/browser_patches/firefox-beta/juggler/protocol/Protocol.js +++ b/browser_patches/firefox-beta/juggler/protocol/Protocol.js @@ -501,6 +501,7 @@ const Network = { statusText: t.String, headers: t.Array(networkTypes.HTTPHeader), timing: networkTypes.ResourceTiming, + fromServiceWorker: t.Boolean, }, 'requestFinished': { requestId: t.String, diff --git a/browser_patches/firefox/BUILD_NUMBER b/browser_patches/firefox/BUILD_NUMBER index f2cafdf7fb..2f1b374dff 100644 --- a/browser_patches/firefox/BUILD_NUMBER +++ b/browser_patches/firefox/BUILD_NUMBER @@ -1,2 +1,2 @@ -1326 -Changed: yurys@chromium.org Wed 01 Jun 2022 08:27:21 PM PDT +1327 +Changed: dgozman@gmail.com Thu Jun 2 16:19:39 PDT 2022 diff --git a/browser_patches/firefox/juggler/NetworkObserver.js b/browser_patches/firefox/juggler/NetworkObserver.js index fa7feead44..7f59f311e1 100644 --- a/browser_patches/firefox/juggler/NetworkObserver.js +++ b/browser_patches/firefox/juggler/NetworkObserver.js @@ -533,6 +533,9 @@ class NetworkRequest { // remoteAddress is not defined for cached requests. } + const fromServiceWorker = this._networkObserver._channelIdsFulfilledByServiceWorker.has(this.requestId); + this._networkObserver._channelIdsFulfilledByServiceWorker.delete(this.requestId); + pageNetwork.emit(PageNetwork.Events.Response, { requestId: this.requestId, securityDetails: getSecurityDetails(this.httpChannel), @@ -543,6 +546,7 @@ class NetworkRequest { status, statusText, timing, + fromServiceWorker, }, this._frameId); } @@ -591,6 +595,7 @@ class NetworkObserver { this._channelToRequest = new Map(); // http channel -> network request this._expectedRedirect = new Map(); // expected redirect channel id (string) -> network request + this._channelIdsFulfilledByServiceWorker = new Set(); // http channel ids that were fulfilled by service worker const protocolProxyService = Cc['@mozilla.org/network/protocol-proxy-service;1'].getService(); this._channelProxyFilter = { @@ -636,6 +641,7 @@ class NetworkObserver { helper.addObserver(this._onResponse.bind(this, false /* fromCache */), 'http-on-examine-response'), helper.addObserver(this._onResponse.bind(this, true /* fromCache */), 'http-on-examine-cached-response'), helper.addObserver(this._onResponse.bind(this, true /* fromCache */), 'http-on-examine-merged-response'), + helper.addObserver(this._onServiceWorkerResponse.bind(this), 'service-worker-synthesized-response'), ]; } @@ -700,6 +706,14 @@ class NetworkObserver { request._sendOnResponse(fromCache); } + _onServiceWorkerResponse(channel, topic) { + if (!(channel instanceof Ci.nsIHttpChannel)) + return; + const httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); + const channelId = httpChannel.channelId + ''; + this._channelIdsFulfilledByServiceWorker.add(channelId); + } + dispose() { this._activityDistributor.removeObserver(this); const registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); diff --git a/browser_patches/firefox/juggler/protocol/Protocol.js b/browser_patches/firefox/juggler/protocol/Protocol.js index afb153d2f6..55ed6f819b 100644 --- a/browser_patches/firefox/juggler/protocol/Protocol.js +++ b/browser_patches/firefox/juggler/protocol/Protocol.js @@ -501,6 +501,7 @@ const Network = { statusText: t.String, headers: t.Array(networkTypes.HTTPHeader), timing: networkTypes.ResourceTiming, + fromServiceWorker: t.Boolean, }, 'requestFinished': { requestId: t.String, diff --git a/tests/page/interception.spec.ts b/tests/page/interception.spec.ts index d01c1b93fc..19f114e990 100644 --- a/tests/page/interception.spec.ts +++ b/tests/page/interception.spec.ts @@ -33,7 +33,7 @@ it('should work with navigation @smoke', async ({ page, server }) => { expect(requests.get('style.css').isNavigationRequest()).toBe(false); }); -it('should intercept after a service worker', async ({ page, server, isAndroid, isElectron }) => { +it('should intercept after a service worker', async ({ page, server, browserName, isAndroid, isElectron }) => { it.skip(isAndroid); it.skip(isElectron); @@ -61,6 +61,14 @@ it('should intercept after a service worker', async ({ page, server, isAndroid, // Page route is not applied to service worker initiated fetch. const nonInterceptedResponse = await page.evaluate(() => window['fetchDummy']('passthrough')); expect(nonInterceptedResponse).toBe('FAILURE: Not Found'); + + // Firefox does not want to fetch the redirect for some reason. + if (browserName !== 'firefox') { + // Page route is not applied to service worker initiated fetch with redirect. + server.setRedirect('/serviceworkers/fetchdummy/passthrough', '/simple.json'); + const redirectedResponse = await page.evaluate(() => window['fetchDummy']('passthrough')); + expect(redirectedResponse).toBe('{"foo": "bar"}\n'); + } }); it('should work with glob', async () => {