Repository: GoogleChrome/lighthouse
Pull request #9591 (2019-08-21 22:30:29)

misc: update favicon to new logo
I resized the logo to 32x32 and base64 encoded that.

This image shows 16x16, which is lower quality, but smaller ...the extra size from 32x32 is probably ndb

![tmpcomp](https://user-images.githubusercontent.com/4071474/63472910-790ad600-c428-11e9-9bac-13ca243cc578.png)



Patch:
diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js
index 71b13a002..c6fe6ce46 100644
--- a/lighthouse-core/gather/gather-runner.js
+++ b/lighthouse-core/gather/gather-runner.js
@@ -9,7 +9,7 @@ const log = require('lighthouse-logger');
 const manifestParser = require('../lib/manifest-parser.js');
 const stacksGatherer = require('../lib/stack-collector.js');
 const LHError = require('../lib/lh-error.js');
-const URL = require('../lib/url-shim.js');
+const NetworkAnalyzer = require('../lib/dependency-graph/simulator/network-analyzer.js');
 const NetworkRecorder = require('../lib/network-recorder.js');
 const constants = require('../config/constants.js');
 const i18n = require('../lib/i18n/i18n.js');
@@ -132,16 +132,10 @@ class GatherRunner {
 
   /**
    * Returns an error if the original network request failed or wasn't found.
-   * @param {string} url The URL of the original requested page.
-   * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
+   * @param {LH.Artifacts.NetworkRequest|undefined} mainRecord
    * @return {LH.LighthouseError|undefined}
    */
-  static getNetworkError(url, networkRecords) {
-    const mainRecord = networkRecords.find(record => {
-      // record.url is actual request url, so needs to be compared without any URL fragment.
-      return URL.equalWithExcludedFragments(record.url, url);
-    });
-
+  static getNetworkError(mainRecord) {
     if (!mainRecord) {
       return new LHError(LHError.errors.NO_DOCUMENT_REQUEST);
     } else if (mainRecord.failed) {
@@ -170,32 +164,31 @@ class GatherRunner {
 
   /**
    * Returns an error if we ended up on the `chrome-error` page and all other requests failed.
+   * @param {LH.Artifacts.NetworkRequest|undefined} mainRecord
    * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
    * @return {LH.LighthouseError|undefined}
    */
-  static getInterstitialError(networkRecords) {
+  static getInterstitialError(mainRecord, networkRecords) {
+    // If we never requested a document, there's no interstitial error, let other cases handle it.
+    if (!mainRecord) return undefined;
+
     const interstitialRequest = networkRecords
       .find(record => record.documentURL.startsWith('chrome-error://'));
     // If the page didn't end up on a chrome interstitial, there's no error here.
     if (!interstitialRequest) return undefined;
 
-    const pageNetworkRecords = networkRecords
-      .filter(record => !URL.NON_NETWORK_PROTOCOLS.includes(record.protocol) &&
-        !record.documentURL.startsWith('chrome-error://'));
-    // If none of the requests failed, there's no error here.
-    // We don't expect that this case could ever occur, but better safe than sorry.
-    // Note also that in cases of redirects, the initial requests could succeed and we still end up
-    // on the error interstitial page.
-    if (!pageNetworkRecords.some(record => record.failed)) return undefined;
+    // If the main document didn't fail, we didn't end up on an interstitial.
+    // FIXME: This doesn't handle client-side redirects.
+    // None of our error-handling deals with this case either because passContext.url doesn't handle non-network redirects.
+    if (!mainRecord.failed) return undefined;
 
     // If a request failed with the `net::ERR_CERT_*` collection of errors, then it's a security issue.
-    const insecureRequest = pageNetworkRecords.find(record =>
-      record.failed && record.localizedFailDescription.startsWith('net::ERR_CERT'));
-    if (insecureRequest) {
+    if (mainRecord.localizedFailDescription.startsWith('net::ERR_CERT')) {
       return new LHError(LHError.errors.INSECURE_DOCUMENT_REQUEST, {securityMessages:
-        insecureRequest.localizedFailDescription});
+        mainRecord.localizedFailDescription});
     }
 
+    // If we made it this far, it's a generic Chrome interstitial error.
     return new LHError(LHError.errors.CHROME_INTERSTITIAL_ERROR);
   }
 
@@ -208,8 +201,15 @@ class GatherRunner {
    * @return {LighthouseError|undefined}
    */
   static getPageLoadError(passContext, loadData, navigationError) {
-    const networkError = GatherRunner.getNetworkError(passContext.url, loadData.networkRecords);
-    const interstitialError = GatherRunner.getInterstitialError(loadData.networkRecords);
+    const {networkRecords} = loadData;
+    /** @type {LH.Artifacts.NetworkRequest|undefined} */
+    let mainRecord;
+    try {
+      mainRecord = NetworkAnalyzer.findMainDocument(networkRecords, passContext.url);
+    } catch (_) {}
+
+    const networkError = GatherRunner.getNetworkError(mainRecord);
+    const interstitialError = GatherRunner.getInterstitialError(mainRecord, networkRecords);
 
     // If the driver was offline, the load will fail without offline support. Ignore this case.
     if (!passContext.driver.online) return;
diff --git a/lighthouse-core/report/html/report-template.html b/lighthouse-core/report/html/report-template.html
index 491925c6b..830ba2a3e 100644
--- a/lighthouse-core/report/html/report-template.html
+++ b/lighthouse-core/report/html/report-template.html
@@ -19,7 +19,7 @@ limitations under the License.
 <head>
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
-  <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAADjklEQVR4AWI08P/HQEvAQrxSQKvlECfLFYXx75xCY2qmh89GbNvOMjb3v9jOOlxnFWxj206ebQ3b7q6q+z1rNagu8/zvPSZACAABpeUAA0miMgU7SA7JjCraFGwZwECOwvL75dWjsKgWBKtx0jvWo+vkBAFbACCkByMP6nMn48+AVgXB2fzSCwsv22/lMGlUhmJ0AE7BH8dyUUDbUEgN6RzJRSeaPxhdRYR0Inel+7Hd5lBiFpkMAxACc0394//9C4voFHDiAAGLpuOXebdfdHfctgwJKaZRLRKy6ItrSis6RBnVBgGtbHyKTEmJHQoEXoBCE5BCrDeA2ogMUIGDAKEBDEhUqwgMqBYDjW4DQzmuffVdqff42/ZQYYqVcMXGZsMPyCsH3lyJSetxvEaxAQXdjR1HjfwCdIS7lo2DZke26Qe+MXO12OWkGT0O6oE7vMGkMnkYw4aN1KQgMKExhXqswfiov4+a7MQ11XPnbr/5qpKlgACAAQj94Lu271bN9DUecQasIZlNzG72llRAAKJiAi+/BSHrSFjRvQhg3DEKEqJh08tsmLTx597+f6enr4cc2Zpk57pihfX24dW7RHcOLLUbJYhJSl0ErQCI9BVXH/XrO97QasuvQQSiECa0BrQCIIJp6X9T/r8QG6L71WYSqCoIIGo2BZDUBnS/D9EA9Nun1iYvbM0MFExIDQRoKFatc1Z6zrm5uWeObJotq0BGV9FuQBWq5a4Fw3PPz848rZHstZSuA5FWAFSMP2nOppOOGpl6qh9PCSg0IFyHKjSQyDNQHTru2t75NOEe0fsf246oAmFkI6vCdnWvbQFQFCKx8vCswV8TrDLiDLgH4Nr7RAtNsrC9d8sfk7b8ls4igdNy8CQKAISlsB0FjZfd3Lfp155tf8fKI4BxZZIj/oTdVEAIAcJFOCmzauHG71I7/rdreUAgAqpDP05fDARCAQQARwEIBQSVxq0FyaLvZZtevpHa8WHw8cft6cpxlq8eAJtIhnSbWDf951yx3y13OqUuu5qyGgkxCgGFh9cDihDGbTa6BqvT1lWmrav3bmt2ZMJ4mU6TGgIC4DBzcv/JqAau1WhzSt3x9Ixk/4Jk/8J4ZrrViFMA4W6A7+WK8xcVjvyrOmVD0FbAXokcT48r+xVqLKvuJYbmpNadnlp3mpufJHOe/GXktM+r09bT8kEdq9BRYAbGSgzP7ll82U71Mc+ZFooXgwAAAABJRU5ErkJggg==">
+  <link rel="icon" href="data:image/png;base64,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">
   <title>Lighthouse Report</title>
   <style>/*%%LIGHTHOUSE_CSS%%*/</style>
 </head>
diff --git a/lighthouse-viewer/app/index.html b/lighthouse-viewer/app/index.html
index 5f065b06b..4cf4b5246 100644
--- a/lighthouse-viewer/app/index.html
+++ b/lighthouse-viewer/app/index.html
@@ -11,7 +11,7 @@ Unless required by applicable law or agreed to in writing, software distributed
   <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
   <title>Lighthouse Report Viewer</title>
   <link rel="manifest" href="manifest.json">
-  <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAADjklEQVR4AWI08P/HQEvAQrxSQKvlECfLFYXx75xCY2qmh89GbNvOMjb3v9jOOlxnFWxj206ebQ3b7q6q+z1rNagu8/zvPSZACAABpeUAA0miMgU7SA7JjCraFGwZwECOwvL75dWjsKgWBKtx0jvWo+vkBAFbACCkByMP6nMn48+AVgXB2fzSCwsv22/lMGlUhmJ0AE7BH8dyUUDbUEgN6RzJRSeaPxhdRYR0Inel+7Hd5lBiFpkMAxACc0394//9C4voFHDiAAGLpuOXebdfdHfctgwJKaZRLRKy6ItrSis6RBnVBgGtbHyKTEmJHQoEXoBCE5BCrDeA2ogMUIGDAKEBDEhUqwgMqBYDjW4DQzmuffVdqff42/ZQYYqVcMXGZsMPyCsH3lyJSetxvEaxAQXdjR1HjfwCdIS7lo2DZke26Qe+MXO12OWkGT0O6oE7vMGkMnkYw4aN1KQgMKExhXqswfiov4+a7MQ11XPnbr/5qpKlgACAAQj94Lu271bN9DUecQasIZlNzG72llRAAKJiAi+/BSHrSFjRvQhg3DEKEqJh08tsmLTx597+f6enr4cc2Zpk57pihfX24dW7RHcOLLUbJYhJSl0ErQCI9BVXH/XrO97QasuvQQSiECa0BrQCIIJp6X9T/r8QG6L71WYSqCoIIGo2BZDUBnS/D9EA9Nun1iYvbM0MFExIDQRoKFatc1Z6zrm5uWeObJotq0BGV9FuQBWq5a4Fw3PPz848rZHstZSuA5FWAFSMP2nOppOOGpl6qh9PCSg0IFyHKjSQyDNQHTru2t75NOEe0fsf246oAmFkI6vCdnWvbQFQFCKx8vCswV8TrDLiDLgH4Nr7RAtNsrC9d8sfk7b8ls4igdNy8CQKAISlsB0FjZfd3Lfp155tf8fKI4BxZZIj/oTdVEAIAcJFOCmzauHG71I7/rdreUAgAqpDP05fDARCAQQARwEIBQSVxq0FyaLvZZtevpHa8WHw8cft6cpxlq8eAJtIhnSbWDf951yx3y13OqUuu5qyGgkxCgGFh9cDihDGbTa6BqvT1lWmrav3bmt2ZMJ4mU6TGgIC4DBzcv/JqAau1WhzSt3x9Ixk/4Jk/8J4ZrrViFMA4W6A7+WK8xcVjvyrOmVD0FbAXokcT48r+xVqLKvuJYbmpNadnlp3mpufJHOe/GXktM+r09bT8kEdq9BRYAbGSgzP7ll82U71Mc+ZFooXgwAAAABJRU5ErkJggg==">
+  <link rel="icon" href="data:image/png;base64,data:image/png;base64,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">
   <meta name="theme-color" content="#304ffe">
   <link rel="stylesheet" href="styles/viewer.css">
 </head>
diff --git a/package.json b/package.json
index be5ba8328..b01d094af 100644
--- a/package.json
+++ b/package.json
@@ -186,7 +186,7 @@
     },
     {
       "path": "./dist/viewer/src/viewer.js",
-      "maxSize": "75 kB"
+      "maxSize": "76 kB"
     },
     {
       "path": "./dist/lighthouse-dt-bundle.js",


Test patch:
diff --git a/lighthouse-cli/test/fixtures/badssl-iframe.html b/lighthouse-cli/test/fixtures/badssl-iframe.html
new file mode 100644
index 000000000..d42c34f96
--- /dev/null
+++ b/lighthouse-cli/test/fixtures/badssl-iframe.html
@@ -0,0 +1,7 @@
+<html>
+  <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
+  <body>
+    <h1>I have a bad iframe!</h1>
+    <iframe src="https://expired.badssl.com"></iframe>
+  </body>
+</html>
diff --git a/lighthouse-cli/test/smokehouse/error-expectations.js b/lighthouse-cli/test/smokehouse/error-expectations.js
index 7030f03f0..a77071d2f 100644
--- a/lighthouse-cli/test/smokehouse/error-expectations.js
+++ b/lighthouse-cli/test/smokehouse/error-expectations.js
@@ -59,4 +59,26 @@ module.exports = [
       },
     },
   },
+  {
+    lhr: {
+      // Our interstitial error handling used to be quite aggressive, so we'll test a page
+      // that has a bad iframe to make sure LH audits successfully.
+      // https://github.com/GoogleChrome/lighthouse/issues/9562
+      requestedUrl: 'http://localhost:10200/badssl-iframe.html',
+      finalUrl: 'http://localhost:10200/badssl-iframe.html',
+      audits: {
+        'first-contentful-paint': {
+          scoreDisplayMode: 'numeric',
+        },
+      },
+    },
+    artifacts: {
+      devtoolsLogs: {
+        defaultPass: NONEMPTY_ARRAY,
+      },
+      traces: {
+        defaultPass: {traceEvents: NONEMPTY_ARRAY},
+      },
+    },
+  },
 ];
diff --git a/lighthouse-core/test/gather/gather-runner-test.js b/lighthouse-core/test/gather/gather-runner-test.js
index 8d8077df0..a05e49d4e 100644
--- a/lighthouse-core/test/gather/gather-runner-test.js
+++ b/lighthouse-core/test/gather/gather-runner-test.js
@@ -426,12 +426,15 @@ describe('GatherRunner', function() {
 
   it('returns a pageLoadError and no artifacts when there is a network error', async () => {
     const requestedUrl = 'https://example.com';
-    // This page load error should be overriden by NO_DOCUMENT_REQUEST (for being
-    // more specific) since requestedUrl does not match any network request in fixture.
+    // This page load error should be overriden by ERRORED_DOCUMENT_REQUEST (for being
+    // more specific) since the main document network request failed with a 500.
     const navigationError = new LHError(LHError.errors.NO_FCP);
     const driver = Object.assign({}, fakeDriver, {
       online: true,
       gotoURL: url => url.includes('blank') ? null : Promise.reject(navigationError),
+      endDevtoolsLog() {
+        return networkRecordsToDevtoolsLog([{url: requestedUrl, statusCode: 500}]);
+      },
     });
 
     const config = new Config({
@@ -450,7 +453,7 @@ describe('GatherRunner', function() {
     const artifacts = await GatherRunner.run(config.passes, options);
     expect(artifacts.LighthouseRunWarnings).toHaveLength(1);
     expect(artifacts.PageLoadError).toBeInstanceOf(Error);
-    expect(artifacts.PageLoadError.code).toEqual('NO_DOCUMENT_REQUEST');
+    expect(artifacts.PageLoadError.code).toEqual('ERRORED_DOCUMENT_REQUEST');
     expect(artifacts.TestGatherer).toBeUndefined();
   });
 
@@ -789,6 +792,7 @@ describe('GatherRunner', function() {
       // resolved URL here does not match any request in the network records, causing a runtime error.
       gotoURL: async _ => requestedUrl,
       online: true,
+      endDevtoolsLog: () => [],
     });
 
     const config = new Config({
@@ -871,14 +875,7 @@ describe('GatherRunner', function() {
       const url = 'http://the-page.com';
       const mainRecord = new NetworkRequest();
       mainRecord.url = url;
-      assert.ok(!GatherRunner.getNetworkError(url, [mainRecord]));
-    });
-
-    it('passes when the page is loaded, ignoring any fragment', () => {
-      const url = 'http://example.com/#/page/list';
-      const mainRecord = new NetworkRequest();
-      mainRecord.url = 'http://example.com';
-      assert.ok(!GatherRunner.getNetworkError(url, [mainRecord]));
+      assert.ok(!GatherRunner.getNetworkError(mainRecord));
     });
 
     it('fails when page fails to load', () => {
@@ -887,7 +884,7 @@ describe('GatherRunner', function() {
       mainRecord.url = url;
       mainRecord.failed = true;
       mainRecord.localizedFailDescription = 'foobar';
-      const error = GatherRunner.getNetworkError(url, [mainRecord]);
+      const error = GatherRunner.getNetworkError(mainRecord);
       assert.equal(error.message, 'FAILED_DOCUMENT_REQUEST');
       assert.equal(error.code, 'FAILED_DOCUMENT_REQUEST');
       expect(error.friendlyMessage)
@@ -895,9 +892,7 @@ describe('GatherRunner', function() {
     });
 
     it('fails when page times out', () => {
-      const url = 'http://the-page.com';
-      const records = [];
-      const error = GatherRunner.getNetworkError(url, records);
+      const error = GatherRunner.getNetworkError(undefined);
       assert.equal(error.message, 'NO_DOCUMENT_REQUEST');
       assert.equal(error.code, 'NO_DOCUMENT_REQUEST');
       expect(error.friendlyMessage).toBeDisplayString(/^Lighthouse was unable to reliably load/);
@@ -908,7 +903,7 @@ describe('GatherRunner', function() {
       const mainRecord = new NetworkRequest();
       mainRecord.url = url;
       mainRecord.statusCode = 404;
-      const error = GatherRunner.getNetworkError(url, [mainRecord]);
+      const error = GatherRunner.getNetworkError(mainRecord);
       assert.equal(error.message, 'ERRORED_DOCUMENT_REQUEST');
       assert.equal(error.code, 'ERRORED_DOCUMENT_REQUEST');
       expect(error.friendlyMessage)
@@ -920,7 +915,7 @@ describe('GatherRunner', function() {
       const mainRecord = new NetworkRequest();
       mainRecord.url = url;
       mainRecord.statusCode = 500;
-      const error = GatherRunner.getNetworkError(url, [mainRecord]);
+      const error = GatherRunner.getNetworkError(mainRecord);
       assert.equal(error.message, 'ERRORED_DOCUMENT_REQUEST');
       assert.equal(error.code, 'ERRORED_DOCUMENT_REQUEST');
       expect(error.friendlyMessage)
@@ -933,7 +928,7 @@ describe('GatherRunner', function() {
       mainRecord.url = url;
       mainRecord.failed = true;
       mainRecord.localizedFailDescription = 'net::ERR_NAME_NOT_RESOLVED';
-      const error = GatherRunner.getNetworkError(url, [mainRecord]);
+      const error = GatherRunner.getNetworkError(mainRecord);
       assert.equal(error.message, 'DNS_FAILURE');
       assert.equal(error.code, 'DNS_FAILURE');
       expect(error.friendlyMessage).toBeDisplayString(/^DNS servers could not resolve/);
@@ -941,11 +936,15 @@ describe('GatherRunner', function() {
   });
 
   describe('#getInterstitialError', () => {
+    it('passes when the page was not requested', () => {
+      expect(GatherRunner.getInterstitialError(undefined, [])).toBeUndefined();
+    });
+
     it('passes when the page is loaded', () => {
       const url = 'http://the-page.com';
       const mainRecord = new NetworkRequest();
       mainRecord.url = url;
-      expect(GatherRunner.getInterstitialError([mainRecord])).toBeUndefined();
+      expect(GatherRunner.getInterstitialError(mainRecord, [mainRecord])).toBeUndefined();
     });
 
     it('passes when page fails to load normally', () => {
@@ -954,7 +953,7 @@ describe('GatherRunner', function() {
       mainRecord.url = url;
       mainRecord.failed = true;
       mainRecord.localizedFailDescription = 'foobar';
-      expect(GatherRunner.getInterstitialError([mainRecord])).toBeUndefined();
+      expect(GatherRunner.getInterstitialError(mainRecord, [mainRecord])).toBeUndefined();
     });
 
     it('passes when page gets a generic interstitial but somehow also loads everything', () => {
@@ -966,7 +965,7 @@ describe('GatherRunner', function() {
       interstitialRecord.url = 'data:text/html;base64,abcdef';
       interstitialRecord.documentURL = 'chrome-error://chromewebdata/';
       const records = [mainRecord, interstitialRecord];
-      expect(GatherRunner.getInterstitialError(records)).toBeUndefined();
+      expect(GatherRunner.getInterstitialError(mainRecord, records)).toBeUndefined();
     });
 
     it('fails when page gets a generic interstitial', () => {
@@ -979,7 +978,7 @@ describe('GatherRunner', function() {
       interstitialRecord.url = 'data:text/html;base64,abcdef';
       interstitialRecord.documentURL = 'chrome-error://chromewebdata/';
       const records = [mainRecord, interstitialRecord];
-      const error = GatherRunner.getInterstitialError(records);
+      const error = GatherRunner.getInterstitialError(mainRecord, records);
       expect(error.message).toEqual('CHROME_INTERSTITIAL_ERROR');
       expect(error.code).toEqual('CHROME_INTERSTITIAL_ERROR');
       expect(error.friendlyMessage).toBeDisplayString(/^Chrome prevented/);
@@ -995,12 +994,29 @@ describe('GatherRunner', function() {
       interstitialRecord.url = 'data:text/html;base64,abcdef';
       interstitialRecord.documentURL = 'chrome-error://chromewebdata/';
       const records = [mainRecord, interstitialRecord];
-      const error = GatherRunner.getInterstitialError(records);
+      const error = GatherRunner.getInterstitialError(mainRecord, records);
       expect(error.message).toEqual('INSECURE_DOCUMENT_REQUEST');
       expect(error.code).toEqual('INSECURE_DOCUMENT_REQUEST');
       expect(error.friendlyMessage).toBeDisplayString(/valid security certificate/);
       expect(error.friendlyMessage).toBeDisplayString(/net::ERR_CERT_COMMON_NAME_INVALID/);
     });
+
+    it('passes when page iframe gets a generic interstitial', () => {
+      const url = 'http://the-page.com';
+      const mainRecord = new NetworkRequest();
+      mainRecord.url = url;
+      mainRecord.failed = false;
+      const iframeRecord = new NetworkRequest();
+      iframeRecord.failed = true;
+      iframeRecord.url = 'https://the-ad.com';
+      iframeRecord.documentURL = 'https://the-ad.com';
+      const interstitialRecord = new NetworkRequest();
+      interstitialRecord.url = 'data:text/html;base64,abcdef';
+      interstitialRecord.documentURL = 'chrome-error://chromewebdata/';
+      const records = [mainRecord, iframeRecord, interstitialRecord];
+      const error = GatherRunner.getInterstitialError(mainRecord, records);
+      expect(error).toBeUndefined();
+    });
   });
 
   describe('#getPageLoadError', () => {
@@ -1019,6 +1035,16 @@ describe('GatherRunner', function() {
       expect(error).toBeUndefined();
     });
 
+    it('passes when the page is loaded, ignoring any fragment', () => {
+      const url = 'http://example.com/#/page/list';
+      const mainRecord = new NetworkRequest();
+      const passContext = {url, driver: {online: true}};
+      const loadData = {networkRecords: [mainRecord]};
+      mainRecord.url = 'http://example.com';
+      const error = GatherRunner.getPageLoadError(passContext, loadData, undefined);
+      expect(error).toBeUndefined();
+    });
+
     it('passes when the page is offline', () => {
       const passContext = {url: 'http://the-page.com', driver: {online: false}};
       const mainRecord = new NetworkRequest();