Skip to content

Commit b3665ed

Browse files
ChrisSGnodkz
authored andcommitted
feat: add proxy support (thanks @ChrisSG)
* Adds proxy support * adds tests for downloadOptions and proxy * sets tabsize to 2 spaces * added https-proxy-agent dependency * fixes linter errors * adds types to new functions * refactors setting https agent * fixes bug for setting agent * fixes linter errors * revert: changes for MongoBinaryDownloadUrl This class only provide URL where can be obtained binaries for current platform. * refactor: MongoBinaryDownload now determine proxy settings from ENV vars This class handle downloading, so better place for proxy setup is here. * fix: small other fixes * chore: update dependencies
1 parent 16eb7e5 commit b3665ed

File tree

7 files changed

+1547
-1384
lines changed

7 files changed

+1547
-1384
lines changed

.eslintrc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
"trailingComma": "es5",
2525
}],
2626
"no-prototype-builtins": 0,
27-
"prefer-destructuring": 0
27+
"prefer-destructuring": 0,
28+
"no-else-return": 0,
29+
"lines-between-class-members": ["error", "always", { exceptAfterSingleLine: true }],
2830
},
2931
"env": {
3032
"jasmine": true,

package.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,15 @@
3333
"babel-plugin-transform-runtime": "^6.23.0",
3434
"babel-preset-env": "^1.7.0",
3535
"cz-conventional-changelog": "^2.1.0",
36-
"eslint": "^4.19.1",
37-
"eslint-config-airbnb-base": "^12.1.0",
36+
"eslint": "^5.0.1",
37+
"eslint-config-airbnb-base": "^13.0.0",
3838
"eslint-config-prettier": "^2.9.0",
3939
"eslint-plugin-flowtype": "^2.49.3",
4040
"eslint-plugin-import": "^2.12.0",
4141
"eslint-plugin-prettier": "^2.6.0",
42-
"flow-bin": "^0.74.0",
42+
"flow-bin": "^0.75.0",
4343
"jest": "^23.1.0",
44-
"mongodb": "3.1.0-beta4",
44+
"mongodb": "3.1.0",
4545
"npm-run-all": "^4.1.3",
4646
"prettier": "^1.13.5",
4747
"rimraf": "^2.6.2",
@@ -54,11 +54,10 @@
5454
"fs-extra": "^6.0.1",
5555
"get-port": "^3.2.0",
5656
"getos": "^3.1.0",
57+
"https-proxy-agent": "^2.2.1",
5758
"lockfile": "^1.0.4",
5859
"md5-file": "^4.0.0",
5960
"mkdirp": "^0.5.1",
60-
"request": "^2.87.0",
61-
"request-promise": "^4.2.2",
6261
"tmp": "^0.0.33",
6362
"uuid": "^3.2.1"
6463
},

src/util/MongoBinaryDownload.js

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
/* eslint-disable class-methods-use-this */
33

44
import os from 'os';
5+
import url from 'url';
56
import path from 'path';
67
import fs from 'fs-extra';
7-
import request from 'request-promise';
88
import md5File from 'md5-file';
99
import https from 'https';
10+
import HttpsProxyAgent from 'https-proxy-agent';
1011
import decompress from 'decompress';
1112
import MongoBinaryDownloadUrl from './MongoBinaryDownloadUrl';
1213

@@ -64,7 +65,7 @@ export default class MongoBinaryDownload {
6465
return mongodPath;
6566
}
6667

67-
const mongoDBArchive = await this.download();
68+
const mongoDBArchive = await this.startDownload();
6869
await this.extract(mongoDBArchive);
6970
fs.unlinkSync(mongoDBArchive);
7071

@@ -75,34 +76,66 @@ export default class MongoBinaryDownload {
7576
throw new Error(`Cannot find downloaded mongod binary by path ${mongodPath}`);
7677
}
7778

