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'] 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 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 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 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`). `failAfter` (default: `Infinity`).
After the reconnect you maybe need to [bind](#bind) again. 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 ## Common patterns

View File

@ -1029,9 +1029,9 @@ Client.prototype.connect = function connect () {
self.log.debug('failed to connect after %d attempts', failAfter) self.log.debug('failed to connect after %d attempts', failAfter)
// Communicate the last-encountered error // Communicate the last-encountered error
if (err instanceof ConnectionError) { if (err instanceof ConnectionError) {
self.emit('connectTimeout', err) self.emitError('connectTimeout', err)
} else if (err.code === 'ECONNREFUSED') { } else if (err.code === 'ECONNREFUSED') {
self.emit('connectRefused', err) self.emitError('connectRefused', err)
} else { } else {
self.emit('error', err) self.emit('error', err)
} }
@ -1277,3 +1277,15 @@ Client.prototype._sendSocket = function _sendSocket (message,
return callback(e) 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 () { get: function getMessage () {
return this.lde_message || this.name return this.lde_message || this.name
}, },
set: function setMessage (message) {
this.lde_message = message
},
configurable: false configurable: false
}, },
dn: { 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 { try {
// This port number is totally invalid. It will cause the URL parser // This port number is totally invalid. It will cause the URL parser
// to throw an exception that should be caught. // to throw an exception that should be caught.
@ -387,6 +387,9 @@ tap.test('createClient', t => {
], ],
connectTimeout: 1 connectTimeout: 1
}) })
client.on('connectTimeout', () => {})
client.on('connectError', () => {})
client.on('connectRefused', () => {})
t.equal(client.urls.length, 2) t.equal(client.urls.length, 2)
}) })
@ -1513,6 +1516,8 @@ tap.test('connection refused', function (t) {
url: `ldap://0.0.0.0:${unusedPortNumber}` url: `ldap://0.0.0.0:${unusedPortNumber}`
}) })
client.on('connectRefused', () => {})
client.bind('cn=root', 'secret', function (err, res) { client.bind('cn=root', 'secret', function (err, res) {
t.true(err) t.true(err)
t.type(err, Error) t.type(err, Error)
@ -1531,6 +1536,8 @@ tap.test('connection timeout', function (t) {
timeout: 1 timeout: 1
}) })
client.on('connectTimeout', () => {})
let done = false let done = false
setTimeout(function () { 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()
})