GoogleChrome / chrome-launcher

Launch Google Chrome with ease from node.
https://www.npmjs.com/package/chrome-launcher
Apache License 2.0
1.24k stars 189 forks source link

How to ignore invalid certificates with this? #109

Open robert-j-webb opened 6 years ago

robert-j-webb commented 6 years ago

Hi, I'm trying to run lighthouse programmatically, and as long as I don't pass in --headless as a flag, then I'm fine. However, if I do, I get errors from lighthouse complaining that it is having a FAILED_DOCUMENT_REQUEST. I can run headlessly fine if I point at production, which tells me the issue is that locally I have an invalid cert.

Looking through how puppeteer deals with it, you can see they send an override to 'Security.setOverrideCertificateErrors'

https://github.com/GoogleChrome/puppeteer/blob/469b910a2de82e165a6a065741f5c99a84c891db/lib/Page.js#L58

Is this possible to do in this repo? Or should I abandon using lighthouse programmatically?

Here's the code I'm using to launch and run lighthouse:

/* eslint-disable no-console */
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

function launchChromeAndRunLighthouse(url, opts, config = null) {
  return chromeLauncher
    .launch({ chromeFlags: opts.chromeFlags })
    .then(chrome => {
      opts.port = chrome.port;
      return lighthouse(url, opts, config).then(results =>
        chrome.kill().then(() => results)
      );
    });
}

function task() {
  const opts = {
    chromeFlags: ['--headless', '--disable-gpu', '--no-sandbox'],
    onlyCategories: ['performance'],
    output: 'json'
  };
  return launchChromeAndRunLighthouse('https://store.nest.test', opts).then(
    results => {
      const { audits } = results;
      const auditSummary = Object.keys(audits)
        .filter(key => typeof audits[key].score === 'number')
        .map(key => [key, audits[key].score, audits[key].displayValue]);
      console.log(auditSummary.join('\n'));
    }
  );
}
robert-j-webb commented 6 years ago

@paulirish @samccone - is there any chance of this being fixed or should I just forget about running headlessly?

patrickhulce commented 6 years ago

@robert-j-webb you can try giving Lighthouse + puppeteer a try

https://github.com/GoogleChrome/lighthouse/blob/master/docs/puppeteer.md#inject-jscss-before-the-page-loads

with something like the below?

browser.on('targetchanged', async target => {
  const client = await target.createCDPSession();
  await client.send('Security.setOverrideCertificateErrors', {override: true});
})

DISCLAIMER: totally untested

robert-j-webb commented 6 years ago

Hmm I'll look into it, if it works I'll post up my setup

robert-j-webb commented 6 years ago

@patrickhulce - you were close but not quite there Your solution is missing a step, it should be like this:

browser.on('targetchanged', async target => {
  const page = await target.page();
  if (page && page.url() === url) {
    const client = await page.target().createCDPSession();
    await client.send('Security.setOverrideCertificateErrors', {override: true});
  }

But I couldn't get that to work, IDK if I had another error but all I needed was to get some headlessness working, so I pushed through. Here's what actually runs:

async function launchChromeAndRunLighthouse(url, opts, config = null) {
const browser = await puppeteer.launch({
    ignoreHTTPSErrors: true
  });

  // When we create a new page and go to it, Puppeteer correctly sends the client message.
  const page = await browser.newPage();
  await page.goto(url);

  opts.port = new URL(browser.wsEndpoint()).port;

  const results = await lighthouse(url, opts, config);

  await browser.close();
  return results;

}
// For some reason this returns `speed-index-metric,NaN,NaN`
// IDK, I guess I made lightspeed happen

Now if you'd like, I can try updating the readme so that this is a socialized choice? I'd love to help with documentation if you need it.

patrickhulce commented 6 years ago

Yeah a PR would be great, probably belongs over the in lighthouse puppeteer or headless docs :)

samccone commented 6 years ago

This feels like a bug in headless Chrome. Has anyone filed a CR bug yet to track this?

We can add a work around inside of the library for this case if we want.

patrickhulce commented 6 years ago

@samccone https://bugs.chromium.org/p/chromium/issues/detail?id=721739

AFAICT Security.setOverrideCertificateErrors was the feature introduced to address precisely this use case as the flag was deprecated.

robert-j-webb commented 6 years ago

Also, as far as I can tell, the issue about speed-index-metric is related to running lighthouse headlessly, not chrome launcher.

samccone commented 6 years ago

Thanks for linking the issue @patrickhulce, if this is the new state of the world then I revise my above statement about adding a workaround to "adding a fix".

I spoke offline with @robert-j-webb and they are going to work on a patch for us.

Thanks all, and thank you @robert-j-webb for pinging me about this important regression in launcher.

:steam_locomotive: :train::train::train::train::train: :running_man:

patrickhulce commented 6 years ago

Also, as far as I can tell, the issue about speed-index-metric is related to running lighthouse headlessly, not chrome launcher.

@robert-j-webb mind filing a bug over in LH with repro steps then? Screenshots should be working in headless.

I spoke offline with @robert-j-webb and they are going to work on a patch for us.

awesome thanks folks!

robert-j-webb commented 6 years ago

@patrickhulce For some reason, this morning when running the same command with the same code, I did not get the issue. If I could reliably reproduce it, I would definitely make an issue for it.

robert-j-webb commented 6 years ago

@samccone - I think the real fix is just to use Puppeteer instead of chrome launcher if you want to use lighthouse with any kind of advanced config options. You need to connect to the dev tools protocol to disable HTTP certificate errors, which Puppeteer already does, so why not use it?

However, I'm not that familiar with how to connect and send messages using the chrome dev tools protocol, so maybe I'm overestimating how complicated it is. I'm looking through the Puppeteer source right now to try to figure out how they're doing it and it seems like it's not terribly complicated but very error prone.

Maybe the solution to this is just to write some documentation that says, 'Use Puppeteer instead?' for this issue?