78-
async download(): Promise<string> {
79+
async startDownload(): Promise<string> {
7980
const mbdUrl = new MongoBinaryDownloadUrl({
8081
platform: this.platform,
8182
arch: this.arch,
8283
version: this.version,
8384
});
8485

8586
await fs.ensureDir(this.downloadDir);
86-
const url = await mbdUrl.getDownloadUrl();
87-
const archName = await mbdUrl.getArchiveName();
88-
const downloadLocation = path.resolve(this.downloadDir, archName);
89-
console.log('Downloading MongoDB:', url);
90-
const tempDownloadLocation = path.resolve(this.downloadDir, `${archName}.downloading`);
91-
const mongoDBArchive = await this.httpDownload(url, downloadLocation, tempDownloadLocation);
92-
const md5Remote = await this.downloadMD5(`${url}.md5`);
87+
88+
const downloadUrl = await mbdUrl.getDownloadUrl();
89+
const mongoDBArchive = await this.download(downloadUrl);
90+
91+
const mongoDBArchiveMd5 = await this.download(`${downloadUrl}.md5`);
92+
await this.checkMd5(mongoDBArchiveMd5, mongoDBArchive);
93+
94+
return mongoDBArchive;
95+
}
96+
97+
async checkMd5(mongoDBArchiveMd5: string, mongoDBArchive: string) {
98+
const signatureContent = (await fs.readFile(mongoDBArchiveMd5)).toString('UTF-8');
99+
const md5Remote = signatureContent.match(/(.*?)\s/)[1];
93100
const md5Local = md5File.sync(mongoDBArchive);
94101
if (md5Remote !== md5Local) {
95102
throw new Error('MongoBinaryDownload: md5 check is failed');
96103
}
97-
return mongoDBArchive;
98104
}
99105

100-
async downloadMD5(md5url: string): Promise<string> {
101-
const signatureContent = await request(md5url);
102-
this.debug(`getDownloadMD5Hash content: ${signatureContent}`);
103-
const signature = signatureContent.match(/(.*?)\s/)[1];
104-
this.debug(`getDownloadMD5Hash extracted signature: ${signature}`);
105-
return signature;
106+
async download(downloadUrl: string) {
107+
const proxy =
108+
process.env['yarn_https-proxy'] ||
109+
process.env.yarn_proxy ||
110+
process.env['npm_config_https-proxy'] ||
111+
process.env.npm_config_proxy ||
112+
process.env.https_proxy ||
113+
process.env.http_proxy;
114+
115+
const urlObject = url.parse(downloadUrl);
116+
117+
const downloadOptions = {
118+
hostname: urlObject.hostname,
119+
port: urlObject.port || 443,
120+
path: urlObject.path,
121+
method: 'GET',
122+
agent: proxy ? new HttpsProxyAgent(proxy) : undefined,
123+
};
124+
125+
const filename = (urlObject.pathname || '').split('/').pop();
126+
if (!filename) {
127+
throw new Error(`MongoBinaryDownload: missing filename for url ${downloadUrl}`);
128+
}
129+
130+
const downloadLocation = path.resolve(this.downloadDir, filename);
131+
const tempDownloadLocation = path.resolve(this.downloadDir, `${filename}.downloading`);
132+
console.log(`Downloading${proxy ? ` via proxy ${proxy}` : ''}:`, downloadUrl);
133+
const downloadedFile = await this.httpDownload(
134+
downloadOptions,
135+
downloadLocation,
136+
tempDownloadLocation
137+
);
138+
return downloadedFile;
106139
}
107140

108141
async extract(mongoDBArchive: string): Promise<string> {

src/util/MongoBinaryDownloadUrl.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ type OS = {
88
release?: string,
99
};
1010

11-
const DOWNLOAD_URI = 'https://fastdl.mongodb.org';
12-
1311
export type MongoBinaryDownloadUrlOpts = {
1412
version: string,
1513
platform: string,
@@ -32,7 +30,7 @@ export default class MongoBinaryDownloadUrl {
3230

3331
async getDownloadUrl(): Promise<string> {
3432
const archive = await this.getArchiveName();
35-
return `${DOWNLOAD_URI}/${this.platform}/${archive}`;
33+
return `https://fastdl.mongodb.org/${this.platform}/${archive}`;
3634
}
3735

3836
async getArchiveName(): Promise<string> {

src/util/__tests__/MongoBinary-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import tmp from 'tmp';
44
import MongoBinary from '../MongoBinary';
55

66
tmp.setGracefulCleanup();
7-
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
7+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 160000;
88

99
describe('MongoBinary', () => {
1010
it('should download binary and keep it in cache', async () => {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* @flow */
2+
3+
import MongoBinaryDownload from '../MongoBinaryDownload';
4+
5+
describe('MongoBinaryDownload', () => {
6+
it('should use direct download', async () => {
7+
process.env['yarn_https-proxy'] = '';
8+
process.env.yarn_proxy = '';
9+
process.env['npm_config_https-proxy'] = '';
10+
process.env.npm_config_proxy = '';
11+
process.env.https_proxy = '';
12+
process.env.http_proxy = '';
13+
14+
const du = new MongoBinaryDownload({});
15+
// $FlowFixMe
16+
du.httpDownload = jest.fn();
17+
18+
await du.download('https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.3.tgz');
19+
expect(du.httpDownload).toHaveBeenCalledTimes(1);
20+
const callArg1 = du.httpDownload.mock.calls[0][0];
21+
expect(callArg1.agent).toBeUndefined();
22+
});
23+
24+
it('should pick up proxy from env vars', async () => {
25+
process.env['yarn_https-proxy'] = 'http://user:pass@proxy:8080';
26+
27+
const du = new MongoBinaryDownload({});
28+
// $FlowFixMe
29+
du.httpDownload = jest.fn();
30+
31+
await du.download('https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-3.6.3.tgz');
32+
expect(du.httpDownload).toHaveBeenCalledTimes(1);
33+
const callArg1 = du.httpDownload.mock.calls[0][0];
34+
expect(callArg1.agent).toBeDefined();
35+
expect(callArg1.agent.options.href).toBe('http://user:pass@proxy:8080/');
36+
});
37+
});

0 commit comments

Comments
 (0)