Drop RFC 2696 paging now that the response is attribute-limited

Paging was introduced to work around what looked like a response-size
problem, but the actual cause (previous commit) was @ldapjs/asn1's BER
decoder choking on a specific oversized attribute value, not overall
response size. With attributes now limited to mail/cn/displayName, the
whole response is tiny, and paging's extra sequential round-trips on the
same connection were themselves causing an ECONNRESET partway through.
An unpaged single request+response now matches what a plain ldapsearch
against this same AD does successfully.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012o9j9RezxbZVKQMrB7oRLY
This commit is contained in:
ogrechkoandClaude Sonnet 5 committed 2026-08-05 11:32:21 +00:00
1 parent 1e8133ee39
commit cb20d9eea5
1 file changed
+13 -16
+13 -16
View File
@@ -61,25 +61,22 @@ function search(
): Promise<{ dn: string; attributes: Record<string, string> }[]> { ): Promise<{ dn: string; attributes: Record<string, string> }[]> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const results: { dn: string; attributes: Record<string, string> }[] = []; const results: { dn: string; attributes: Record<string, string> }[] = [];
// Paged (RFC 2696) rather than one unbounded response: a directory-wide // `attributes` is restricted to just what callers actually read
// browse on a real AD domain can return ~1000 entries, and ldapjs's
// single-response handling for a batch that size was observed to drop
// the connection ("<id> closed") even though a plain `ldapsearch` with
// the identical filter completes cleanly — so the fix is on our client's
// response handling, not the query itself. ldapjs runs the multi-page
// RFC 2696 round-trips internally; callers still just see one continuous
// stream of `searchEntry` events followed by a single `end`.
//
// `attributes` is also restricted to just what callers actually read
// (mail/cn/displayName) instead of requesting every attribute AD has on // (mail/cn/displayName) instead of requesting every attribute AD has on
// an object. The real failure turned out to be @ldapjs/asn1's BER // an object. The original failure was @ldapjs/asn1's BER decoder
// decoder throwing "Encoding too long" — a parser desync, most likely // throwing "Encoding too long" — a parser desync, most likely triggered
// triggered while decoding some oversized/exotic AD attribute we never // while decoding some oversized/exotic AD attribute we never use anyway
// use anyway (e.g. nTSecurityDescriptor, msDS-ReplAttributeMetaData). // (e.g. nTSecurityDescriptor, msDS-ReplAttributeMetaData). Not requesting
// Not requesting them sidesteps the bug entirely. // them sidesteps that bug entirely.
//
// Deliberately NOT using RFC 2696 paging here: with the response now
// this much smaller, an unpaged single request+response is simpler and
// matches what a plain `ldapsearch` against this same AD does — paging
// instead caused ldapjs's multiple sequential requests on one connection
// to get an ECONNRESET partway through.
client.search( client.search(
baseDn, baseDn,
{ filter, scope: "sub", paged: { pageSize: 200 }, attributes: ["mail", "cn", "displayName"] }, { filter, scope: "sub", attributes: ["mail", "cn", "displayName"] },
(err, res) => { (err, res) => {
if (err) { if (err) {
reject(describeError(client, err)); reject(describeError(client, err));