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();
|
var req = new UnbindRequest();
|
||||||
if (this.socket.listeners('error').length === 0) {
|
if (this.socket.listeners('error').length === 0) {
|
||||||
this.socket.once('error', function(){});
|
this.socket.once('error', function () {});
|
||||||
}
|
}
|
||||||
return this._send(req, 'unbind', null, callback);
|
return this._send(req, 'unbind', null, callback);
|
||||||
};
|
};
|
||||||
|
@ -725,7 +725,9 @@ Client.prototype._connect = function _connect() {
|
||||||
self.emit('connect', socket);
|
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('connect', onConnect);
|
||||||
socket.once('secureConnect', onConnect);
|
socket.once('secureConnect', onConnect);
|
||||||
|
|
|
@ -6,6 +6,7 @@ var util = require('util');
|
||||||
var Filter = require('./filter');
|
var Filter = require('./filter');
|
||||||
|
|
||||||
var Protocol = require('../protocol');
|
var Protocol = require('../protocol');
|
||||||
|
var SubstringFilter = require('./substr_filter');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +24,10 @@ function ExtensibleFilter(options) {
|
||||||
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.matchType = options.matchType || null;
|
||||||
this.rule = options.rule || null;
|
this.rule = options.rule || null;
|
||||||
this.value = options.value || '';
|
this.value = options.value || '';
|
||||||
|
@ -90,9 +95,29 @@ ExtensibleFilter.prototype.matches = function (target) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
if (this.matchType && target.hasOwnProperty(this.matchType)) {
|
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) {
|
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();
|
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;
|
return self.value === v;
|
||||||
}, target[this.matchType]);
|
}, 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
|
// recursive function that builds a filter tree from a string expression
|
||||||
// the filter tree is an intermediary step between the incoming expression and
|
// the filter tree is an intermediary step between the incoming expression and
|
||||||
// the outgoing Filter Class structure.
|
// the outgoing Filter Class structure.
|
||||||
|
@ -70,9 +126,9 @@ function _buildFilterTree(expr) {
|
||||||
var endParen;
|
var endParen;
|
||||||
var esc = false;
|
var esc = false;
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
var obj;
|
||||||
var tree = {};
|
var tree = {};
|
||||||
var split;
|
var split;
|
||||||
var substrNdx = 0;
|
|
||||||
var val = '';
|
var val = '';
|
||||||
|
|
||||||
if (expr.length === 0)
|
if (expr.length === 0)
|
||||||
|
@ -183,59 +239,22 @@ function _buildFilterTree(expr) {
|
||||||
if (tree.value === '*') {
|
if (tree.value === '*') {
|
||||||
tree.tag = 'present';
|
tree.tag = 'present';
|
||||||
} else {
|
} else {
|
||||||
|
obj = parse_substr(tree);
|
||||||
// Effectively a hand-rolled .shift() to support \* sequences
|
tree.initial = obj.initial;
|
||||||
clean = true;
|
tree.any = obj.any;
|
||||||
split = [];
|
tree['final'] = obj['final'];
|
||||||
substrNdx = 0;
|
tree.tag = obj.tag || tree.tag;
|
||||||
split[substrNdx] = '';
|
tree.value = obj.value;
|
||||||
for (i = 0; i < tree.value.length; i++) {
|
esc = obj.esc;
|
||||||
c = tree.value[i];
|
clean = obj.clean;
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (tree.tag == 'extensibleMatch') {
|
} else if (tree.tag == 'extensibleMatch') {
|
||||||
split = tree.name.split(':');
|
split = tree.name.split(':');
|
||||||
tree.extensible = {
|
tree.extensible = {
|
||||||
matchType: split[0],
|
matchType: split[0],
|
||||||
value: tree.value
|
value: tree.value
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (split.length) {
|
switch (split.length) {
|
||||||
case 1:
|
case 1:
|
||||||
break;
|
break;
|
||||||
|
@ -253,6 +272,28 @@ function _buildFilterTree(expr) {
|
||||||
default:
|
default:
|
||||||
throw new Error('Invalid extensible filter');
|
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]) {
|
if (tmp[3]) {
|
||||||
u.extensions = querystring.unescape(tmp[3]);
|
u.extensions = querystring.unescape(tmp[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!u.scope)
|
if (!u.scope)
|
||||||
u.scope = 'base';
|
u.scope = 'base';
|
||||||
if (!u.filter)
|
if (!u.filter)
|
||||||
|
|
|
@ -108,3 +108,26 @@ test('parse RFC example 5', function (t) {
|
||||||
t.ok(f.dnAttributes);
|
t.ok(f.dnAttributes);
|
||||||
t.end();
|
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