diff --git a/lib/filters/index.js b/lib/filters/index.js index 6a7d07d..9e08f05 100644 --- a/lib/filters/index.js +++ b/lib/filters/index.js @@ -28,249 +28,271 @@ var BerReader = asn1.BerReader; ///--- Internal Parsers -//expression parsing -//returns the index of the closing parenthesis matching the open paren specified by openParenIndex -function matchParens(str, openParenIndex){ - var stack = []; - - for(var i=openParenIndex || 0;i - //so thats why its named tag, if you were wondering... - var operatorStr = ""; - var valueOffset=0; - tree.name = ""; - tree.value = ''; - if(expr.indexOf('~=') !=-1 ){ - operatorStr = '~='; - tree.tag = 'approxMatch'; - valueOffset = 2; - }else if(expr.indexOf('>=') != -1){ - operatorStr = '>='; - tree.tag = 'greaterOrEqual'; - valueOffset = 2; - }else if(expr.indexOf('<=') != -1){ - operatorStr = '<='; - tree.tag = 'lessOrEqual'; - valueOffset = 2; - }else if(expr.indexOf("=") != -1){ - operatorStr = '='; - tree.tag = 'equalityMatch'; - valueOffset = 1; - }else { - tree.tag = 'present'; - } - console.log('operatorStr: ' + operatorStr + '; valueOffset: ' + valueOffset); - if (operatorStr == ""){ - tree.name = expr; - }else{ - //pull out lhs and rhs of equality operator - //var index = expr.indexOf('='); - - var splitAry = expr.split(operatorStr,2); - tree.name =splitAry[0]; - tree.value = splitAry[1]; - - //substrings fall into the equality bin in the switch above - //so we need another check here to look for * - if (tree.value.indexOf('*') != -1 && tree.tag == 'equalityMatch'){ - tree.tag = 'substrings'; - - var split = tree.value.split("*"); - - //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; - } - if(tree.value.length == 0){ - tree.tag = 'present'; - } - } - } - - return tree; -}; +// 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. +function _buildFilterTree(expr) { + var tree = {}; + var split; -var treeToObjs = function(tree,filterObj){ - //console.log("in treeToObjs"); - if(tree === undefined){ - return filterObj; - } - - if(tree.length === 0){ - return filterObj; - } - - //if the current tree object is not an expression then its a logical operator (ie an internal node in the tree) - var currentFilter = filterObj; - if(tree.op != "expr"){ - console.log("adding "+tree.op+" to filters"); - switch (tree.op){ - case "and": - filterObj.addFilter(currentFilter = new AndFilter({filters:[]})); - break; - case "or": - filterObj.addFilter(currentFilter = new OrFilter({filters:[]})); - break; - case "not": - filterObj.addFilter(currentFilter = new NotFilter({filters:[]})); - break; - } - for(var i = 0,tempFilter,child;i + // so thats why its named tag, if you were wondering... + var operatorStr = ''; + var valueOffset = 0; + tree.name = ''; + tree.value = ''; + if (expr.indexOf('~=') !== -1) { + operatorStr = '~='; + tree.tag = 'approxMatch'; + valueOffset = 2; + } else if (expr.indexOf('>=') !== -1) { + operatorStr = '>='; + tree.tag = 'greaterOrEqual'; + valueOffset = 2; + } else if (expr.indexOf('<=') !== -1) { + operatorStr = '<='; + tree.tag = 'lessOrEqual'; + valueOffset = 2; + } else if (expr.indexOf(':=') !== -1) { + operatorStr = ':='; + tree.tag = 'extensibleMatch'; + valueOffset = 2; + } else if (expr.indexOf('=') !== -1) { + operatorStr = '='; + tree.tag = 'equalityMatch'; + valueOffset = 1; + } else { + tree.tag = 'present'; + } + + if (operatorStr === '') { + tree.name = expr; + } else { + // pull out lhs and rhs of equality operator + var splitAry = expr.split(operatorStr, 2); + tree.name = splitAry[0]; + tree.value = splitAry[1]; + + // substrings and extensible matching fall into the equality bin in the + // switch above so we need more processing here + if (tree.tag === 'equalityMatch') { + if (tree.value.indexOf('*') !== -1) { + tree.tag = 'substrings'; + + split = tree.value.split('*'); + + // 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 if (tree.value.length === 0) { + tree.tag = 'present'; + } + } else if (tree.tag == 'extensibleMatch') { + split = tree.name.split(':'); + console.log(split) + tree.extensible = { + matchType: split[0], + value: tree.value + }; + switch (split.length) { + case 1: + break; + case 2: + if (split[1].toLowerCase() === 'dn') { + tree.extensible.dnAttributes = true; + } else { + tree.extensible.rule = split[1]; + } + break; + case 3: + tree.extensible.dnAttributes = true; + tree.extensible.rule = split[2]; + break; + default: + throw new Error('Invalid extensible filter'); + } + } + } + } + + return tree; +} -function _parseString(str){ - assert.ok(str); - //create a blank object to pass into treeToObjs - //since its recursive we have to prime it ourselves. - //this gets stripped off before the filter structure is returned - //at the bottom of this function. - var filterObj = new AndFilter({ - filters:[] - }); - - var tree = _buildFilterTree(str); - //console.log("tree built: ",JSON.stringify(tree)); - treeToObjs(tree,filterObj); - return filterObj.filters[0]; -}; +function serializeTree(tree, filter) { + if (tree === undefined || tree.length === 0) + return filter; + + // if the current tree object is not an expression then its a logical + // operator (ie an internal node in the tree) + var current = null; + if (tree.op !== 'expr') { + switch (tree.op) { + case 'and': + current = new AndFilter(); + break; + case 'or': + current = new OrFilter(); + break; + case 'not': + current = new NotFilter(); + break; + } + + filter.addFilter(current || filter); + if (current || tree.children.length) { + tree.children.forEach(function(child) { + serializeTree(child, current); + }); + } + } else { + // else its a leaf node in the tree, and represents some type of + // non-logical expression + var tmp; + + // convert the tag name to a filter class type + switch (tree.tag) { + case 'approxMatch': + tmp = new ApproximateFilter({ + attribute: tree.name, + value: tree.value + }); + break; + case 'extensibleMatch': + tmp = new ExtensibleFilter(tree.extensible); + break; + case 'greaterOrEqual': + tmp = new GreaterThanEqualsFilter({ + attribute: tree.name, + value: tree.value + }); + break; + case 'lessOrEqual': + tmp = new LessThanEqualsFilter({ + attribute: tree.name, + value: tree.value + }); + break; + case 'equalityMatch': + tmp = new EqualityFilter({ + attribute: tree.name, + value: tree.value + }); + break; + case 'substrings': + tmp = new SubstringFilter({ + attribute: tree.name, + initial: tree.initial, + any: tree.any, + 'final': tree['final'] + }); + break; + case 'present': + tmp = new PresenceFilter({ + attribute: tree.name + }); + break; + } + filter.addFilter(tmp); + } +} + + +function _parseString(str) { + assert.ok(str); + + // create a blank object to pass into treeToObjs + // since its recursive we have to prime it ourselves. + // this gets stripped off before the filter structure is returned + // at the bottom of this function. + var filterObj = new AndFilter({ + filters: [] + }); + + serializeTree(_buildFilterTree(str), filterObj); + return filterObj.filters[0]; +} + /* * A filter looks like this coming in: diff --git a/lib/server.js b/lib/server.js index 9bc4b15..9354fde 100644 --- a/lib/server.js +++ b/lib/server.js @@ -425,14 +425,14 @@ function Server(options) { log.trace('data on %s: %s', c.ldap.id, util.inspect(data)); try { - c.parser.write(data); + c.parser.write(data); } catch (e) { - log.warn('Unable to parse message [c.on(\'data\')]: %s', e.stack); - c.end(new LDAPResult({ - status: 0x02, - errorMessage: e.toString(), - connection: c - }).toBer()); + log.warn('Unable to parse message [c.on(\'data\')]: %s', e.stack); + c.end(new LDAPResult({ + status: 0x02, + errorMessage: e.toString(), + connection: c + }).toBer()); } }); diff --git a/tst/filters/ext.test.js b/tst/filters/ext.test.js index c5ce806..07ae381 100644 --- a/tst/filters/ext.test.js +++ b/tst/filters/ext.test.js @@ -108,3 +108,4 @@ test('parse RFC example 5', function(t) { t.ok(f.dnAttributes); t.end(); }); +