Fix client memory leaks
This commit is contained in:
parent
3ce399a710
commit
fd9d713cdc
|
@ -1,11 +1,12 @@
|
||||||
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
|
||||||
|
|
||||||
var assert = require('assert');
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
var tls = require('tls');
|
var tls = require('tls');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
|
|
||||||
|
var assert = require('assert-plus');
|
||||||
|
|
||||||
var Attribute = require('../attribute');
|
var Attribute = require('../attribute');
|
||||||
var Change = require('../change');
|
var Change = require('../change');
|
||||||
var Control = require('../controls/index').Control;
|
var Control = require('../controls/index').Control;
|
||||||
|
@ -104,6 +105,11 @@ function setupSocket(socket, opts) {
|
||||||
// On close we have to walk the outstanding messages and go invoke their
|
// On close we have to walk the outstanding messages and go invoke their
|
||||||
// callback with an error
|
// callback with an error
|
||||||
socket.on('close', function onClose(had_err) {
|
socket.on('close', function onClose(had_err) {
|
||||||
|
socket.removeAllListeners('data');
|
||||||
|
socket.removeAllListeners('end');
|
||||||
|
socket.removeAllListeners('error');
|
||||||
|
socket.removeAllListeners('timeout');
|
||||||
|
|
||||||
if (log.trace())
|
if (log.trace())
|
||||||
log.trace('close event had_err=%s', had_err ? 'yes' : 'no');
|
log.trace('close event had_err=%s', had_err ? 'yes' : 'no');
|
||||||
|
|
||||||
|
@ -243,16 +249,14 @@ module.exports = Client;
|
||||||
* @throws {TypeError} on invalid input.
|
* @throws {TypeError} on invalid input.
|
||||||
*/
|
*/
|
||||||
Client.prototype.abandon = function abandon(messageID, controls, callback) {
|
Client.prototype.abandon = function abandon(messageID, controls, callback) {
|
||||||
if (typeof (messageID) !== 'number')
|
assert.number(messageID, 'messageID');
|
||||||
throw new TypeError('messageID (number) required');
|
|
||||||
if (typeof (controls) === 'function') {
|
if (typeof (controls) === 'function') {
|
||||||
callback = controls;
|
callback = controls;
|
||||||
controls = [];
|
controls = [];
|
||||||
} else {
|
} else {
|
||||||
controls = validateControls(controls);
|
controls = validateControls(controls);
|
||||||
}
|
}
|
||||||
if (typeof (callback) !== 'function')
|
assert.func(callback, 'callback');
|
||||||
throw new TypeError('callback (function) required');
|
|
||||||
|
|
||||||
var req = new AbandonRequest({
|
var req = new AbandonRequest({
|
||||||
abandonID: messageID,
|
abandonID: messageID,
|
||||||
|
@ -277,18 +281,15 @@ Client.prototype.abandon = function abandon(messageID, controls, callback) {
|
||||||
* @throws {TypeError} on invalid input.
|
* @throws {TypeError} on invalid input.
|
||||||
*/
|
*/
|
||||||
Client.prototype.add = function add(name, entry, controls, callback) {
|
Client.prototype.add = function add(name, entry, controls, callback) {
|
||||||
if (typeof (name) !== 'string')
|
assert.string(name, 'name');
|
||||||
throw new TypeError('name (string) required');
|
assert.object(entry, 'entry');
|
||||||
if (typeof (entry) !== 'object')
|
|
||||||
throw new TypeError('entry (object) required');
|
|
||||||
if (typeof (controls) === 'function') {
|
if (typeof (controls) === 'function') {
|
||||||
callback = controls;
|
callback = controls;
|
||||||
controls = [];
|
controls = [];
|
||||||
} else {
|
} else {
|
||||||
controls = validateControls(controls);
|
controls = validateControls(controls);
|
||||||
}
|
}
|
||||||
if (typeof (callback) !== 'function')
|
assert.func(callback, 'callback');
|
||||||
throw new TypeError('callback (function) required');
|
|
||||||
|
|
||||||
if (Array.isArray(entry)) {
|
if (Array.isArray(entry)) {
|
||||||
entry.forEach(function (a) {
|
entry.forEach(function (a) {
|
||||||
|
@ -334,16 +335,14 @@ Client.prototype.add = function add(name, entry, controls, callback) {
|
||||||
Client.prototype.bind = function bind(name, credentials, controls, callback) {
|
Client.prototype.bind = function bind(name, credentials, controls, callback) {
|
||||||
if (typeof (name) !== 'string' && !(name instanceof dn.DN))
|
if (typeof (name) !== 'string' && !(name instanceof dn.DN))
|
||||||
throw new TypeError('name (string) required');
|
throw new TypeError('name (string) required');
|
||||||
if (typeof (credentials) !== 'string')
|
assert.string(credentials, 'credentials');
|
||||||
throw new TypeError('credentials (string) required');
|
|
||||||
if (typeof (controls) === 'function') {
|
if (typeof (controls) === 'function') {
|
||||||
callback = controls;
|
callback = controls;
|
||||||
controls = [];
|
controls = [];
|
||||||
} else {
|
} else {
|
||||||
controls = validateControls(controls);
|
controls = validateControls(controls);
|
||||||
}
|
}
|
||||||
if (typeof (callback) !== 'function')
|
assert.func(callback, 'callback');
|
||||||
throw new TypeError('callback (function) required');
|
|
||||||
|
|
||||||
var req = new BindRequest({
|
var req = new BindRequest({
|
||||||
name: name || '',
|
name: name || '',
|
||||||
|
@ -371,20 +370,16 @@ Client.prototype.compare = function compare(name,
|
||||||
value,
|
value,
|
||||||
controls,
|
controls,
|
||||||
callback) {
|
callback) {
|
||||||
if (typeof (name) !== 'string')
|
assert.string(name, 'name');
|
||||||
throw new TypeError('name (string) required');
|
assert.string(attr, 'attr');
|
||||||
if (typeof (attr) !== 'string')
|
assert.string(value, 'value');
|
||||||
throw new TypeError('attribute (string) required');
|
|
||||||
if (typeof (value) !== 'string')
|
|
||||||
throw new TypeError('value (string) required');
|
|
||||||
if (typeof (controls) === 'function') {
|
if (typeof (controls) === 'function') {
|
||||||
callback = controls;
|
callback = controls;
|
||||||
controls = [];
|
controls = [];
|
||||||
} else {
|
} else {
|
||||||
controls = validateControls(controls);
|
controls = validateControls(controls);
|
||||||
}
|
}
|
||||||
if (typeof (callback) !== 'function')
|
assert.func(callback, 'callback');
|
||||||
throw new TypeError('callback (function) required');
|
|
||||||
|
|
||||||
var req = new CompareRequest({
|
var req = new CompareRequest({
|
||||||
entry: dn.parse(name),
|
entry: dn.parse(name),
|
||||||
|
@ -411,16 +406,14 @@ Client.prototype.compare = function compare(name,
|
||||||
* @throws {TypeError} on invalid input.
|
* @throws {TypeError} on invalid input.
|
||||||
*/
|
*/
|
||||||
Client.prototype.del = function del(name, controls, callback) {
|
Client.prototype.del = function del(name, controls, callback) {
|
||||||
if (typeof (name) !== 'string')
|
assert.string(name, 'name');
|
||||||
throw new TypeError('name (string) required');
|
|
||||||
if (typeof (controls) === 'function') {
|
if (typeof (controls) === 'function') {
|
||||||
callback = controls;
|
callback = controls;
|
||||||
controls = [];
|
controls = [];
|
||||||
} else {
|
} else {
|
||||||
controls = validateControls(controls);
|
controls = validateControls(controls);
|
||||||
}
|
}
|
||||||
if (typeof (callback) !== 'function')
|
assert.func(callback, 'callback');
|
||||||
throw new TypeError('callback (function) required');
|
|
||||||
|
|
||||||
var req = new DeleteRequest({
|
var req = new DeleteRequest({
|
||||||
entry: dn.parse(name),
|
entry: dn.parse(name),
|
||||||
|
@ -445,8 +438,7 @@ Client.prototype.del = function del(name, controls, callback) {
|
||||||
* @throws {TypeError} on invalid input.
|
* @throws {TypeError} on invalid input.
|
||||||
*/
|
*/
|
||||||
Client.prototype.exop = function exop(name, value, controls, callback) {
|
Client.prototype.exop = function exop(name, value, controls, callback) {
|
||||||
if (typeof (name) !== 'string')
|
assert.string(name, 'name');
|
||||||
throw new TypeError('name (string) required');
|
|
||||||
if (typeof (value) === 'function') {
|
if (typeof (value) === 'function') {
|
||||||
callback = value;
|
callback = value;
|
||||||
controls = [];
|
controls = [];
|
||||||
|
@ -460,8 +452,7 @@ Client.prototype.exop = function exop(name, value, controls, callback) {
|
||||||
} else {
|
} else {
|
||||||
controls = validateControls(controls);
|
controls = validateControls(controls);
|
||||||
}
|
}
|
||||||
if (typeof (callback) !== 'function')
|
assert.func(callback, 'callback');
|
||||||
throw new TypeError('callback (function) required');
|
|
||||||
|
|
||||||
var req = new ExtendedRequest({
|
var req = new ExtendedRequest({
|
||||||
requestName: name,
|
requestName: name,
|
||||||
|
@ -488,10 +479,8 @@ Client.prototype.exop = function exop(name, value, controls, callback) {
|
||||||
* @throws {TypeError} on invalid input.
|
* @throws {TypeError} on invalid input.
|
||||||
*/
|
*/
|
||||||
Client.prototype.modify = function modify(name, change, controls, callback) {
|
Client.prototype.modify = function modify(name, change, controls, callback) {
|
||||||
if (typeof (name) !== 'string')
|
assert.string(name, 'name');
|
||||||
throw new TypeError('name (string) required');
|
assert.object(change, 'change');
|
||||||
if (typeof (change) !== 'object')
|
|
||||||
throw new TypeError('change (Change) required');
|
|
||||||
|
|
||||||
var changes = [];
|
var changes = [];
|
||||||
|
|
||||||
|
@ -531,8 +520,7 @@ Client.prototype.modify = function modify(name, change, controls, callback) {
|
||||||
} else {
|
} else {
|
||||||
controls = validateControls(controls);
|
controls = validateControls(controls);
|
||||||
}
|
}
|
||||||
if (typeof (callback) !== 'function')
|
assert.func(callback, 'callback');
|
||||||
throw new TypeError('callback (function) required');
|
|
||||||
|
|
||||||
var req = new ModifyRequest({
|
var req = new ModifyRequest({
|
||||||
object: dn.parse(name),
|
object: dn.parse(name),
|
||||||
|
@ -761,8 +749,14 @@ Client.prototype._send = function _send(message, expect, emitter, callback) {
|
||||||
return callback(new ConnectionError('no socket'));
|
return callback(new ConnectionError('no socket'));
|
||||||
|
|
||||||
function _done(event, obj) {
|
function _done(event, obj) {
|
||||||
if (emitter)
|
if (emitter) {
|
||||||
|
if (event === 'error')
|
||||||
|
emitter.removeAllListeners('end');
|
||||||
|
if (event === 'end')
|
||||||
|
emitter.removeAllListeners('error');
|
||||||
|
|
||||||
return emitter.emit(event, obj);
|
return emitter.emit(event, obj);
|
||||||
|
}
|
||||||
|
|
||||||
if (event === 'error')
|
if (event === 'error')
|
||||||
return callback(obj);
|
return callback(obj);
|
||||||
|
|
|
@ -54,7 +54,7 @@ module.exports = {
|
||||||
if (typeof (options.log) !== 'object')
|
if (typeof (options.log) !== 'object')
|
||||||
throw new TypeError('options.log must be an object');
|
throw new TypeError('options.log must be an object');
|
||||||
|
|
||||||
if (options.maxConnections > 1)
|
if (options.maxConnections >= 1)
|
||||||
return new ClientPool(options);
|
return new ClientPool(options);
|
||||||
|
|
||||||
return new Client(options);
|
return new Client(options);
|
||||||
|
|
|
@ -44,7 +44,8 @@ function createPool(options) {
|
||||||
create: function createClient(callback) {
|
create: function createClient(callback) {
|
||||||
var client = new Client(options);
|
var client = new Client(options);
|
||||||
|
|
||||||
client.once('error', function (err) {
|
client.on('error', function (err) {
|
||||||
|
client.removeAllListeners('connect');
|
||||||
return callback(err);
|
return callback(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -101,11 +101,11 @@ Parser.prototype.write = function (data) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
message.parse(ber);
|
message.parse(ber);
|
||||||
this.emit('message', message);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.emit('error', e, message);
|
this.emit('error', e, message);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
this.emit('message', message);
|
||||||
|
|
||||||
return end();
|
return end();
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
"name": "ldapjs",
|
"name": "ldapjs",
|
||||||
"homepage": "http://ldapjs.org",
|
"homepage": "http://ldapjs.org",
|
||||||
"description": "LDAP client and server APIs",
|
"description": "LDAP client and server APIs",
|
||||||
"version": "0.5.0",
|
"version": "0.5.1",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git://github.com/mcavage/node-ldapjs.git"
|
"url": "git://github.com/mcavage/node-ldapjs.git"
|
||||||
|
@ -21,10 +21,11 @@
|
||||||
"lib": "./lib"
|
"lib": "./lib"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.6"
|
"node": "~0.6"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asn1": "0.1.11",
|
"asn1": "0.1.11",
|
||||||
|
"assert-plus": "0.1.0",
|
||||||
"buffertools": "1.1.0",
|
"buffertools": "1.1.0",
|
||||||
"bunyan": "0.10.0",
|
"bunyan": "0.10.0",
|
||||||
"dtrace-provider": "0.0.9",
|
"dtrace-provider": "0.0.9",
|
||||||
|
|
|
@ -130,6 +130,7 @@ test('setup', function (t) {
|
||||||
|
|
||||||
server.listen(SOCKET, function () {
|
server.listen(SOCKET, function () {
|
||||||
client = ldap.createClient({
|
client = ldap.createClient({
|
||||||
|
connectTimeout: 100,
|
||||||
socketPath: SOCKET,
|
socketPath: SOCKET,
|
||||||
maxConnections: process.env.LDAP_MAX_CONNS || 5,
|
maxConnections: process.env.LDAP_MAX_CONNS || 5,
|
||||||
idleTimeoutMillis: 10,
|
idleTimeoutMillis: 10,
|
||||||
|
@ -148,6 +149,7 @@ test('setup', function (t) {
|
||||||
|
|
||||||
|
|
||||||
test('simple bind failure', function (t) {
|
test('simple bind failure', function (t) {
|
||||||
|
try {
|
||||||
client.bind(BIND_DN, uuid(), function (err, res) {
|
client.bind(BIND_DN, uuid(), function (err, res) {
|
||||||
t.ok(err);
|
t.ok(err);
|
||||||
t.notOk(res);
|
t.notOk(res);
|
||||||
|
@ -160,6 +162,10 @@ test('simple bind failure', function (t) {
|
||||||
|
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e.stack);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue