Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit f1a5d73

Browse files
author
Jan Krems
committed
fix: Fail cleanly when the chromedriver download 404s
1 parent 0d11b83 commit f1a5d73

File tree

4 files changed

+102
-18
lines changed

4 files changed

+102
-18
lines changed

lib/chromedriver/download.js

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
var fs = require('fs');
3434

3535
var async = require('async');
36+
var debug = require('debug')('selenium-download:chromedriver:download');
3637
var fsExtra = require('fs.extra');
3738
var AdmZip = require('adm-zip');
3839
var _ = require('lodash');
@@ -62,9 +63,37 @@ function unzip(tempPath, filePath, callback) {
6263
return move(filePath, tempFilePath, onMoved);
6364
}
6465

66+
function isValidExecutable(filename) {
67+
var stat;
68+
try {
69+
stat = fs.statSync(filename);
70+
} catch (err) {
71+
if (err.code !== 'ENOENT') throw err;
72+
return false;
73+
}
74+
debug('size(%j) = %d', filename, stat.size);
75+
// Quick sanity check - it should be bigger than an elf binary header
76+
return stat.size > 64;
77+
}
78+
79+
function copyReplace(source, dest, callback) {
80+
function onDestUnlinked(err) {
81+
if (err && err.code !== 'ENOENT') {
82+
callback(err);
83+
return;
84+
}
85+
if (!err) {
86+
debug('removed old file at', dest);
87+
}
88+
copy(source, dest, callback);
89+
}
90+
fs.unlink(dest, onDestUnlinked);
91+
}
92+
6593
function downloadChromeDriver(binPath, tempPath, version, url, callback) {
6694
var chromedriverPath = binPath + '/chromedriver';
67-
if (fs.existsSync(chromedriverPath)) {
95+
if (isValidExecutable(chromedriverPath)) {
96+
debug('already downloaded', chromedriverPath);
6897
return callback();
6998
}
7099
var tempFileName = 'chromedriver_' + version;
@@ -77,17 +106,22 @@ function downloadChromeDriver(binPath, tempPath, version, url, callback) {
77106
return fs.chmod(chromedriverPath, '755', callback);
78107
}
79108

80-
if (fs.existsSync(tempFilePath)) {
81-
return copy(tempFilePath, chromedriverPath, makeExecutable);
109+
if (isValidExecutable(tempFilePath)) {
110+
debug('using previous download', tempFilePath);
111+
return copyReplace(tempFilePath, chromedriverPath, makeExecutable);
82112
}
83113

114+
debug('download url', url);
115+
debug('tmp file', tempFilePath);
116+
debug('target file', chromedriverPath);
117+
84118
var unzippedFilePath = tempPath + '/chromedriver' + extension;
85119
return async.waterfall([
86120
_.partial(downloadFile, url, tempPath, tempFileName),
87121
_.partial(validate, tempFilePath),
88122
_.partial(unzip, tempPath, tempFilePath),
89123
_.partial(move, unzippedFilePath, tempFilePath),
90-
_.partial(copy, tempFilePath, chromedriverPath)
124+
_.partial(copyReplace, tempFilePath, chromedriverPath)
91125
], makeExecutable);
92126
}
93127
module.exports = downloadChromeDriver;

lib/download.js

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
var fs = require('fs');
3434
var path = require('path');
3535

36+
var _ = require('lodash');
3637
var request = require('request');
3738

3839
function parseHashes(rawHash) {
@@ -48,20 +49,21 @@ function parseHashes(rawHash) {
4849
}
4950

5051
function downloadWithMD5(url, destinationDir, fileName, callback) {
51-
var hash = null;
52-
var stream = request(url, { gzip: true });
53-
var fileStream = fs.createWriteStream(path.join(destinationDir, fileName));
54-
stream.pipe(fileStream);
55-
stream.on('response', function onResponse(response) {
56-
var rawHash;
57-
rawHash = response.headers['x-goog-hash'];
58-
hash = parseHashes(rawHash).md5;
59-
});
60-
stream.on('error', callback);
61-
fileStream.on('error', callback);
52+
function onResponse(err, response, body) {
53+
if (err) return callback(err);
54+
if (response.statusCode !== 200) {
55+
return callback(new Error(response.statusCode + ' - failed to download ' + url));
56+
}
6257

63-
fileStream.on('close', function returnHash() {
64-
callback(null, hash);
65-
});
58+
var rawHash = response.headers['x-goog-hash'];
59+
if (!rawHash) {
60+
return callback(new Error('Response did not contain a checksum: ' + url));
61+
}
62+
63+
var absoluteFile = path.join(destinationDir, fileName);
64+
return fs.writeFile(absoluteFile, body, _.partial(callback, _, parseHashes(rawHash).md5));
65+
}
66+
67+
request(url, { gzip: true, encoding: null }, onResponse);
6668
}
6769
module.exports = downloadWithMD5;

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"dependencies": {
2828
"adm-zip": "~0.4.4",
2929
"async": "~0.2.10",
30+
"debug": "^2.2.0",
3031
"fs.extra": "^1.2.1",
3132
"lodash": "^4.6.1",
3233
"mkdirp": "~0.3.5",

test/chromedriver/download.test.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
'use strict';
2+
var fs = require('fs');
3+
var os = require('os');
4+
var path = require('path');
5+
6+
var assert = require('assertive');
7+
8+
var downloadChromeDriver = require('../../lib/chromedriver/download');
9+
10+
// Downloaded, started to make sure it works, copied the file size.
11+
var CHROME_DRIVER_SIZE = 10907892;
12+
13+
function tryRemove(filename) {
14+
try {
15+
fs.unlinkSync(filename);
16+
} catch (err) {
17+
if (err.code !== 'ENOENT') throw err;
18+
}
19+
}
20+
21+
describe('downloadChromeDriver', function () {
22+
it('fails cleanly when the file is empty', function (done) {
23+
var tmpDir = os.tmpdir();
24+
var tmpFilePath = path.join(tmpDir, 'chromedriver_0.23');
25+
var driverPath = path.join(tmpDir, 'chromedriver');
26+
27+
var badUrl = 'https://chromedriver.storage.googleapis.com/2.23/chromedriver_mac32.zip';
28+
var goodUrl = 'https://chromedriver.storage.googleapis.com/2.23/chromedriver_mac64.zip';
29+
30+
tryRemove(tmpFilePath);
31+
tryRemove(driverPath);
32+
33+
downloadChromeDriver(tmpDir, tmpDir, '0.23', badUrl, function (expectedError) {
34+
assert.truthy(expectedError);
35+
assert.include('404', expectedError.message);
36+
37+
downloadChromeDriver(tmpDir, tmpDir, '0.23', goodUrl, function (unexpectedError) {
38+
if (unexpectedError) {
39+
done(unexpectedError);
40+
return;
41+
}
42+
assert.equal(CHROME_DRIVER_SIZE, fs.statSync(tmpFilePath).size);
43+
done();
44+
});
45+
});
46+
});
47+
});

0 commit comments

Comments
 (0)