From 421d262b1996ea8c8514eb6e6e73f2fcc37b102c Mon Sep 17 00:00:00 2001 From: Rynat Sibahatau Date: Mon, 10 Jun 2019 14:51:47 -0400 Subject: [PATCH] Initial implementation --- lighthouse-cli/bin.js | 15 ++++++++++ lighthouse-cli/cli-flags.js | 10 ++++++- .../test/cli/__snapshots__/index-test.js.snap | 1 + lighthouse-cli/test/cli/bin-test.js | 20 +++++++++++++ lighthouse-cli/test/cli/index-test.js | 9 ++++++ .../test/fixtures/extra-cookies/invalid.txt | 1 + .../test/fixtures/extra-cookies/valid.json | 7 +++++ lighthouse-cli/test/fixtures/static-server.js | 14 +++++++++ lighthouse-core/config/constants.js | 1 + lighthouse-core/gather/driver.js | 13 +++++++++ lighthouse-core/gather/gather-runner.js | 1 + lighthouse-core/test/gather/driver-test.js | 29 ++++++++++++++++++- lighthouse-core/test/gather/fake-driver.js | 3 ++ .../test/gather/gather-runner-test.js | 28 +++++++++++++++++- .../test/results/artifacts/artifacts.json | 1 + lighthouse-core/test/results/sample_v2.json | 1 + readme.md | 22 +++++++------- 17 files changed, 163 insertions(+), 13 deletions(-) create mode 100644 lighthouse-cli/test/fixtures/extra-cookies/invalid.txt create mode 100644 lighthouse-cli/test/fixtures/extra-cookies/valid.json diff --git a/lighthouse-cli/bin.js b/lighthouse-cli/bin.js index 887a533d8623..6278b7d24c4c 100644 --- a/lighthouse-cli/bin.js +++ b/lighthouse-cli/bin.js @@ -122,6 +122,21 @@ async function begin() { cliFlags.extraHeaders = JSON.parse(extraHeadersStr); } + if (cliFlags.extraCookies) { + // TODO: LH.Flags.extraCookies is actually a string at this point, but needs to be + // copied over to LH.Settings.extraCookies, which is LH.Crdp.Network.Cookies. Force + // the conversion here, but long term either the CLI flag or the setting should have + // a different name. + // @ts-ignore + let extraCookiesStr = /** @type {string} */ (cliFlags.extraCookies); + // If not a JSON array, assume it's a path to a JSON file. + if (extraCookiesStr.substr(0, 1) !== '[') { + extraCookiesStr = fs.readFileSync(extraCookiesStr, 'utf-8'); + } + + cliFlags.extraCookies = JSON.parse(extraCookiesStr); + } + if (cliFlags.precomputedLanternDataPath) { const lanternDataStr = fs.readFileSync(cliFlags.precomputedLanternDataPath, 'utf8'); /** @type {LH.PrecomputedLanternData} */ diff --git a/lighthouse-cli/cli-flags.js b/lighthouse-cli/cli-flags.js index 9e7188f042e1..cfa9a5cdf447 100644 --- a/lighthouse-cli/cli-flags.js +++ b/lighthouse-cli/cli-flags.js @@ -53,11 +53,17 @@ function getFlags(manualArgv) { 'lighthouse --quiet --chrome-flags="--headless"', 'Launch Headless Chrome, turn off logging') .example( - 'lighthouse --extra-headers "{\\"Cookie\\":\\"monster=blue\\", \\"x-men\\":\\"wolverine\\"}"', + 'lighthouse --extra-headers "{\\"x-men\\":\\"wolverine\\"}"', 'Stringify\'d JSON HTTP Header key/value pairs to send in requests') .example( 'lighthouse --extra-headers=./path/to/file.json', 'Path to JSON file of HTTP Header key/value pairs to send in requests') + .example( + 'lighthouse --extra-cookies "[{\\"name\\":\\"session_id\\",\\"value\\":\\"x-men\\" }]"', + 'Stringify\'d JSON array of HTTP Cookies to send in requests') + .example( + 'lighthouse --extra-cookies=./path/to/file.json', + 'Path to JSON file of HTTP Cookies to send in requests') .example( 'lighthouse --only-categories=performance,pwa', 'Only run specific categories.') @@ -126,6 +132,7 @@ function getFlags(manualArgv) { 'max-wait-for-load': 'The timeout (in milliseconds) to wait before the page is considered done loading and the run should continue. WARNING: Very high values can lead to large traces and instability', 'extra-headers': 'Set extra HTTP Headers to pass with request', + 'extra-cookies': 'Set extra HTTP Cookies to pass with request', 'precomputed-lantern-data-path': 'Path to the file where lantern simulation data should be read from, overwriting the lantern observed estimates for RTT and server latency.', 'lantern-data-output-path': 'Path to the file where lantern simulation data should be written to, can be used in a future run with the `precomputed-lantern-data-path` flag.', 'only-audits': 'Only run the specified audits', @@ -166,6 +173,7 @@ function getFlags(manualArgv) { .array('output') .array('plugins') .string('extraHeaders') + .string('extraCookies') .string('channel') .string('precomputedLanternDataPath') .string('lanternDataOutputPath') diff --git a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap index 3983c1067232..3397922a5668 100644 --- a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap +++ b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap @@ -1371,6 +1371,7 @@ Object { "channel": "cli", "disableStorageReset": false, "emulatedFormFactor": "mobile", + "extraCookies": null, "extraHeaders": null, "gatherMode": false, "locale": "en-US", diff --git a/lighthouse-cli/test/cli/bin-test.js b/lighthouse-cli/test/cli/bin-test.js index d6b3ce96b3d6..f2f413f084a1 100644 --- a/lighthouse-cli/test/cli/bin-test.js +++ b/lighthouse-cli/test/cli/bin-test.js @@ -170,6 +170,26 @@ describe('CLI bin', function() { }); }); + describe('extraCookies', () => { + it('should convert extra cookies to object', async () => { + // @ts-ignore - see TODO: in bin.js + cliFlags = {...cliFlags, extraCookies: '[{"name":"foo", "value": "bar", "url": "http://localhost"}]'}; + await bin.begin(); + + expect(getRunLighthouseArgs()[1]).toHaveProperty('extraCookies', [{'name': 'foo', 'value': 'bar', 'url': 'http://localhost'}]); + }); + + it('should read extra cookies from file', async () => { + const headersFile = require.resolve('../fixtures/extra-headers/valid.json'); + // @ts-ignore - see TODO: in bin.js + cliFlags = {...cliFlags, extraCookies: headersFile}; + await bin.begin(); + + expect(getRunLighthouseArgs()[1]).toHaveProperty('extraCookies', require(headersFile)); + }); + }); + + describe('precomputedLanternData', () => { it('should read lantern data from file', async () => { const lanternDataFile = require.resolve('../fixtures/lantern-data.json'); diff --git a/lighthouse-cli/test/cli/index-test.js b/lighthouse-cli/test/cli/index-test.js index 11d31388b313..b4f46ab92a70 100644 --- a/lighthouse-cli/test/cli/index-test.js +++ b/lighthouse-cli/test/cli/index-test.js @@ -59,6 +59,15 @@ describe('CLI Tests', function() { assert.equal(ret.status, 1); }); + it('should exit with a error if the file does not contain valid JSON', () => { + const ret = spawnSync('node', [indexPath, 'https://www.google.com', + '--extra-cookies', + path.resolve(__dirname, '../fixtures/extra-cookies/invalid.txt')], {encoding: 'utf8'}); + + assert.ok(ret.stderr.includes('Unexpected token')); + assert.equal(ret.status, 1); + }); + it('should exit with a error if the passsed in string is not valid JSON', () => { const ret = spawnSync('node', [indexPath, 'https://www.google.com', '--extra-headers', '{notjson}'], {encoding: 'utf8'}); diff --git a/lighthouse-cli/test/fixtures/extra-cookies/invalid.txt b/lighthouse-cli/test/fixtures/extra-cookies/invalid.txt new file mode 100644 index 000000000000..cfd9a1e3a781 --- /dev/null +++ b/lighthouse-cli/test/fixtures/extra-cookies/invalid.txt @@ -0,0 +1 @@ +NotJSON diff --git a/lighthouse-cli/test/fixtures/extra-cookies/valid.json b/lighthouse-cli/test/fixtures/extra-cookies/valid.json new file mode 100644 index 000000000000..1e404b985004 --- /dev/null +++ b/lighthouse-cli/test/fixtures/extra-cookies/valid.json @@ -0,0 +1,7 @@ +[ + { + "name":"test", + "value":"true", + "url":"http://localhost" + } +] diff --git a/lighthouse-cli/test/fixtures/static-server.js b/lighthouse-cli/test/fixtures/static-server.js index 2a0cdf6eacee..341498652786 100644 --- a/lighthouse-cli/test/fixtures/static-server.js +++ b/lighthouse-cli/test/fixtures/static-server.js @@ -105,6 +105,20 @@ function requestHandler(request, response) { } } + if (params.has('extra_cookie')) { + const extraCookies = new URLSearchParams(params.get('extra_cookie')); + let cookeString = ''; + for (const [cookieName, cookieValue] of extraCookies) { + cookeString += cookieName + '=' + cookieValue + ';'; + } + + // Extra cookie we allways override possible 'Set-Cookie' header + // which may be already present in request by extra_header + headers['Set-Cookie'] = []; + headers['Set-Cookie'].push(cookeString); + } + + if (params.has('gzip')) { useGzip = Boolean(params.get('gzip')); } diff --git a/lighthouse-core/config/constants.js b/lighthouse-core/config/constants.js index 9f5ce283b313..8bac08564d95 100644 --- a/lighthouse-core/config/constants.js +++ b/lighthouse-core/config/constants.js @@ -60,6 +60,7 @@ const defaultSettings = { blockedUrlPatterns: null, additionalTraceCategories: null, extraHeaders: null, + extraCookies: null, precomputedLanternData: null, onlyAudits: null, onlyCategories: null, diff --git a/lighthouse-core/gather/driver.js b/lighthouse-core/gather/driver.js index b9d58f6d5566..68e8bdbbf184 100644 --- a/lighthouse-core/gather/driver.js +++ b/lighthouse-core/gather/driver.js @@ -1487,6 +1487,19 @@ class Driver { return this.sendCommand('Network.setExtraHTTPHeaders', {headers}); } + /** + * @param {LH.Crdp.Network.Cookies|null} cookies key/value pairs of HTTP Cookies. + * @return {Promise} + */ + async setCookies(cookies) { + if (!cookies) { + return; + } + + return this.sendCommand('Network.setCookies', {cookies}); + } + + /** * @param {string} url * @return {Promise} diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js index c1d50c80f8e7..2b1f6491a5e7 100644 --- a/lighthouse-core/gather/gather-runner.js +++ b/lighthouse-core/gather/gather-runner.js @@ -213,6 +213,7 @@ class GatherRunner { // neccessary at the beginning of the next pass. await passContext.driver.blockUrlPatterns(blockedUrls); await passContext.driver.setExtraHTTPHeaders(passContext.settings.extraHeaders); + await passContext.driver.setCookies(passContext.settings.extraCookies); log.timeEnd(status); } diff --git a/lighthouse-core/test/gather/driver-test.js b/lighthouse-core/test/gather/driver-test.js index 62bfbcb2c1c7..b3e0229fba75 100644 --- a/lighthouse-core/test/gather/driver-test.js +++ b/lighthouse-core/test/gather/driver-test.js @@ -412,7 +412,7 @@ describe('.setExtraHTTPHeaders', () => { ); }); - it('should Network.setExtraHTTPHeaders when there are extra-headers', async () => { + it('should not Network.setExtraHTTPHeaders when there are extra-headers', async () => { connectionStub.sendCommand = createMockSendCommandFn(); await driver.setExtraHTTPHeaders(); @@ -420,6 +420,33 @@ describe('.setExtraHTTPHeaders', () => { }); }); +describe('.setCookies', () => { + it('should call Network.setCookies when there are extra-cookies', async () => { + connectionStub.sendCommand = createMockSendCommandFn().mockResponse( + 'Network.setCookies', + {} + ); + + await driver.setCookies([{ + 'name': 'cookie1', + 'value': 'monster', + }]); + + expect(connectionStub.sendCommand).toHaveBeenCalledWith( + 'Network.setCookies', + expect.anything() + ); + }); + + it('should not call Network.setCookies when there are extra-headers', async () => { + connectionStub.sendCommand = createMockSendCommandFn(); + await driver.setCookies(); + + expect(connectionStub.sendCommand).not.toHaveBeenCalled(); + }); +}); + + describe('.getAppManifest', () => { it('should return null when no manifest', async () => { connectionStub.sendCommand = createMockSendCommandFn().mockResponse( diff --git a/lighthouse-core/test/gather/fake-driver.js b/lighthouse-core/test/gather/fake-driver.js index 108a40aa6d78..ac400f6c568a 100644 --- a/lighthouse-core/test/gather/fake-driver.js +++ b/lighthouse-core/test/gather/fake-driver.js @@ -87,6 +87,9 @@ function makeFakeDriver({protocolGetVersionResponse}) { setExtraHTTPHeaders() { return Promise.resolve(); }, + setCookies() { + return Promise.resolve(); + }, }; } diff --git a/lighthouse-core/test/gather/gather-runner-test.js b/lighthouse-core/test/gather/gather-runner-test.js index f76f0f63ff00..5ba7b2707dd4 100644 --- a/lighthouse-core/test/gather/gather-runner-test.js +++ b/lighthouse-core/test/gather/gather-runner-test.js @@ -40,7 +40,7 @@ const fakeDriver = require('./fake-driver.js'); const fakeDriverUsingRealMobileDevice = fakeDriver.fakeDriverUsingRealMobileDevice; function getMockedEmulationDriver(emulationFn, netThrottleFn, cpuThrottleFn, - blockUrlFn, extraHeadersFn) { + blockUrlFn, extraHeadersFn, extraCookiesFn) { const Driver = require('../../gather/driver.js'); const Connection = require('../../gather/connections/connection.js'); const EmulationDriver = class extends Driver { @@ -81,6 +81,9 @@ function getMockedEmulationDriver(emulationFn, netThrottleFn, cpuThrottleFn, case 'Network.setExtraHTTPHeaders': fn = extraHeadersFn; break; + case 'Network.setCookies': + fn = extraCookiesFn; + break; default: fn = null; break; @@ -393,6 +396,7 @@ describe('GatherRunner', function() { setThrottling: asyncFunc, blockUrlPatterns: asyncFunc, setExtraHTTPHeaders: asyncFunc, + setCookies: asyncFunc, endTrace: asyncFunc, endDevtoolsLog: () => [], getBrowserVersion: async () => ({userAgent: ''}), @@ -578,6 +582,28 @@ describe('GatherRunner', function() { )); }); + it('tells the driver to set additional cookies when extraCookies flag is given', () => { + let receivedCookies = null; + const driver = getMockedEmulationDriver(null, null, null, null, null, params => { + receivedCookies = params.cookies; + }); + const cookies = [{ + 'name': 'cookie1', + 'value': 'monster', + }]; + + return GatherRunner.setupPassNetwork({ + driver, + settings: { + extraCookies: cookies, + }, + passConfig: {gatherers: []}, + }).then(() => assert.deepStrictEqual( + receivedCookies, + cookies + )); + }); + it('tells the driver to begin tracing', async () => { let calledTrace = false; const driver = { diff --git a/lighthouse-core/test/results/artifacts/artifacts.json b/lighthouse-core/test/results/artifacts/artifacts.json index 2cbcd6481379..a6819f0f74c4 100644 --- a/lighthouse-core/test/results/artifacts/artifacts.json +++ b/lighthouse-core/test/results/artifacts/artifacts.json @@ -60,6 +60,7 @@ "blockedUrlPatterns": null, "additionalTraceCategories": null, "extraHeaders": null, + "extraCookies": null, "precomputedLanternData": null, "onlyAudits": null, "onlyCategories": null, diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json index 088cbea1083d..b280e5dece97 100644 --- a/lighthouse-core/test/results/sample_v2.json +++ b/lighthouse-core/test/results/sample_v2.json @@ -3327,6 +3327,7 @@ "blockedUrlPatterns": null, "additionalTraceCategories": null, "extraHeaders": null, + "extraCookies": null, "precomputedLanternData": null, "onlyAudits": null, "onlyCategories": null, diff --git a/readme.md b/readme.md index 50d447e5c40e..97b01565817e 100644 --- a/readme.md +++ b/readme.md @@ -101,18 +101,20 @@ Options: --throttling.uploadThroughputKbps Controls emulated network upload throughput --throttling.cpuSlowdownMultiplier Controls simulated + emulated CPU throttling --extra-headers Set extra HTTP Headers to pass with request [string] + --extra-cookies Set extra HTTP Cookies to pass with request [string] Examples: - lighthouse --view Opens the HTML report in a browser after the run completes - lighthouse --config-path=./myconfig.js Runs Lighthouse with your own configuration: custom audits, report - generation, etc. - lighthouse --output=json --output-path=./report.json --save-assets Save trace, devtoolslog, and named JSON report. - lighthouse --emulated-form-factor=none Disable device emulation and all throttling. - --throttling-method=provided - lighthouse --chrome-flags="--window-size=412,660" Launch Chrome with a specific window size - lighthouse --quiet --chrome-flags="--headless" Launch Headless Chrome, turn off logging - lighthouse --extra-headers "{\"Cookie\":\"monster=blue\"}" Stringify\'d JSON HTTP Header key/value pairs to send in requests - lighthouse --extra-headers=./path/to/file.json Path to JSON file of HTTP Header key/value pairs to send in requests + lighthouse --view Opens the HTML report in a browser after the run completes + lighthouse --config-path=./myconfig.js Runs Lighthouse with your own configuration: custom audits, report generation, etc. + lighthouse --output=json --output-path=./report.json --save-assets Save trace, screenshots, and named JSON report. + lighthouse --emulated-form-factor=none --throttling-method=provided Disable device emulation and all throttling + lighthouse --chrome-flags="--window-size=412,660" Launch Chrome with a specific window size + lighthouse --quiet --chrome-flags="--headless" Launch Headless Chrome, turn off logging + lighthouse --extra-headers "{\"x-men\":\"wolverine\"}" Stringify'd JSON HTTP Header key/value pairs to send in requests + lighthouse --extra-headers=./path/to/file.json Path to JSON file of HTTP Header key/value pairs to send in requests + lighthouse --extra-cookies "[{\"name\":\"session_id\",\"value\":\"x-men\" }]" Stringify'd JSON array of HTTP Cookies to send in requests + lighthouse --extra-cookies=./path/to/file.json Path to JSON file of HTTP Cookies to send in requests + lighthouse --only-categories=performance,pwa Only run specific categories. For more information on Lighthouse, see https://developers.google.com/web/tools/lighthouse/. ```