From 46cd63ecb215272ace475b62eaf6d62e4340b4bf Mon Sep 17 00:00:00 2001
From: Bart Veneman
Date: Fri, 7 Jan 2022 20:32:31 +0100
Subject: [PATCH] handle server timeouts
---
src/index.js | 55 +++++++++++++++++++++++++++++++++------------------
test/index.js | 12 +++++++++++
2 files changed, 48 insertions(+), 19 deletions(-)
diff --git a/src/index.js b/src/index.js
index 1e014ef..4ea8c88 100644
--- a/src/index.js
+++ b/src/index.js
@@ -12,9 +12,17 @@ InvalidUrlError.prototype = Error.prototype
/**
* @param {string} url URL to get CSS from
* @param {string} waitUntil https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#pagegotourl-options
+ * @param {string} timeout https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#pagegotourl-options
+ * @param {string} origins Can either be 'include' or 'exlude'
+ * @param {string} inlineStyles Can either be 'include' or 'exlude'
* @returns {string} All CSS that was found
*/
-module.exports = async (url, {waitUntil = 'networkidle0', origins = 'exclude', inlineStyles = 'include'} = {}) => {
+module.exports = async (url, {
+ waitUntil = 'networkidle0',
+ timeout = 10000,
+ origins = 'exclude',
+ inlineStyles = 'include'
+} = {}) => {
// Setup a browser instance
const browser = await puppeteer.launch()
@@ -26,20 +34,32 @@ module.exports = async (url, {waitUntil = 'networkidle0', origins = 'exclude', i
await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.16; rv:85.0) Gecko/20100101 Firefox/85.0')
await page.coverage.startCSSCoverage()
url = normalizeUrl(url, {stripWWW: false})
- const response = await page.goto(url, {waitUntil})
+
+ let response
+
+ // Explicit try-catch for when pages timeout
+ try {
+ response = await page.goto(url, {
+ waitUntil,
+ timeout
+ })
+ } catch (error) {
+ // In case of timeouts
+ await browser.close()
+
+ throw error
+ }
// Make sure that we only try to extract CSS from valid pages.
// Bail out if the response is an invalid request (400, 500)
if (response.status() >= 400) {
await browser.close() // Don't leave any resources behind
- return Promise.reject(
- new InvalidUrlError({
- url,
- statusCode: response.status(),
- statusText: response.statusText()
- })
- )
+ throw new InvalidUrlError({
+ url,
+ statusCode: response.status(),
+ statusText: response.statusText()
+ })
}
// If the response is a CSS file, return that file
@@ -47,8 +67,7 @@ module.exports = async (url, {waitUntil = 'networkidle0', origins = 'exclude', i
const headers = response.headers()
if (headers['content-type'].includes('text/css')) {
- const css = await response.text()
- return Promise.resolve(css)
+ return response.text()
}
const coverage = await page.coverage.stopCSSCoverage()
@@ -95,6 +114,8 @@ module.exports = async (url, {waitUntil = 'networkidle0', origins = 'exclude', i
.map(css => ({type: 'inline', href: url, css}))
}
+ await browser.close()
+
const links = coverage
// Filter out the tags that were found in the coverage
// report since we've conducted our own search for them.
@@ -107,21 +128,17 @@ module.exports = async (url, {waitUntil = 'networkidle0', origins = 'exclude', i
type: 'link-or-import'
}))
- await browser.close()
-
const css = links
.concat(styleSheetsApiCss)
.concat(inlineStyles === 'exclude' ? [] : inlineCss)
// Return the complete structure ...
if (origins === 'include') {
- return Promise.resolve(css)
+ return css
}
// ... or return all CSS as a single String
- return Promise.resolve(
- css
- .map(({css}) => css)
- .join('\n')
- )
+ return css
+ .map(({css}) => css)
+ .join('\n')
}
diff --git a/test/index.js b/test/index.js
index 47ef57d..4928f4a 100644
--- a/test/index.js
+++ b/test/index.js
@@ -145,3 +145,15 @@ test('it rejects if the url has an HTTP error status', async t => {
test('it rejects on an invalid url', async t => {
await t.throwsAsync(extractCss('site.example'))
})
+
+test('it rejects on server timing out', async t => {
+ server.get('/timeout-page', (req, res) => {
+ setTimeout(function () {
+ res.status(500).send()
+ }, 5000)
+ })
+ const timoutUrl = server.url + '/timeout-page'
+ await t.throwsAsync(extractCss(timoutUrl, {timeout: 4500}), {
+ message: 'Navigation timeout of 4500 ms exceeded'
+ })
+})