Merge pull request #42 from yunong/master

add feature to deserialize persistent search control requests.
This commit is contained in:
Mark Cavage 2011-12-08 13:59:21 -08:00
commit ee89eff6b4
8 changed files with 287 additions and 45 deletions

View File

@ -8,7 +8,7 @@ var util = require('util');
var Attribute = require('./attribute');
var Change = require('./change');
var Control = require('./control');
var Control = require('./controls/index').Control;
var Protocol = require('./protocol');
var dn = require('./dn');
var errors = require('./errors');

View File

@ -5,16 +5,11 @@ var util = require('util');
var asn1 = require('asn1');
var Protocol = require('./protocol');
var Protocol = require('../protocol');
///--- Globals
var Ber = asn1.Ber;
///--- API
function Control(options) {
@ -47,35 +42,10 @@ function Control(options) {
}
module.exports = Control;
Control.prototype.toString = function() {
return this.json;
};
Control.prototype.parse = function(ber) {
assert.ok(ber);
if (ber.readSequence() === null)
return false;
var end = ber.offset + ber.length;
if (ber.length) {
this.type = ber.readString();
if (ber.offset < end) {
if (ber.peek() === 0x01) // Boolean, optional
this.criticality = ber.readBoolean();
}
if (ber.offset < end)
this.value = ber.readString();
}
return true;
};
Control.prototype.toBer = function(ber) {
assert.ok(ber);

40
lib/controls/index.js Normal file
View File

@ -0,0 +1,40 @@
var assert = require('assert');
var Control = require('./control');
var PersistentSearchControl = require('./persistent_search_control');
var OID_PERSISTENT_SEARCH_CONTROL = '2.16.840.1.113730.3.4.3';
///--- API
module.exports = {
getControl: function(ber) {
assert.ok(ber);
if (ber.readSequence() === null)
return;
var end = ber.offset + ber.length;
var options = {};
if (ber.length) {
options.type = ber.readString();
if (ber.offset < end) {
if (ber.peek() === 0x01) // Boolean, optional
options.criticality = ber.readBoolean();
}
if (ber.offset < end) {
if (options.type == OID_PERSISTENT_SEARCH_CONTROL) {
// send the buffer directly to the PSC
options.value = ber.readString(0x04, true);
return new PersistentSearchControl(options);
} else {
options.value = ber.readString();
return new Control(options);
}
}
}
},
Control: Control,
PersistentSearchControl: PersistentSearchControl
};

View File

@ -0,0 +1,109 @@
var assert = require('assert');
var asn1 = require('asn1');
var buffer = require('buffer');
var Control = require('./control');
var util = require('util');
function PersistentSearchControl(options) {
if (options) {
if (typeof(options) !== 'object')
throw new TypeError('options must be an object');
if (options.type && typeof(options.type) !== 'string')
throw new TypeError('options.type must be a string');
if (options.criticality !== undefined &&
typeof(options.criticality) !== 'boolean')
throw new TypeError('options.criticality must be a boolean');
if (options.value && !Buffer.isBuffer(options.value))
throw new TypeError('options.value must be a buffer');
} else {
options = {};
}
this.type = options.type || '2.16.840.1.113730.3.4.3';
this.criticality = options.criticality || false;
if (options.value) {
// parse out this.value into the PSC object
var ber = new asn1.BerReader(options.value);
if (ber.readSequence()) {
this.value = {
changeTypes: ber.readInt(),
changesOnly: ber.readBoolean(),
returnECs: ber.readBoolean()
};
}
}
var self = this;
this.__defineGetter__('json', function() {
return {
controlType: self.type,
criticality: self.criticality,
controlValue: self.value
};
});
}
module.exports = PersistentSearchControl;
// returns a psc given a fully populated psc object
PersistentSearchControl.prototype.get = function(options) {
if (options) {
if (typeof(options) !== 'object')
throw new TypeError('options must be an object');
if (options.type && typeof(options.type) !== 'string')
throw new TypeError('options.type must be a string');
if (options.criticality !== undefined &&
typeof(options.criticality) !== 'boolean')
throw new TypeError('options.criticality must be a boolean');
if (options.value && typeof(options.value) !== 'object') {
throw new TypeError('options.value must be an object');
} else {
if (options.value.changeTypes &&
typeof(options.value.changeTypes) !== 'number')
throw new TypeError('options.value.changeTypes must be a number');
if (options.value.changesOnly !== undefined &&
typeof(options.value.changesOnly) !== 'boolean')
throw new TypeError('options.value.changesOnly must be a boolean');
if (options.value.returnECs !== undefined &&
typeof(options.value.returnECs) !== 'boolean')
throw new TypeError('options.value.returnECs must be a boolean');
}
} else {
options = {};
}
this.type = options.type || '';
this.criticality = options.criticality || false;
this.value = options.value || undefined;
var self = this;
this.__defineGetter__('json', function() {
return {
controlType: self.type,
criticality: self.criticality,
controlValue: self.value
};
});
};
PersistentSearchControl.prototype.toBer = function(ber) {
assert.ok(ber);
ber.startSequence();
ber.writeString(this.type);
ber.writeBoolean(this.criticality);
var pscWriter = new asn1.BerWriter();
// write the value subsequence
pscWriter.startSequence();
pscWriter.writeInt(this.value.changeTypes);
pscWriter.writeBoolean(this.value.changesOnly);
pscWriter.writeBoolean(this.value.returnECs);
pscWriter.endSequence();
// write the pscValue as a octetstring to the ber
ber.writeBuffer(pscWriter.buffer, 0x04);
ber.endSequence();
};

View File

@ -3,10 +3,10 @@
var Client = require('./client');
var Attribute = require('./attribute');
var Change = require('./change');
var Control = require('./control');
var Protocol = require('./protocol');
var Server = require('./server');
var assert = require('assert');
var dn = require('./dn');
var errors = require('./errors');
var filters = require('./filters');
@ -15,8 +15,6 @@ var messages = require('./messages');
var schema = require('./schema');
var url = require('./url');
/// Hack a few things we need (i.e., "monkey patch" the prototype)
if (!String.prototype.startsWith) {
@ -55,7 +53,6 @@ module.exports = {
Attribute: Attribute,
Change: Change,
Control: Control,
DN: dn.DN,
RDN: dn.RDN,

View File

@ -5,7 +5,7 @@ var util = require('util');
var asn1 = require('asn1');
var Control = require('../control');
var Control = require('../controls/index').Control;
var Protocol = require('../protocol');
var logStub = require('../log_stub');
@ -15,11 +15,11 @@ var logStub = require('../log_stub');
var Ber = asn1.Ber;
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
var getControl = require('../controls/index').getControl;
///--- API
/**
* LDAPMessage structure.
*
@ -76,8 +76,9 @@ LDAPMessage.prototype.parse = function(ber) {
ber.readSequence();
var end = ber.offset + ber.length;
while (ber.offset < end) {
var c = new Control();
if (c.parse(ber))
var c = getControl(ber);
if (c)
this.controls.push(c);
}
}

View File

@ -10,13 +10,16 @@ var asn1 = require('asn1');
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
var Control;
var getControl;
///--- Tests
test('load library', function(t) {
Control = require('../lib/index').Control;
Control = require('../../lib/controls/index').Control;
t.ok(Control);
getControl = require('../../lib/controls/index').getControl;
t.ok(getControl);
t.end();
});
@ -47,9 +50,7 @@ test('parse', function(t) {
ber.writeString('foo');
ber.endSequence();
var c = new Control();
t.ok(c);
t.ok(c.parse(new BerReader(ber.buffer)));
var c = getControl(new BerReader(ber.buffer));
t.ok(c);
t.equal(c.type, '2.16.840.1.113730.3.4.2');

View File

@ -0,0 +1,124 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
var test = require('tap').test;
var asn1 = require('asn1');
var log4js = require('log4js');
var sys = require('sys');
var BerReader = asn1.BerReader;
var BerWriter = asn1.BerWriter;
var getControl;
var PersistentSearchControl;
///--- Globals
var LOG = log4js.getLogger('persistent_search_control.test');
///--- Tests
test('load library', function(t) {
PersistentSearchControl =
require('../../lib/controls/index').PersistentSearchControl;
t.ok(PersistentSearchControl);
getControl = require('../../lib/controls/index').getControl;
t.ok(getControl);
t.end();
});
test('new no args', function(t) {
t.ok(new PersistentSearchControl());
t.end();
});
test('new with args', function(t) {
var options = {
type: '2.16.840.1.113730.3.4.3',
criticality: true,
value: {
changeTypes: 15,
changesOnly: false,
returnECs: false
}
};
var c = new PersistentSearchControl();
c.get(options);
t.ok(c);
t.equal(c.type, '2.16.840.1.113730.3.4.3');
t.ok(c.criticality);
t.equal(c.value.changeTypes, 15);
t.equal(c.value.changesOnly, false);
t.equal(c.value.returnECs, false);
var writer = new BerWriter();
c.toBer(writer);
var reader = new BerReader(writer.buffer);
var psc = getControl(reader);
t.ok(psc);
t.equal(psc.type, '2.16.840.1.113730.3.4.3');
t.ok(psc.criticality);
t.equal(psc.value.changeTypes, 15);
t.equal(psc.value.changesOnly, false);
t.equal(psc.value.returnECs, false);
t.end();
});
test('getControl with args', function(t) {
var buf = new Buffer([
0x30, 0x26, 0x04, 0x17, 0x32, 0x2e, 0x31, 0x36, 0x2e, 0x38, 0x34, 0x30,
0x2e, 0x31, 0x2e, 0x31, 0x31, 0x33, 0x37, 0x33, 0x30, 0x2e, 0x33, 0x2e,
0x34, 0x2e, 0x33, 0x04, 0x0b, 0x30, 0x09, 0x02, 0x01, 0x0f, 0x01, 0x01,
0xff, 0x01, 0x01, 0xff]);
var options = {
type: '2.16.840.1.113730.3.4.3',
criticality: false,
value: {
changeTypes: 15,
changesOnly: true,
returnECs: true
}
};
var ber = new BerReader(buf);
var psc = getControl(ber);
LOG.info(psc.value);
t.ok(psc);
t.equal(psc.type, '2.16.840.1.113730.3.4.3');
t.equal(psc.criticality, false);
t.equal(psc.value.changeTypes, 15);
t.equal(psc.value.changesOnly, true);
t.equal(psc.value.returnECs, true);
t.end();
});
test('tober', function(t) {
var ber = new BerWriter();
var options = {
type: '2.16.840.1.113730.3.4.3',
criticality: true,
value: {
changeTypes: 15,
changesOnly: false,
returnECs: false
}
};
var psc = new PersistentSearchControl();
psc.get(options);
psc.toBer(ber);
var c = getControl(new BerReader(ber.buffer));
t.ok(c);
t.equal(c.type, '2.16.840.1.113730.3.4.3');
t.ok(c.criticality);
t.equal(c.value.changeTypes, 15);
t.equal(c.value.changesOnly, false);
t.equal(c.value.returnECs, false);
t.end();
});