Compare commits

...

3 Commits

Author SHA1 Message Date
Dora Korpar 5d7fe79115 bf: S3C-3581 add bucket notif apis for policy eval 2020-11-24 18:06:34 -08:00
Jonathan Gramain 633b9c377e bugfix: S3C-3388 constants for HTTP connection timeouts
Add constants related to HTTP client/server connection timeouts with
values avoiding ECONNRESET errors due to the server closing
connections that clients are attempting to reuse at the same moment.

(cherry picked from commit 918a1d7c89)
2020-11-09 17:48:31 -08:00
Jonathan Gramain 2d9e91b855 bugfix: S3C-3388 network.http.Server.setKeepAliveTimeout()
Add a helper function to set the keep-alive timeout of the node.js
HTTP server managed by the Server class.

(cherry picked from commit 15140cd6bb)
2020-11-09 17:46:47 -08:00
4 changed files with 66 additions and 0 deletions

View File

@ -88,4 +88,16 @@ module.exports = {
's3:ObjectRemoved:DeleteMarkerCreated', 's3:ObjectRemoved:DeleteMarkerCreated',
]), ]),
notificationArnPrefix: 'arn:scality:bucketnotif', notificationArnPrefix: 'arn:scality:bucketnotif',
// HTTP server keep-alive timeout is set to a higher value than
// client's free sockets timeout to avoid the risk of triggering
// ECONNRESET errors if the server closes the connection at the
// exact moment clients attempt to reuse an established connection
// for a new request.
//
// Note: the ability to close inactive connections on the client
// after httpClientFreeSocketsTimeout milliseconds requires the
// use of "agentkeepalive" module instead of the regular node.js
// http.Agent.
httpServerKeepAliveTimeout: 60000,
httpClientFreeSocketTimeout: 55000,
}; };

View File

@ -43,6 +43,7 @@ class Server {
this._address = checkSupportIPv6() ? '::' : '0.0.0.0'; this._address = checkSupportIPv6() ? '::' : '0.0.0.0';
this._server = null; this._server = null;
this._logger = logger; this._logger = logger;
this._keepAliveTimeout = null; // null: use default node.js value
} }
/** /**
@ -57,6 +58,19 @@ class Server {
return this; return this;
} }
/**
* Set the keep-alive timeout after which inactive client
* connections are automatically closed (default should be
* 5 seconds in node.js)
*
* @param {number} keepAliveTimeout - keep-alive timeout in milliseconds
* @return {Server} - returns this
*/
setKeepAliveTimeout(keepAliveTimeout) {
this._keepAliveTimeout = keepAliveTimeout;
return this;
}
/** /**
* Getter to access to the http/https server * Getter to access to the http/https server
* *
@ -401,6 +415,9 @@ class Server {
this._server = http.createServer( this._server = http.createServer(
(req, res) => this._onRequest(req, res)); (req, res) => this._onRequest(req, res));
} }
if (this._keepAliveTimeout) {
this._server.keepAliveTimeout = this._keepAliveTimeout;
}
this._server.on('error', err => this._onError(err)); this._server.on('error', err => this._onError(err));
this._server.on('secureConnection', this._server.on('secureConnection',

View File

@ -13,6 +13,7 @@ const _actionMap = {
bucketGet: 's3:ListBucket', bucketGet: 's3:ListBucket',
bucketGetACL: 's3:GetBucketAcl', bucketGetACL: 's3:GetBucketAcl',
bucketGetCors: 's3:GetBucketCORS', bucketGetCors: 's3:GetBucketCORS',
bucketGetNotificationConfiguration: 's3:GetBucketNotificationConfiguration',
bucketGetObjectLock: 's3:GetBucketObjectLockConfiguration', bucketGetObjectLock: 's3:GetBucketObjectLockConfiguration',
bucketGetVersioning: 's3:GetBucketVersioning', bucketGetVersioning: 's3:GetBucketVersioning',
bucketGetWebsite: 's3:GetBucketWebsite', bucketGetWebsite: 's3:GetBucketWebsite',
@ -21,6 +22,7 @@ const _actionMap = {
bucketPut: 's3:CreateBucket', bucketPut: 's3:CreateBucket',
bucketPutACL: 's3:PutBucketAcl', bucketPutACL: 's3:PutBucketAcl',
bucketPutCors: 's3:PutBucketCORS', bucketPutCors: 's3:PutBucketCORS',
bucketPutNotificationConfiguration: 's3:PutBucketNotificationConfiguration',
bucketPutObjectLock: 's3:PutBucketObjectLockConfiguration', bucketPutObjectLock: 's3:PutBucketObjectLockConfiguration',
// for bucketDeleteCors need s3:PutBucketCORS permission // for bucketDeleteCors need s3:PutBucketCORS permission
// see http://docs.aws.amazon.com/AmazonS3/latest/API/ // see http://docs.aws.amazon.com/AmazonS3/latest/API/

View File

@ -180,4 +180,39 @@ describe('network.Server: ', () => {
res.end('done'); res.end('done');
}).start(); }).start();
}); });
it('should automatically close idle connections with setKeepAliveTimeout()', done => {
const ws = new Server(3000, log);
ws.setKeepAliveTimeout(1000);
ws.onError(done).onListening(() => {
const options = {
hostname: '127.0.0.1',
port: 3000,
path: '/',
agent: new http.Agent({ keepAlive: true }),
};
const req = http.request(options, res => {
res.on('data', () => {});
res.on('end', () => {});
});
req.on('error', err => {
assert.ifError(err);
});
req.end();
}).onRequest((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end();
assert.strictEqual(ws._server._connections, 1);
setTimeout(() => {
// client connection should remain open after less than 1000ms
assert.strictEqual(ws._server._connections, 1);
setTimeout(() => {
// client connection should have been closed after more than 1000ms
assert.strictEqual(ws._server.connections, 0);
ws.stop();
ws.onStop(done);
}, 200);
}, 900);
}).start();
});
}); });