Skip to content

Commit 15c7bf5

Browse files
committed
fix(MongoBinaryDownload): use "http" module for "USE_HTTP" requests
Also test this request method now fixes #962
1 parent bb6776e commit 15c7bf5

3 files changed

Lines changed: 147 additions & 9 deletions

File tree

packages/mongodb-memory-server-core/src/util/MongoBinaryDownload.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import os from 'os';
22
import { URL } from 'url';
33
import path from 'path';
44
import { promises as fspromises, createWriteStream, createReadStream, constants } from 'fs';
5-
import { https } from 'follow-redirects';
5+
import { https, http } from 'follow-redirects';
66
import { createUnzip } from 'zlib';
77
import tar from 'tar-stream';
88
import yauzl from 'yauzl';
@@ -212,7 +212,6 @@ export class MongoBinaryDownload {
212212
const requestOptions: RequestOptions = {
213213
method: 'GET',
214214
rejectUnauthorized: strictSsl,
215-
protocol: envToBool(resolveConfig(ResolveConfigVariables.USE_HTTP)) ? 'http:' : 'https:',
216215
agent: proxy ? new HttpsProxyAgent(proxy) : undefined,
217216
};
218217

@@ -492,7 +491,9 @@ export class MongoBinaryDownload {
492491
return new Promise((resolve, reject) => {
493492
log(`httpDownload: trying to download "${downloadUrl}"`);
494493

495-
const request = https.get(url, useHttpsOptions, async (response) => {
494+
const protocol = envToBool(resolveConfig(ResolveConfigVariables.USE_HTTP)) ? http : https;
495+
496+
const request = protocol.get(url, useHttpsOptions, async (response) => {
496497
if (response.statusCode != 200 && response.statusCode != 206) {
497498
if (response.statusCode === 403) {
498499
reject(

packages/mongodb-memory-server-core/src/util/__tests__/MongoBinaryDownload.test.ts

Lines changed: 141 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import * as path from 'path';
1111
import * as yazl from 'yazl';
1212
import { pack } from 'tar-stream';
1313
import { createGzip } from 'zlib';
14-
import { Server, createServer } from 'https';
14+
import https from 'https';
15+
import http from 'http';
1516

1617
describe('MongoBinaryDownload', () => {
1718
let originalTTY: boolean = false;
@@ -425,9 +426,9 @@ describe('MongoBinaryDownload', () => {
425426
});
426427
});
427428

428-
describe('should download correctly', () => {
429+
describe('should download correctly https', () => {
429430
let tmpdir: string;
430-
let server: Server;
431+
let server: https.Server;
431432

432433
let key: string;
433434
let cert: string;
@@ -474,7 +475,7 @@ describe('MongoBinaryDownload', () => {
474475
) {
475476
let isFirstRequest = true;
476477

477-
const builder = createServer(
478+
const builder = https.createServer(
478479
{
479480
key,
480481
cert,
@@ -801,4 +802,140 @@ describe('MongoBinaryDownload', () => {
801802
}
802803
});
803804
});
805+
806+
describe('should download correctly http', () => {
807+
let tmpdir: string;
808+
let server: http.Server;
809+
810+
const totalBytes = 1024 * 10;
811+
812+
let originalUseHttp: any;
813+
814+
beforeAll(async () => {
815+
originalUseHttp = process.env[envName(ResolveConfigVariables.USE_HTTP)];
816+
});
817+
818+
beforeEach(async () => {
819+
tmpdir = await utils.createTmpDir('mongo-mem-test-download-');
820+
821+
process.env[envName(ResolveConfigVariables.USE_HTTP)] = 'true';
822+
});
823+
afterEach(async () => {
824+
await utils.removeDir(tmpdir);
825+
826+
if (server) {
827+
await new Promise((res) => {
828+
server.close(res);
829+
});
830+
}
831+
832+
jest.restoreAllMocks();
833+
});
834+
835+
afterAll(() => {
836+
process.env[envName(ResolveConfigVariables.USE_HTTP)] = originalUseHttp;
837+
});
838+
839+
function createTestServer() {
840+
const builder = http.createServer({}, (req, res) => {
841+
if (req.url != '/archive.tgz') {
842+
res.writeHead(404, { 'Content-Type': 'application/json' });
843+
res.end(JSON.stringify({ error: `Invalid Path ${req.url}` }));
844+
845+
return;
846+
}
847+
848+
let toSendBytes = totalBytes;
849+
let rangeStart = 0;
850+
851+
if (req.headers.range) {
852+
rangeStart = parseInt(req.headers.range.match(/bytes=(\d+)-/)?.[1] ?? '0');
853+
toSendBytes = totalBytes - rangeStart;
854+
}
855+
856+
res.writeHead(200, {
857+
'Content-Type': 'application/gzip',
858+
'Content-Length': toSendBytes,
859+
'Accept-Ranges': 'bytes',
860+
});
861+
862+
const buffer = genBuffer(toSendBytes, rangeStart);
863+
864+
res.write(buffer);
865+
866+
res.end();
867+
});
868+
869+
server = builder.listen(5000);
870+
}
871+
872+
/** Generate 4 bytes 00, then 4 bytes FF until "toGen" */
873+
function genBuffer(toGen: number, offset: number) {
874+
const buffer = Buffer.alloc(toGen);
875+
876+
for (let i = 0; i < toGen; i++) {
877+
const byteId = offset + i;
878+
879+
if (byteId % 8 < 4) {
880+
buffer.writeUInt8(0, i);
881+
} else {
882+
buffer.writeUInt8(255, i);
883+
}
884+
}
885+
886+
return buffer;
887+
}
888+
889+
it('should correctly allow HTTP requests', async () => {
890+
jest.spyOn(console, 'log').mockImplementation(() => void 0);
891+
createTestServer();
892+
893+
const downloadDir = path.join(tmpdir, 'downloadDir');
894+
895+
await utils.mkdir(downloadDir);
896+
897+
const outfile = path.join(downloadDir, 'archive.tgz');
898+
const tmpfile = outfile + '.downloading';
899+
900+
const options: MongoBinaryOpts = {
901+
arch: 'x64',
902+
downloadDir,
903+
os: {
904+
os: 'linux',
905+
dist: 'Ubuntu Linux',
906+
release: '24.04',
907+
},
908+
version: '8.0.0',
909+
};
910+
const mbd = new MongoBinaryDownload(options);
911+
mbd.isTTY = false;
912+
913+
const resolved = await mbd.httpDownload(
914+
new URL('http://localhost:5000/archive.tgz'),
915+
{
916+
rejectUnauthorized: false,
917+
},
918+
outfile,
919+
tmpfile,
920+
1,
921+
0,
922+
1000
923+
);
924+
925+
expect(resolved).toStrictEqual(outfile);
926+
927+
const stat = await utils.statPath(outfile);
928+
929+
expect(stat).not.toBeUndefined();
930+
utils.assertion(stat !== undefined); // for types
931+
932+
expect(stat.size).toStrictEqual(totalBytes);
933+
934+
const buffer = await fspromises.readFile(outfile, null);
935+
936+
const expected = genBuffer(totalBytes, 0);
937+
938+
expect(buffer).toStrictEqual(expected);
939+
});
940+
});
804941
});

packages/mongodb-memory-server-core/src/util/__tests__/__snapshots__/MongoBinaryDownload.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ exports[`MongoBinaryDownload extract() should extract zip archives 1`] = `"main
66

77
exports[`MongoBinaryDownload makeMD5check throws an error if md5 of downloaded mongoDBArchive is NOT the same as in the reference result 1`] = `"{\\"binarymd5\\":\\"anotherMD5\\",\\"checkfilemd5\\":\\"someMD5\\"}"`;
88

9-
exports[`MongoBinaryDownload should download correctly should error of repeated retry errors 1`] = `"{\\"url\\":\\"https://localhost:5000/archive.tgz\\",\\"msg\\":\\"aborted\\",\\"code\\":\\"ECONNRESET\\",\\"maxRetries\\":2,\\"attempts\\":2}"`;
9+
exports[`MongoBinaryDownload should download correctly https should error of repeated retry errors 1`] = `"{\\"url\\":\\"https://localhost:5000/archive.tgz\\",\\"msg\\":\\"aborted\\",\\"code\\":\\"ECONNRESET\\",\\"maxRetries\\":2,\\"attempts\\":2}"`;
1010

11-
exports[`MongoBinaryDownload should download correctly should error on 403 without retrying 1`] = `"{\\"url\\":\\"https://localhost:5000/archive.tgz\\",\\"msg\\":\\"Status Code is 403 (MongoDB's 404)\\\\nThis means that the requested version-platform combination doesn't exist\\\\nTry to use different version 'new MongoMemoryServer({ binary: { version: 'X.Y.Z' } })'\\\\nList of available versions can be found here: https://www.mongodb.com/download-center/community/releases/archive\\",\\"code\\":\\"Status: 403\\",\\"maxRetries\\":3,\\"attempts\\":1}"`;
11+
exports[`MongoBinaryDownload should download correctly https should error on 403 without retrying 1`] = `"{\\"url\\":\\"https://localhost:5000/archive.tgz\\",\\"msg\\":\\"Status Code is 403 (MongoDB's 404)\\\\nThis means that the requested version-platform combination doesn't exist\\\\nTry to use different version 'new MongoMemoryServer({ binary: { version: 'X.Y.Z' } })'\\\\nList of available versions can be found here: https://www.mongodb.com/download-center/community/releases/archive\\",\\"code\\":\\"Status: 403\\",\\"maxRetries\\":3,\\"attempts\\":1}"`;
1212

1313
exports[`MongoBinaryDownload should passthrough options to MongoBinaryDownloadUrl 1`] = `"/path/to/somewhere/mongod-x64-custom-4.0.0"`;

0 commit comments

Comments
 (0)