From 6c14fa780aeea39dc066ca9e45d8a85dd58c9af7 Mon Sep 17 00:00:00 2001 From: Giovanni Bassi Date: Thu, 22 Feb 2024 14:35:55 -0300 Subject: [PATCH] Use metadata endpoint to find DL url Closes #450. --- .github/workflows/build.yml | 26 +++++++++++- README.md | 13 +++++- install.js | 85 ++++++++++++++++++++++++------------- package-lock.json | 4 +- package.json | 2 +- 5 files changed, 94 insertions(+), 36 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 195c09c..62cfdc2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -167,7 +167,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 21.x registry-url: "https://registry.npmjs.org" cache: npm - run: | @@ -184,6 +184,30 @@ jobs: - run: ./test-driver.sh name: Verify install + build_legacy: + name: Build with legacy cdn url + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 21.x + registry-url: "https://registry.npmjs.org" + cache: npm + - run: | + node --version + npm --version + export CHROMEDRIVER_VERSION=LATEST_113 + npm ci + name: Install npm dependencies + - run: | + set -euo pipefail + sudo apt-get update + sudo apt-get install -y libnss3 + name: Install OS dependencies + - run: ./test-driver.sh + name: Verify install + publish: permissions: contents: read diff --git a/README.md b/README.md index d457233..feeb6c9 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,17 @@ See [Chrome for Testing](https://googlechromelabs.github.io/chrome-for-testing/) how these urls work. Npm config: -For metadata use `chromedriver_cdnurl`. The default is `https://googlechromelabs.github.io`. -For binaries use `chromedriver_cdnbinariesurl`. The default is `https://storage.googleapis.com/chrome-for-testing-public`. + +For metadata use `chromedriver_cdnurl`. The default is `https://googlechromelabs.github.io`. You need to either supply the binary download endpoint, or the binaries url config, see bellow. + +For binaries use `chromedriver_cdnbinariesurl`. The default is to search for the download url using +`$chromedriver_cdnurl/chrome-for-testing/[version].json`, which forms a URL like: +https://googlechromelabs.github.io/chrome-for-testing/122.0.6261.57.json. + +The resulting url will be something like: +https://storage.googleapis.com/chrome-for-testing-public/122.0.6261.57/linux64/chromedriver-linux64.zip. + +Keep in mind that this last url is just an example and it might change (as it has happened in the past). ```shell npm install chromedriver --chromedriver_cdnurl=https://npmmirror.com/metadata --chromedriver_cdnbinariesurl=https://npmmirror.com/binaries diff --git a/install.js b/install.js index ee73978..a34ba89 100644 --- a/install.js +++ b/install.js @@ -54,17 +54,23 @@ if (skipDownload) { const majorVersion = parseInt(chromedriverVersion.split('.')[0]); const useLegacyMethod = majorVersion <= 114; const platform = getPlatform(chromedriverVersion); - let downloadedFile = getDownloadFilePath(useLegacyMethod, tmpPath, platform); - if (!useLegacyMethod) { + const downloadedFile = getDownloadFilePath(useLegacyMethod, tmpPath, platform); + if (!useLegacyMethod) tmpPath = path.join(tmpPath, path.basename(downloadedFile, path.extname(downloadedFile))); - } const chromedriverBinaryFileName = process.platform === 'win32' ? 'chromedriver.exe' : 'chromedriver'; const chromedriverBinaryFilePath = path.resolve(tmpPath, chromedriverBinaryFileName); const chromedriverIsAvailable = await verifyIfChromedriverIsAvailableAndHasCorrectVersion(chromedriverVersion, chromedriverBinaryFilePath); if (!chromedriverIsAvailable) { console.log('Current existing ChromeDriver binary is unavailable, proceeding with download and extraction.'); - const cdnBinariesUrl = (process.env.npm_config_chromedriver_cdnbinariesurl || process.env.CHROMEDRIVER_CDNBINARIESURL || 'https://storage.googleapis.com/chrome-for-testing-public').replace(/\/+$/, ''); - downloadedFile = await downloadFile(useLegacyMethod ? legacyCdnUrl : cdnBinariesUrl, useLegacyMethod, downloadedFile, chromedriverVersion, platform); + const configuredfilePath = process.env.npm_config_chromedriver_filepath || process.env.CHROMEDRIVER_FILEPATH; + if (configuredfilePath) { + console.log('Using file: ', configuredfilePath); + return configuredfilePath; + } + if (useLegacyMethod) + await downloadFileLegacy(legacyCdnUrl, downloadedFile, chromedriverVersion); + else + await downloadFile(cdnUrl, downloadedFile, chromedriverVersion, platform); await extractDownload(extractDirectory, chromedriverBinaryFilePath, downloadedFile); } const libPath = path.join(__dirname, 'lib', 'chromedriver'); @@ -86,14 +92,14 @@ function getPlatform(chromedriverVersion) { if (process.arch === 'arm64' || process.arch === 's390x' || process.arch === 'x64') { return 'linux64'; } else { - console.log('Only Linux 64 bits supported.'); + console.error('Only Linux 64 bits supported.'); process.exit(1); } } else if (thePlatform === 'darwin' || thePlatform === 'freebsd') { const osxPlatform = getMacOsRealArch(chromedriverVersion); if (!osxPlatform) { - console.log('Only Mac 64 bits supported.'); + console.error('Only Mac 64 bits supported.'); process.exit(1); } @@ -104,36 +110,38 @@ function getPlatform(chromedriverVersion) { } return (process.arch === 'x64') ? 'win64' : 'win32'; } - - console.log('Unexpected platform or architecture:', process.platform, process.arch); + console.error('Unexpected platform or architecture:', process.platform, process.arch); process.exit(1); } /** * @param {string} cdnUrl - * @param {boolean} useLegacyDownloadMethod * @param {string} downloadedFile * @param {string} chromedriverVersion * @param {string} platform */ -async function downloadFile(cdnUrl, useLegacyDownloadMethod, downloadedFile, chromedriverVersion, platform) { - const configuredfilePath = process.env.npm_config_chromedriver_filepath || process.env.CHROMEDRIVER_FILEPATH; - if (configuredfilePath) { - console.log('Using file: ', configuredfilePath); - return configuredfilePath; - } else { - const fileName = path.basename(downloadedFile); - if (useLegacyDownloadMethod) { - const formattedDownloadUrl = `${cdnUrl}/${chromedriverVersion}/${fileName}`; - console.log('Downloading from file: ', formattedDownloadUrl); - await requestBinary(getRequestOptions(formattedDownloadUrl), downloadedFile); - } else { - const formattedDownloadUrl = `${cdnUrl}/${chromedriverVersion}/${platform}/${fileName}`; - console.log('Downloading from file: ', formattedDownloadUrl); - await requestBinary(getRequestOptions(formattedDownloadUrl), downloadedFile); - } - return downloadedFile; +async function downloadFile(cdnUrl, downloadedFile, chromedriverVersion, platform) { + const cdnBinariesUrl = (process.env.npm_config_chromedriver_cdnbinariesurl || process.env.CHROMEDRIVER_CDNBINARIESURL)?.replace(/\/+$/, ''); + const url = cdnBinariesUrl + ? `${cdnBinariesUrl}/${chromedriverVersion}/${platform}/${path.basename(downloadedFile)}` + : await getDownloadUrl(cdnUrl, chromedriverVersion, platform); + if (!url) { + console.error(`Download url could not be found for version ${chromedriverVersion} and platform '${platform}'`); + process.exit(1); } + console.log('Downloading from file: ', url); + await requestBinary(getRequestOptions(url), downloadedFile); +} + +/** + * @param {string} cdnUrl + * @param {string} downloadedFile + * @param {string} chromedriverVersion + */ +async function downloadFileLegacy(cdnUrl, downloadedFile, chromedriverVersion) { + const url = `${cdnUrl}/${chromedriverVersion}/${path.basename(downloadedFile)}`; + console.log('Downloading from file: ', url); + await requestBinary(getRequestOptions(url), downloadedFile); } /** @@ -309,6 +317,21 @@ async function getChromeDriverVersion(cdnUrl, legacyCdnUrl, majorVersion) { } } +/** + * @param {string} cdnUrl + * @param {string} version + * @param {string} platform + * @returns {Promise<[string]>} + */ +async function getDownloadUrl(cdnUrl, version, platform) { + const getUrlUrl = `${cdnUrl}/chrome-for-testing/${version}.json`; + const requestOptions = getRequestOptions(getUrlUrl); + // @ts-expect-error + const response = await axios.request(requestOptions); + const url = response.data?.downloads?.chromedriver?.find((/** @type {{ platform: string; }} */ c) => c.platform == platform)?.url; + return url; +} + /** * * @param {import('axios').AxiosRequestConfig} requestOptions @@ -321,11 +344,12 @@ async function requestBinary(requestOptions, filePath) { // @ts-expect-error response = await axios.request({ responseType: 'stream', ...requestOptions }); } catch (error) { + let errorData = ''; if (error && error.response) { if (error.response.status) console.error('Error status code:', error.response.status); if (error.response.data) { - error.response.data.on('data', data => console.error(data.toString('utf8'))); + error.response.data.on('data', data => errorData += data.toString('utf8')); try { await finishedAsync(error.response.data); } catch (error) { @@ -333,7 +357,8 @@ async function requestBinary(requestOptions, filePath) { } } } - throw new Error('Error with http(s) request: ' + error); + console.error(`Error with http(s) request:\n${error}\nError data:\n${errorData}`); + process.exit(1); } let count = 0; let notifiedCount = 0; @@ -359,7 +384,7 @@ async function requestBinary(requestOptions, filePath) { */ async function extractDownload(dirToExtractTo, chromedriverBinaryFilePath, downloadedFile) { if (path.extname(downloadedFile) !== '.zip') { - fs.mkdirSync(path.dirname(chromedriverBinaryFilePath), {recursive: true}); + fs.mkdirSync(path.dirname(chromedriverBinaryFilePath), { recursive: true }); fs.copyFileSync(downloadedFile, chromedriverBinaryFilePath); console.log('Skipping zip extraction - binary file found.'); return; diff --git a/package-lock.json b/package-lock.json index c37ba56..a798a34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "chromedriver", - "version": "122.0.0", + "version": "122.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "chromedriver", - "version": "122.0.0", + "version": "122.0.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/package.json b/package.json index 2eaafd6..700b68c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "chromedriver", - "version": "122.0.0", + "version": "122.0.1", "keywords": [ "chromedriver", "selenium"