support extensible matching of caseIgnore and caseIgnoreSubstrings
This commit is contained in:
parent
506b7d2c90
commit
aa633dfd20
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ module.exports = {
|
|||
if (tmp[3]) {
|
||||
u.extensions = querystring.unescape(tmp[3]);
|
||||
}
|
||||
|
||||
if (!u.scope)
|
||||
u.scope = 'base';
|
||||
if (!u.filter)
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue