Skip to content

Commit 6c14fa7

Browse files
committed
Use metadata endpoint to find DL url
Closes #450.
1 parent 4da3f80 commit 6c14fa7

File tree

5 files changed

+94
-36
lines changed

5 files changed

+94
-36
lines changed

.github/workflows/build.yml

+25-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ jobs:
167167
- uses: actions/checkout@v4
168168
- uses: actions/setup-node@v4
169169
with:
170-
node-version: 20.x
170+
node-version: 21.x
171171
registry-url: "https://registry.npmjs.org"
172172
cache: npm
173173
- run: |
@@ -184,6 +184,30 @@ jobs:
184184
- run: ./test-driver.sh
185185
name: Verify install
186186

187+
build_legacy:
188+
name: Build with legacy cdn url
189+
runs-on: ubuntu-latest
190+
steps:
191+
- uses: actions/checkout@v4
192+
- uses: actions/setup-node@v4
193+
with:
194+
node-version: 21.x
195+
registry-url: "https://registry.npmjs.org"
196+
cache: npm
197+
- run: |
198+
node --version
199+
npm --version
200+
export CHROMEDRIVER_VERSION=LATEST_113
201+
npm ci
202+
name: Install npm dependencies
203+
- run: |
204+
set -euo pipefail
205+
sudo apt-get update
206+
sudo apt-get install -y libnss3
207+
name: Install OS dependencies
208+
- run: ./test-driver.sh
209+
name: Verify install
210+
187211
publish:
188212
permissions:
189213
contents: read

README.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,17 @@ See [Chrome for Testing](https://googlechromelabs.github.io/chrome-for-testing/)
6868
how these urls work.
6969

7070
Npm config:
71-
For metadata use `chromedriver_cdnurl`. The default is `https://googlechromelabs.github.io`.
72-
For binaries use `chromedriver_cdnbinariesurl`. The default is `https://storage.googleapis.com/chrome-for-testing-public`.
71+
72+
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.
73+
74+
For binaries use `chromedriver_cdnbinariesurl`. The default is to search for the download url using
75+
`$chromedriver_cdnurl/chrome-for-testing/[version].json`, which forms a URL like:
76+
https://googlechromelabs.github.io/chrome-for-testing/122.0.6261.57.json.
77+
78+
The resulting url will be something like:
79+
https://storage.googleapis.com/chrome-for-testing-public/122.0.6261.57/linux64/chromedriver-linux64.zip.
80+
81+
Keep in mind that this last url is just an example and it might change (as it has happened in the past).
7382

7483
```shell
7584
npm install chromedriver --chromedriver_cdnurl=https://npmmirror.com/metadata --chromedriver_cdnbinariesurl=https://npmmirror.com/binaries

install.js

+55-30
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,23 @@ if (skipDownload) {
5454
const majorVersion = parseInt(chromedriverVersion.split('.')[0]);
5555
const useLegacyMethod = majorVersion <= 114;
5656
const platform = getPlatform(chromedriverVersion);
57-
let downloadedFile = getDownloadFilePath(useLegacyMethod, tmpPath, platform);
58-
if (!useLegacyMethod) {
57+
const downloadedFile = getDownloadFilePath(useLegacyMethod, tmpPath, platform);
58+
if (!useLegacyMethod)
5959
tmpPath = path.join(tmpPath, path.basename(downloadedFile, path.extname(downloadedFile)));
60-
}
6160
const chromedriverBinaryFileName = process.platform === 'win32' ? 'chromedriver.exe' : 'chromedriver';
6261
const chromedriverBinaryFilePath = path.resolve(tmpPath, chromedriverBinaryFileName);
6362
const chromedriverIsAvailable = await verifyIfChromedriverIsAvailableAndHasCorrectVersion(chromedriverVersion, chromedriverBinaryFilePath);
6463
if (!chromedriverIsAvailable) {
6564
console.log('Current existing ChromeDriver binary is unavailable, proceeding with download and extraction.');
66-
const cdnBinariesUrl = (process.env.npm_config_chromedriver_cdnbinariesurl || process.env.CHROMEDRIVER_CDNBINARIESURL || 'https://storage.googleapis.com/chrome-for-testing-public').replace(/\/+$/, '');
67-
downloadedFile = await downloadFile(useLegacyMethod ? legacyCdnUrl : cdnBinariesUrl, useLegacyMethod, downloadedFile, chromedriverVersion, platform);
65+
const configuredfilePath = process.env.npm_config_chromedriver_filepath || process.env.CHROMEDRIVER_FILEPATH;
66+
if (configuredfilePath) {
67+
console.log('Using file: ', configuredfilePath);
68+
return configuredfilePath;
69+
}
70+
if (useLegacyMethod)
71+
await downloadFileLegacy(legacyCdnUrl, downloadedFile, chromedriverVersion);
72+
else
73+
await downloadFile(cdnUrl, downloadedFile, chromedriverVersion, platform);
6874
await extractDownload(extractDirectory, chromedriverBinaryFilePath, downloadedFile);
6975
}
7076
const libPath = path.join(__dirname, 'lib', 'chromedriver');
@@ -86,14 +92,14 @@ function getPlatform(chromedriverVersion) {
8692
if (process.arch === 'arm64' || process.arch === 's390x' || process.arch === 'x64') {
8793
return 'linux64';
8894
} else {
89-
console.log('Only Linux 64 bits supported.');
95+
console.error('Only Linux 64 bits supported.');
9096
process.exit(1);
9197
}
9298
} else if (thePlatform === 'darwin' || thePlatform === 'freebsd') {
9399
const osxPlatform = getMacOsRealArch(chromedriverVersion);
94100

95101
if (!osxPlatform) {
96-
console.log('Only Mac 64 bits supported.');
102+
console.error('Only Mac 64 bits supported.');
97103
process.exit(1);
98104
}
99105

@@ -104,36 +110,38 @@ function getPlatform(chromedriverVersion) {
104110
}
105111
return (process.arch === 'x64') ? 'win64' : 'win32';
106112
}
107-
108-
console.log('Unexpected platform or architecture:', process.platform, process.arch);
113+
console.error('Unexpected platform or architecture:', process.platform, process.arch);
109114
process.exit(1);
110115
}
111116

112117
/**
113118
* @param {string} cdnUrl
114-
* @param {boolean} useLegacyDownloadMethod
115119
* @param {string} downloadedFile
116120
* @param {string} chromedriverVersion
117121
* @param {string} platform
118122
*/
119-
async function downloadFile(cdnUrl, useLegacyDownloadMethod, downloadedFile, chromedriverVersion, platform) {
120-
const configuredfilePath = process.env.npm_config_chromedriver_filepath || process.env.CHROMEDRIVER_FILEPATH;
121-
if (configuredfilePath) {
122-
console.log('Using file: ', configuredfilePath);
123-
return configuredfilePath;
124-
} else {
125-
const fileName = path.basename(downloadedFile);
126-
if (useLegacyDownloadMethod) {
127-
const formattedDownloadUrl = `${cdnUrl}/${chromedriverVersion}/${fileName}`;
128-
console.log('Downloading from file: ', formattedDownloadUrl);
129-
await requestBinary(getRequestOptions(formattedDownloadUrl), downloadedFile);
130-
} else {
131-
const formattedDownloadUrl = `${cdnUrl}/${chromedriverVersion}/${platform}/${fileName}`;
132-
console.log('Downloading from file: ', formattedDownloadUrl);
133-
await requestBinary(getRequestOptions(formattedDownloadUrl), downloadedFile);
134-
}
135-
return downloadedFile;
123+
async function downloadFile(cdnUrl, downloadedFile, chromedriverVersion, platform) {
124+
const cdnBinariesUrl = (process.env.npm_config_chromedriver_cdnbinariesurl || process.env.CHROMEDRIVER_CDNBINARIESURL)?.replace(/\/+$/, '');
125+
const url = cdnBinariesUrl
126+
? `${cdnBinariesUrl}/${chromedriverVersion}/${platform}/${path.basename(downloadedFile)}`
127+
: await getDownloadUrl(cdnUrl, chromedriverVersion, platform);
128+
if (!url) {
129+
console.error(`Download url could not be found for version ${chromedriverVersion} and platform '${platform}'`);
130+
process.exit(1);
136131
}
132+
console.log('Downloading from file: ', url);
133+
await requestBinary(getRequestOptions(url), downloadedFile);
134+
}
135+
136+
/**
137+
* @param {string} cdnUrl
138+
* @param {string} downloadedFile
139+
* @param {string} chromedriverVersion
140+
*/
141+
async function downloadFileLegacy(cdnUrl, downloadedFile, chromedriverVersion) {
142+
const url = `${cdnUrl}/${chromedriverVersion}/${path.basename(downloadedFile)}`;
143+
console.log('Downloading from file: ', url);
144+
await requestBinary(getRequestOptions(url), downloadedFile);
137145
}
138146

139147
/**
@@ -309,6 +317,21 @@ async function getChromeDriverVersion(cdnUrl, legacyCdnUrl, majorVersion) {
309317
}
310318
}
311319

320+
/**
321+
* @param {string} cdnUrl
322+
* @param {string} version
323+
* @param {string} platform
324+
* @returns {Promise<[string]>}
325+
*/
326+
async function getDownloadUrl(cdnUrl, version, platform) {
327+
const getUrlUrl = `${cdnUrl}/chrome-for-testing/${version}.json`;
328+
const requestOptions = getRequestOptions(getUrlUrl);
329+
// @ts-expect-error
330+
const response = await axios.request(requestOptions);
331+
const url = response.data?.downloads?.chromedriver?.find((/** @type {{ platform: string; }} */ c) => c.platform == platform)?.url;
332+
return url;
333+
}
334+
312335
/**
313336
*
314337
* @param {import('axios').AxiosRequestConfig} requestOptions
@@ -321,19 +344,21 @@ async function requestBinary(requestOptions, filePath) {
321344
// @ts-expect-error
322345
response = await axios.request({ responseType: 'stream', ...requestOptions });
323346
} catch (error) {
347+
let errorData = '';
324348
if (error && error.response) {
325349
if (error.response.status)
326350
console.error('Error status code:', error.response.status);
327351
if (error.response.data) {
328-
error.response.data.on('data', data => console.error(data.toString('utf8')));
352+
error.response.data.on('data', data => errorData += data.toString('utf8'));
329353
try {
330354
await finishedAsync(error.response.data);
331355
} catch (error) {
332356
console.error('Error downloading entire response:', error);
333357
}
334358
}
335359
}
336-
throw new Error('Error with http(s) request: ' + error);
360+
console.error(`Error with http(s) request:\n${error}\nError data:\n${errorData}`);
361+
process.exit(1);
337362
}
338363
let count = 0;
339364
let notifiedCount = 0;
@@ -359,7 +384,7 @@ async function requestBinary(requestOptions, filePath) {
359384
*/
360385
async function extractDownload(dirToExtractTo, chromedriverBinaryFilePath, downloadedFile) {
361386
if (path.extname(downloadedFile) !== '.zip') {
362-
fs.mkdirSync(path.dirname(chromedriverBinaryFilePath), {recursive: true});
387+
fs.mkdirSync(path.dirname(chromedriverBinaryFilePath), { recursive: true });
363388
fs.copyFileSync(downloadedFile, chromedriverBinaryFilePath);
364389
console.log('Skipping zip extraction - binary file found.');
365390
return;

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chromedriver",
3-
"version": "122.0.0",
3+
"version": "122.0.1",
44
"keywords": [
55
"chromedriver",
66
"selenium"

0 commit comments

Comments
 (0)