Skip to content

Commit 829d7be

Browse files
authored
fix(NODE-4208): add aws http request timeout handler (#3225)
1 parent 35eeba3 commit 829d7be

File tree

6 files changed

+71
-0
lines changed

6 files changed

+71
-0
lines changed

.evergreen/config.in.yml

+1
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ functions:
599599
working_dir: "src"
600600
script: |
601601
${PREPARE_SHELL}
602+
export IS_EC2=true
602603
${PROJECT_DIRECTORY}/.evergreen/run-mongodb-aws-test.sh
603604
604605
"run aws auth test with aws credentials as environment variables":

.evergreen/config.yml

+1
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ functions:
565565
working_dir: src
566566
script: |
567567
${PREPARE_SHELL}
568+
export IS_EC2=true
568569
${PROJECT_DIRECTORY}/.evergreen/run-mongodb-aws-test.sh
569570
run aws auth test with aws credentials as environment variables:
570571
- command: shell.exec

src/cmap/auth/mongodb_aws.ts

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { Binary, BSONSerializeOptions } from '../../bson';
66
import * as BSON from '../../bson';
77
import { aws4 } from '../../deps';
88
import {
9+
MongoAWSError,
910
MongoCompatibilityError,
1011
MongoMissingCredentialsError,
1112
MongoRuntimeError
@@ -283,6 +284,10 @@ function request(uri: string, _options: RequestOptions | undefined, callback: Ca
283284
});
284285
});
285286

287+
req.on('timeout', () => {
288+
req.destroy(new MongoAWSError(`AWS request to ${uri} timed out after ${options.timeout} ms`));
289+
});
290+
286291
req.on('error', err => callback(err));
287292
req.end();
288293
}

src/error.ts

+17
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,23 @@ export class MongoKerberosError extends MongoRuntimeError {
347347
}
348348
}
349349

350+
/**
351+
* A error generated when the user attempts to authenticate
352+
* via AWS, but fails
353+
*
354+
* @public
355+
* @category Error
356+
*/
357+
export class MongoAWSError extends MongoRuntimeError {
358+
constructor(message: string) {
359+
super(message);
360+
}
361+
362+
override get name(): string {
363+
return 'MongoAWSError';
364+
}
365+
}
366+
350367
/**
351368
* An error generated when a ChangeStream operation fails to execute.
352369
*

src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const ObjectID = ObjectId;
3838
export { AnyBulkWriteOperation, BulkWriteOptions, MongoBulkWriteError } from './bulk/common';
3939
export {
4040
MongoAPIError,
41+
MongoAWSError,
4142
MongoBatchReExecutionError,
4243
MongoChangeStreamError,
4344
MongoCompatibilityError,

test/integration/auth/mongodb_aws.test.js

+46
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
'use strict';
22
const { expect } = require('chai');
33
const { removeAuthFromConnectionString } = require('../../tools/utils');
4+
const sinon = require('sinon');
5+
const http = require('http');
6+
const { performance } = require('perf_hooks');
7+
const { MongoAWSError } = require('../../../src');
48

59
describe('MONGODB-AWS', function () {
610
beforeEach(function () {
@@ -52,4 +56,46 @@ describe('MONGODB-AWS', function () {
5256
.to.have.nested.property('options.credentials.mechanismProperties.AWS_SESSION_TOKEN')
5357
.that.equals('');
5458
});
59+
60+
describe('EC2 with missing credentials', () => {
61+
let client;
62+
63+
beforeEach(function () {
64+
if (!process.env.IS_EC2) {
65+
this.currentTest.skipReason = 'requires an AWS EC2 environment';
66+
this.skip();
67+
}
68+
sinon.stub(http, 'request').callsFake(function () {
69+
arguments[0].hostname = 'www.example.com';
70+
arguments[0].port = 81;
71+
return http.request.wrappedMethod.apply(this, arguments);
72+
});
73+
});
74+
75+
afterEach(async () => {
76+
sinon.restore();
77+
if (client) {
78+
await client.close();
79+
}
80+
});
81+
82+
it('should respect the default timeout of 10000ms', async function () {
83+
const config = this.configuration;
84+
client = config.newClient(process.env.MONGODB_URI, { authMechanism: 'MONGODB-AWS' }); // use the URI built by the test environment
85+
const startTime = performance.now();
86+
87+
let caughtError = null;
88+
await client.connect().catch(err => {
89+
caughtError = err;
90+
});
91+
92+
const endTime = performance.now();
93+
const timeTaken = endTime - startTime;
94+
expect(caughtError).to.be.instanceOf(MongoAWSError);
95+
expect(caughtError)
96+
.property('message')
97+
.match(/timed out after/);
98+
expect(timeTaken).to.be.within(10000, 12000);
99+
});
100+
});
55101
});

0 commit comments

Comments
 (0)