support extensible matching of caseIgnore and caseIgnoreSubstrings

This commit is contained in:
Mark Cavage 2013-10-28 21:12:12 +00:00
parent 506b7d2c90
commit aa633dfd20
5 changed files with 142 additions and 50 deletions

View File

@ -692,7 +692,7 @@ Client.prototype.unbind = function unbind(callback) {
var req = new UnbindRequest();
if (this.socket.listeners('error').length === 0) {
this.socket.once('error', function(){});
this.socket.once('error', function () {});
}
return this._send(req, 'unbind', null, callback);
};
@ -725,7 +725,9 @@ Client.prototype._connect = function _connect() {
self.emit('connect', socket);
}
socket = proto.connect((this.port || this.socketPath), this.host, this.secure ? this.tlsOptions : null);
socket = proto.connect((this.port || this.socketPath),
this.host,
this.secure ? this.tlsOptions : null);
socket.once('connect', onConnect);
socket.once('secureConnect', onConnect);

View File

@ -6,6 +6,7 @@ var util = require('util');
var Filter = require('./filter');
var Protocol = require('../protocol');
var SubstringFilter = require('./substr_filter');
@ -23,6 +24,10 @@ function ExtensibleFilter(options) {
options = {};
}
this.any = options.any || null;
this.attribute = options.matchType || null;
this['final'] = options['final'] || null;
this.initial = options.initial || null;
this.matchType = options.matchType || null;
this.rule = options.rule || null;
this.value = options.value || '';
@ -90,9 +95,29 @@ ExtensibleFilter.prototype.matches = function (target) {
var self = this;
if (this.matchType && target.hasOwnProperty(this.matchType)) {
if (self.rule === '2.5.13.4' || self.rule === 'caseIgnoreSubstringsMatch') {
var f = {
attribute: self.matchType,
initial: self.initial ? self.initial.toLowerCase() : undefined,
any: self.any ? self.any.map(function (a) {
return a.toLowerCase()
}) : undefined,
'final': self['final'] ? self['final'].toLowerCase() : undefined
};
}
return Filter.multi_test(function (v) {
if (self.rule === '2.5.13.2')
if (self.rule === '2.5.13.2' || self.rule === 'caseIgnoreMatch') {
return self.value.toLowerCase() === v.toLowerCase();
} else if (self.rule === '2.5.13.4' ||
self.rule === 'caseIgnoreSubstringsMatch') {
var t = {};
t[self.matchType] = v.toLowerCase();
return SubstringFilter.prototype.matches.call(f, t);
}
return self.value === v;
}, target[this.matchType]);

View File

@ -60,6 +60,62 @@ function matchParens(str, openParenIndex) {
}
function parse_substr(tree) {
// Effectively a hand-rolled .shift() to support \* sequences
var clean = true;
var esc = false;
var obj = {};
var split = [];
var substrNdx = 0;
split[substrNdx] = '';
for (var i = 0; i < tree.value.length; i++) {
var c = tree.value[i];
if (esc) {
split[substrNdx] += c;
esc = false;
} else if (c === '*') {
split[++substrNdx] = '';
} else if (c === '\\') {
esc = true;
} else {
split[substrNdx] += c;
}
}
if (split.length > 1) {
obj.tag = 'substrings';
clean = true;
// if the value string doesn't start with a * then theres no initial
// value else split will have an empty string in its first array
// index...
// we need to remove that empty string
if (tree.value.indexOf('*') !== 0) {
obj.initial = split.shift();
} else {
split.shift();
}
// if the value string doesn't end with a * then theres no final
// value also same split stuff as the initial stuff above
if (tree.value.lastIndexOf('*') !== tree.value.length - 1) {
obj['final'] = split.pop();
} else {
split.pop();
}
obj.any = split;
} else {
obj.value = split[0]; // pick up the cleaned version
}
obj.clean = clean;
obj.esc = esc;
return obj;
}
// recursive function that builds a filter tree from a string expression
// the filter tree is an intermediary step between the incoming expression and
// the outgoing Filter Class structure.
@ -70,9 +126,9 @@ function _buildFilterTree(expr) {
var endParen;
var esc = false;
var i = 0;
var obj;
var tree = {};
var split;
var substrNdx = 0;
var val = '';
if (expr.length === 0)
@ -183,59 +239,22 @@ function _buildFilterTree(expr) {
if (tree.value === '*') {
tree.tag = 'present';
} else {
// Effectively a hand-rolled .shift() to support \* sequences
clean = true;
split = [];
substrNdx = 0;
split[substrNdx] = '';
for (i = 0; i < tree.value.length; i++) {
c = tree.value[i];
if (esc) {
split[substrNdx] += c;
esc = false;
} else if (c === '*') {
split[++substrNdx] = '';
} else if (c === '\\') {
esc = true;
} else {
split[substrNdx] += c;
}
}
if (split.length > 1) {
tree.tag = 'substrings';
clean = true;
// if the value string doesn't start with a * then theres no initial
// value else split will have an empty string in its first array
// index...
// we need to remove that empty string
if (tree.value.indexOf('*') !== 0) {
tree.initial = split.shift();
} else {
split.shift();
}
// if the value string doesn't end with a * then theres no final
// value also same split stuff as the initial stuff above
if (tree.value.lastIndexOf('*') !== tree.value.length - 1) {
tree['final'] = split.pop();
} else {
split.pop();
}
tree.any = split;
} else {
tree.value = split[0]; // pick up the cleaned version
}
obj = parse_substr(tree);
tree.initial = obj.initial;
tree.any = obj.any;
tree['final'] = obj['final'];
tree.tag = obj.tag || tree.tag;
tree.value = obj.value;
esc = obj.esc;
clean = obj.clean;
}
} else if (tree.tag == 'extensibleMatch') {
split = tree.name.split(':');
tree.extensible = {
matchType: split[0],
value: tree.value
};
switch (split.length) {
case 1:
break;
@ -253,6 +272,28 @@ function _buildFilterTree(expr) {
default:
throw new Error('Invalid extensible filter');
}
switch (tree.extensible.rule) {
case '2.5.13.4':
case 'caseIgnoreSubstringsMatch':
tree.extensible.attribute = tree.extensible.matchType;
obj = parse_substr(tree);
tree.extensible.initial = obj.initial;
tree.extensible.any = obj.any;
tree.extensible['final'] = obj['final'];
tree.value = obj.value;
esc = obj.esc;
clean = obj.clean;
break;
case '2.5.13.2':
case 'caseIgnoreMatch':
tree.extensible.attribute = tree.extensible.matchType;
break;
default:
// noop
break;
}
}
}

View File

@ -52,6 +52,7 @@ module.exports = {
if (tmp[3]) {
u.extensions = querystring.unescape(tmp[3]);
}
if (!u.scope)
u.scope = 'base';
if (!u.filter)

View File

@ -108,3 +108,26 @@ test('parse RFC example 5', function (t) {
t.ok(f.dnAttributes);
t.end();
});
test('parse caseIgnore', function (t) {
var f = filters.parseString('(cn:caseIgnoreMatch:=Dino)');
t.ok(f);
t.ok(f.matchType);
t.equal(f.matchingRule, 'caseIgnoreMatch');
t.equal(f.matchValue, 'Dino');
t.ok(f.matches({cn: 'dino'}));
t.end();
});
test('parse case substrings', function (t) {
var f = filters.parseString('(cn:caseIgnoreSubstringsMatch:=*i*o)');
t.ok(f);
t.ok(f.matchType);
t.equal(f.matchingRule, 'caseIgnoreSubstringsMatch');
t.ok(f.any);
t.ok(f['final']);
t.ok(f.matches({cn: 'dino'}));
t.end();
});