Merge pull request #704 from UziTech/emitError

This commit is contained in:
Tony Brix 2021-02-24 08:46:29 -06:00 committed by GitHub
commit f247fba7d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 142 additions and 3 deletions

View File

@ -20,6 +20,10 @@ The code to create a new client looks like:
url: ['ldap://127.0.0.1:1389', 'ldap://127.0.0.2:1389']
});
client.on('error', (err) => {
// handle connection error
})
You can use `ldap://` or `ldaps://`; the latter would connect over SSL (note
that this will not use the LDAP TLS extended operation, but literally an SSL
connection to port 636, as in LDAP v2). The full set of options to create a
@ -70,6 +74,25 @@ more sophisticated control, you can provide an Object with the properties
`failAfter` (default: `Infinity`).
After the reconnect you maybe need to [bind](#bind) again.
## Client events
The client is an `EventEmitter` and can emit the following events:
|Event |Description |
|---------------|----------------------------------------------------------|
|error |General error |
|connectRefused |Server refused connection. Most likely bad authentication |
|connectTimeout |Server timeout |
|connectError |Socket connection error |
|setupError |Setup error after successful connection |
|socketTimeout |Socket timeout |
|resultError |Search result error |
|timeout |Search result timeout |
|destroy |After client is disconnected |
|end |Socket end event |
|close |Socket closed |
|connect |Client connected |
|idle |Idle timeout reached |
## Common patterns

View File

@ -1029,9 +1029,9 @@ Client.prototype.connect = function connect () {
self.log.debug('failed to connect after %d attempts', failAfter)
// Communicate the last-encountered error
if (err instanceof ConnectionError) {
self.emit('connectTimeout', err)
self.emitError('connectTimeout', err)
} else if (err.code === 'ECONNREFUSED') {
self.emit('connectRefused', err)
self.emitError('connectRefused', err)
} else {
self.emit('error', err)
}
@ -1277,3 +1277,15 @@ Client.prototype._sendSocket = function _sendSocket (message,
return callback(e)
}
}
Client.prototype.emitError = function emitError (event, err) {
if (event !== 'error' && err && this.listenerCount(event) === 0) {
if (typeof err === 'string') {
err = event + ': ' + err
} else if (err.message) {
err.message = event + ': ' + err.message
}
this.emit('error', err)
}
this.emit(event, err)
}

View File

@ -32,6 +32,9 @@ Object.defineProperties(LDAPError.prototype, {
get: function getMessage () {
return this.lde_message || this.name
},
set: function setMessage (message) {
this.lde_message = message
},
configurable: false
},
dn: {

View File

@ -367,7 +367,7 @@ tap.test('createClient', t => {
)
})
tap.test('exception from bad createClient parameter (issue #418)', t => {
t.test('exception from bad createClient parameter (issue #418)', t => {
try {
// This port number is totally invalid. It will cause the URL parser
// to throw an exception that should be caught.
@ -387,6 +387,9 @@ tap.test('createClient', t => {
],
connectTimeout: 1
})
client.on('connectTimeout', () => {})
client.on('connectError', () => {})
client.on('connectRefused', () => {})
t.equal(client.urls.length, 2)
})
@ -1513,6 +1516,8 @@ tap.test('connection refused', function (t) {
url: `ldap://0.0.0.0:${unusedPortNumber}`
})
client.on('connectRefused', () => {})
client.bind('cn=root', 'secret', function (err, res) {
t.true(err)
t.type(err, Error)
@ -1531,6 +1536,8 @@ tap.test('connection timeout', function (t) {
timeout: 1
})
client.on('connectTimeout', () => {})
let done = false
setTimeout(function () {
@ -1549,3 +1556,97 @@ tap.test('connection timeout', function (t) {
})
})
})
tap.only('emitError', function (t) {
t.test('connectTimeout', function (t) {
getPort().then(function (unusedPortNumber) {
const client = ldap.createClient({
url: `ldap://example.org:${unusedPortNumber}`,
connectTimeout: 1,
timeout: 1
})
const timeout = setTimeout(function () {
throw new Error('LDAPJS waited for the server for too long')
}, 2000)
client.on('error', (err) => {
t.fail(err)
})
client.on('connectTimeout', (err) => {
t.true(err)
t.type(err, Error)
t.equals(err.message, 'connection timeout')
clearTimeout(timeout)
t.end()
})
client.bind('cn=root', 'secret', () => {})
})
})
t.test('connectTimeout to error', function (t) {
getPort().then(function (unusedPortNumber) {
const client = ldap.createClient({
url: `ldap://example.org:${unusedPortNumber}`,
connectTimeout: 1,
timeout: 1
})
const timeout = setTimeout(function () {
throw new Error('LDAPJS waited for the server for too long')
}, 2000)
client.on('error', (err) => {
t.true(err)
t.type(err, Error)
t.equals(err.message, 'connectTimeout: connection timeout')
clearTimeout(timeout)
t.end()
})
client.bind('cn=root', 'secret', () => {})
})
})
t.test('connectRefused', function (t) {
getPort().then(function (unusedPortNumber) {
const client = ldap.createClient({
url: `ldap://0.0.0.0:${unusedPortNumber}`
})
client.on('error', (err) => {
t.fail(err)
})
client.on('connectRefused', (err) => {
t.true(err)
t.type(err, Error)
t.equals(err.message, `connect ECONNREFUSED 0.0.0.0:${unusedPortNumber}`)
t.equals(err.code, 'ECONNREFUSED')
t.end()
})
client.bind('cn=root', 'secret', () => {})
})
})
t.test('connectRefused to error', function (t) {
getPort().then(function (unusedPortNumber) {
const client = ldap.createClient({
url: `ldap://0.0.0.0:${unusedPortNumber}`
})
client.on('error', (err) => {
t.true(err)
t.type(err, Error)
t.equals(err.message, `connectRefused: connect ECONNREFUSED 0.0.0.0:${unusedPortNumber}`)
t.equals(err.code, 'ECONNREFUSED')
t.end()
})
client.bind('cn=root', 'secret', () => {})
})
})
t.end()
})