Skip to content

Commit

Permalink
Use metadata endpoint to find DL url
Browse files Browse the repository at this point in the history
Closes #450.
  • Loading branch information
giggio committed Feb 22, 2024
1 parent 4da3f80 commit 6c14fa7
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 36 deletions.
26 changes: 25 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand All @@ -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
Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
85 changes: 55 additions & 30 deletions install.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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);
}

Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -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
Expand All @@ -321,19 +344,21 @@ 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) {
console.error('Error downloading entire response:', error);
}
}
}
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;
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "chromedriver",
"version": "122.0.0",
"version": "122.0.1",
"keywords": [
"chromedriver",
"selenium"
Expand Down

0 comments on commit 6c14fa7

Please sign in to comment.