cypress 9.2.0 → 9.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,7 +8,7 @@ const is = require('check-more-types');
8
8
 
9
9
  const os = require('os');
10
10
 
11
- const url = require('url');
11
+ const Url = require('url');
12
12
 
13
13
  const path = require('path');
14
14
 
@@ -36,6 +36,7 @@ const fs = require('../fs');
36
36
  const util = require('../util');
37
37
 
38
38
  const defaultBaseUrl = 'https://download.cypress.io/';
39
+ const defaultMaxRedirects = 10;
39
40
 
40
41
  const getProxyForUrlWithNpmConfig = url => {
41
42
  return getProxyForUrl(url) || process.env.npm_config_https_proxy || process.env.npm_config_proxy || null;
@@ -76,7 +77,7 @@ const getCA = () => {
76
77
  };
77
78
 
78
79
  const prepend = urlPath => {
79
- const endpoint = url.resolve(getBaseUrl(), urlPath);
80
+ const endpoint = Url.resolve(getBaseUrl(), urlPath);
80
81
  const platform = os.platform();
81
82
  return `${endpoint}?platform=${platform}&arch=${arch()}`;
82
83
  };
@@ -183,8 +184,18 @@ const downloadFromUrl = ({
183
184
  url,
184
185
  downloadDestination,
185
186
  progress,
186
- ca
187
+ ca,
188
+ version,
189
+ redirectTTL = defaultMaxRedirects
187
190
  }) => {
191
+ if (redirectTTL <= 0) {
192
+ return Promise.reject(new Error(stripIndent`
193
+ Failed downloading the Cypress binary.
194
+ There were too many redirects. The default allowance is ${defaultMaxRedirects}.
195
+ Maybe you got stuck in a redirect loop?
196
+ `));
197
+ }
198
+
188
199
  return new Promise((resolve, reject) => {
189
200
  const proxy = getProxyForUrlWithNpmConfig(url);
190
201
  debug('Downloading package', {
@@ -192,35 +203,24 @@ const downloadFromUrl = ({
192
203
  proxy,
193
204
  downloadDestination
194
205
  });
195
- let redirectVersion;
196
- const reqOptions = {
197
- url,
198
- proxy,
199
-
200
- followRedirect(response) {
201
- const version = response.headers['x-version'];
202
- debug('redirect version:', version);
203
-
204
- if (version) {
205
- // set the version in options if we have one.
206
- // this insulates us from potential redirect
207
- // problems where version would be set to undefined.
208
- redirectVersion = version;
209
- } // yes redirect
210
-
211
-
212
- return true;
213
- }
214
-
215
- };
216
206
 
217
207
  if (ca) {
218
208
  debug('using custom CA details from npm config');
219
- reqOptions.agentOptions = {
220
- ca
221
- };
222
209
  }
223
210
 
211
+ const reqOptions = {
212
+ uri: url,
213
+ ...(proxy ? {
214
+ proxy
215
+ } : {}),
216
+ ...(ca ? {
217
+ agentOptions: {
218
+ ca
219
+ }
220
+ } : {}),
221
+ method: 'GET',
222
+ followRedirect: false
223
+ };
224
224
  const req = request(reqOptions); // closure
225
225
 
226
226
  let started = null;
@@ -248,18 +248,46 @@ const downloadFromUrl = ({
248
248
  // response headers
249
249
 
250
250
 
251
- started = new Date(); // if our status code does not start with 200
252
-
253
- if (!/^2/.test(response.statusCode)) {
251
+ started = new Date();
252
+
253
+ if (/^3/.test(response.statusCode)) {
254
+ const redirectVersion = response.headers['x-version'];
255
+ const redirectUrl = response.headers.location;
256
+ debug('redirect version:', redirectVersion);
257
+ debug('redirect url:', redirectUrl);
258
+ downloadFromUrl({
259
+ url: redirectUrl,
260
+ progress,
261
+ ca,
262
+ downloadDestination,
263
+ version: redirectVersion,
264
+ redirectTTL: redirectTTL - 1
265
+ }).then(resolve).catch(reject); // if our status code does not start with 200
266
+ } else if (!/^2/.test(response.statusCode)) {
254
267
  debug('response code %d', response.statusCode);
255
268
  const err = new Error(stripIndent`
256
269
  Failed downloading the Cypress binary.
257
270
  Response code: ${response.statusCode}
258
271
  Response message: ${response.statusMessage}
259
272
  `);
260
- reject(err);
273
+ reject(err); // status codes here are all 2xx
274
+ } else {
275
+ // We only enable this pipe connection when we know we've got a successful return
276
+ // and handle the completion with verify and resolve
277
+ // there was a possible race condition between end of request and close of writeStream
278
+ // that is made ordered with this Promise.all
279
+ Promise.all([new Promise(r => {
280
+ return response.pipe(fs.createWriteStream(downloadDestination).on('close', r));
281
+ }), new Promise(r => response.on('end', r))]).then(() => {
282
+ debug('downloading finished');
283
+ verifyDownloadedFile(downloadDestination, expectedSize, expectedChecksum).then(() => debug('verified')).then(() => resolve(version)).catch(reject);
284
+ });
261
285
  }
262
- }).on('error', reject).on('progress', state => {
286
+ }).on('error', e => {
287
+ if (e.code === 'ECONNRESET') return; // sometimes proxies give ECONNRESET but we don't care
288
+
289
+ reject(e);
290
+ }).on('progress', state => {
263
291
  // total time we've elapsed
264
292
  // starting on our first progress notification
265
293
  const elapsed = new Date() - started; // request-progress sends a value between 0 and 1
@@ -268,12 +296,6 @@ const downloadFromUrl = ({
268
296
  const eta = util.calculateEta(percentage, elapsed); // send up our percent and seconds remaining
269
297
 
270
298
  progress.onProgress(percentage, util.secsRemaining(eta));
271
- }) // save this download here
272
- .pipe(fs.createWriteStream(downloadDestination)).on('finish', () => {
273
- debug('downloading finished');
274
- verifyDownloadedFile(downloadDestination, expectedSize, expectedChecksum).then(() => {
275
- return resolve(redirectVersion);
276
- }, reject);
277
299
  });
278
300
  });
279
301
  };
@@ -288,7 +310,8 @@ const start = opts => {
288
310
  let {
289
311
  version,
290
312
  downloadDestination,
291
- progress
313
+ progress,
314
+ redirectTTL
292
315
  } = opts;
293
316
 
294
317
  if (!downloadDestination) {
@@ -316,7 +339,11 @@ const start = opts => {
316
339
  url,
317
340
  downloadDestination,
318
341
  progress,
319
- ca
342
+ ca,
343
+ version,
344
+ ...(redirectTTL ? {
345
+ redirectTTL
346
+ } : {})
320
347
  });
321
348
  }).catch(err => {
322
349
  return prettyDownloadErr(err, version);
@@ -37,7 +37,7 @@ const xvfb = require('../exec/xvfb');
37
37
 
38
38
  const state = require('./state');
39
39
 
40
- const VERIFY_TEST_RUNNER_TIMEOUT_MS = process.env.CYPRESS_VERIFY_TIMEOUT || 30000;
40
+ const VERIFY_TEST_RUNNER_TIMEOUT_MS = +process.env.CYPRESS_VERIFY_TIMEOUT || 30000;
41
41
 
42
42
  const checkExecutable = binaryDir => {
43
43
  const executable = state.getPathToExecutable(binaryDir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress",
3
- "version": "9.2.0",
3
+ "version": "9.2.1",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "postinstall": "node index.js --exec install",
@@ -19,7 +19,7 @@
19
19
  "chalk": "^4.1.0",
20
20
  "check-more-types": "^2.24.0",
21
21
  "cli-cursor": "^3.1.0",
22
- "cli-table3": "~0.6.0",
22
+ "cli-table3": "~0.6.1",
23
23
  "commander": "^5.1.0",
24
24
  "common-tags": "^1.8.0",
25
25
  "dayjs": "^1.10.4",