From ec326905356c59aed51c6f6516db5a1b5d8516d6 Mon Sep 17 00:00:00 2001 From: Mayank Maheshwari <51356673+maheshwari-mayank@users.noreply.github.com> Date: Tue, 19 Apr 2022 22:07:43 +0530 Subject: [PATCH] CVE-2020-25614: Update xmlquery, jsonquery and xpath packages. (#58) Updated xmlquery version from 1.2.1 to 1.3.1 Updated jsonquery version from 1.1.0 to 1.1.4 Updated xpath version from 1.1.2 to 1.1.10 Updated patch files as package version are updated. --- go.mod | 7 +- go.sum | 20 ++- patches/jsonquery.patch | 10 +- patches/xmlquery.patch | 14 +- patches/xpath.patch | 331 +++++++++++++--------------------------- 5 files changed, 137 insertions(+), 245 deletions(-) diff --git a/go.mod b/go.mod index 4c681b718d0c..5e89aca469df 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,12 @@ module github.com/Azure/sonic-mgmt-common require ( github.com/Workiva/go-datastructures v1.0.50 - github.com/antchfx/jsonquery v1.1.0 - github.com/antchfx/xmlquery v1.2.1 - github.com/antchfx/xpath v1.1.2 + github.com/antchfx/jsonquery v1.1.4 + github.com/antchfx/xmlquery v1.3.1 + github.com/antchfx/xpath v1.1.10 github.com/go-redis/redis v6.15.6+incompatible github.com/go-redis/redis/v7 v7.0.0-beta.3.0.20190824101152-d19aba07b476 + github.com/godbus/dbus/v5 v5.1.0 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/openconfig/gnmi v0.0.0-20200617225440-d2b4e6a45802 diff --git a/go.sum b/go.sum index 61b669bae434..0ddf3662610e 100644 --- a/go.sum +++ b/go.sum @@ -2,12 +2,13 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Workiva/go-datastructures v1.0.50 h1:slDmfW6KCHcC7U+LP3DDBbm4fqTwZGn1beOFPfGaLvo= github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= -github.com/antchfx/jsonquery v1.1.0 h1:ZeqeHheI8WsEN5blUqZXZ30w2jrbFvlQIq5B7X7Z86E= -github.com/antchfx/jsonquery v1.1.0/go.mod h1:h7950pvPrUZzJIflNqsELgDQovTpPNa0rAHf8NwjegY= -github.com/antchfx/xmlquery v1.2.1 h1:wE4xjHrqOScP440wdv23Xkg0Gr8JryW0ptqodPH+y2U= -github.com/antchfx/xmlquery v1.2.1/go.mod h1:/+CnyD/DzHRnv2eRxrVbieRU/FIF6N0C+7oTtyUtCKk= -github.com/antchfx/xpath v1.1.2 h1:YziPrtM0gEJBnhdUGxYcIVYXZ8FXbtbovxOi+UW/yWQ= -github.com/antchfx/xpath v1.1.2/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= +github.com/antchfx/jsonquery v1.1.4 h1:+OlFO3QS9wjU0MKx9MgHm5f6o6hdd4e9mUTp0wTjxlM= +github.com/antchfx/jsonquery v1.1.4/go.mod h1:cHs8r6Bymd8j6HI6Ej1IJbjahKvLBcIEh54dfmo+E9A= +github.com/antchfx/xmlquery v1.3.1 h1:nIKWdtnhrXtj0/IRUAAw2I7TfpHUa3zMnHvNmPXFg+w= +github.com/antchfx/xmlquery v1.3.1/go.mod h1:64w0Xesg2sTaawIdNqMB+7qaW/bSqkQm+ssPaCMWNnc= +github.com/antchfx/xpath v1.1.7/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= +github.com/antchfx/xpath v1.1.10 h1:cJ0pOvEdN/WvYXxvRrzQH9x5QWKpzHacYO8qzCcDYAg= +github.com/antchfx/xpath v1.1.10/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -21,6 +22,8 @@ github.com/go-redis/redis v6.15.6+incompatible h1:H9evprGPLI8+ci7fxQx6WNZHJSb7be github.com/go-redis/redis v6.15.6+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v7 v7.0.0-beta.3.0.20190824101152-d19aba07b476 h1:WNSiFp8Ww4ZP7XUzW56zDYv5roKQ4VfsdHCLoh8oDj4= github.com/go-redis/redis/v7 v7.0.0-beta.3.0.20190824101152-d19aba07b476/go.mod h1:xhhSbUMTsleRPur+Vgx9sUHtyN33bdjxY+9/0n9Ig8s= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= @@ -74,6 +77,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -87,6 +91,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4= +golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -97,6 +103,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/patches/jsonquery.patch b/patches/jsonquery.patch index cca6140eccc8..62e7565056d8 100644 --- a/patches/jsonquery.patch +++ b/patches/jsonquery.patch @@ -1,5 +1,5 @@ diff --git a/node.go b/node.go -index 76032bb..f6103d9 100644 +index 4b28b32..afeed80 100644 --- a/node.go +++ b/node.go @@ -8,6 +8,7 @@ import ( @@ -10,7 +10,7 @@ index 76032bb..f6103d9 100644 ) // A NodeType is the type of a Node. -@@ -110,6 +111,29 @@ func parseValue(x interface{}, top *Node, level int) { +@@ -143,6 +144,29 @@ func parseValue(x interface{}, top *Node, level int) { addNode(n) parseValue(vv, n, level+1) } @@ -40,7 +40,7 @@ index 76032bb..f6103d9 100644 case map[string]interface{}: // The Go’s map iteration order is random. // (https://blog.golang.org/go-maps-in-action#Iteration-order) -@@ -119,9 +143,21 @@ func parseValue(x interface{}, top *Node, level int) { +@@ -152,9 +176,21 @@ func parseValue(x interface{}, top *Node, level int) { } sort.Strings(keys) for _, key := range keys { @@ -64,7 +64,7 @@ index 76032bb..f6103d9 100644 } case string: n := &Node{Data: v, Type: TextNode, level: level} -@@ -155,3 +191,9 @@ func Parse(r io.Reader) (*Node, error) { +@@ -188,3 +224,9 @@ func Parse(r io.Reader) (*Node, error) { } return parse(b) } @@ -75,7 +75,7 @@ index 76032bb..f6103d9 100644 + return doc, nil +} diff --git a/query.go b/query.go -index d105962..e8db1d6 100644 +index 6421801..e3df27a 100644 --- a/query.go +++ b/query.go @@ -120,6 +120,14 @@ func (a *NodeNavigator) MoveToRoot() { diff --git a/patches/xmlquery.patch b/patches/xmlquery.patch index fbb218e8492f..0ea86b3a2b67 100644 --- a/patches/xmlquery.patch +++ b/patches/xmlquery.patch @@ -1,8 +1,8 @@ diff --git a/node.go b/node.go -index e86c0c3..028867c 100644 +index e053748..1c9a529 100644 --- a/node.go +++ b/node.go -@@ -48,7 +48,7 @@ type Node struct { +@@ -45,7 +45,7 @@ type Node struct { // InnerText returns the text between the start and end tags of the object. func (n *Node) InnerText() string { @@ -10,8 +10,8 @@ index e86c0c3..028867c 100644 + /*var output func(*bytes.Buffer, *Node) output = func(buf *bytes.Buffer, n *Node) { switch n.Type { - case TextNode: -@@ -64,7 +64,18 @@ func (n *Node) InnerText() string { + case TextNode, CharDataNode: +@@ -60,7 +60,18 @@ func (n *Node) InnerText() string { var buf bytes.Buffer output(&buf, n) @@ -32,7 +32,7 @@ index e86c0c3..028867c 100644 func (n *Node) sanitizedData(preserveSpaces bool) string { diff --git a/query.go b/query.go -index 146c2a4..f21b61b 100644 +index c148e5f..4ac76af 100644 --- a/query.go +++ b/query.go @@ -49,6 +49,29 @@ func CreateXPathNavigator(top *Node) *NodeNavigator { @@ -65,7 +65,7 @@ index 146c2a4..f21b61b 100644 func getCurrentNode(it *xpath.NodeIterator) *Node { n := it.Current().(*NodeNavigator) if n.NodeType() == xpath.AttributeNode { -@@ -145,7 +168,7 @@ func FindEachWithBreak(top *Node, expr string, cb func(int, *Node) bool) { +@@ -146,7 +169,7 @@ func FindEachWithBreak(top *Node, expr string, cb func(int, *Node) bool) { } type NodeNavigator struct { @@ -74,7 +74,7 @@ index 146c2a4..f21b61b 100644 attr int } -@@ -212,6 +235,17 @@ func (x *NodeNavigator) MoveToRoot() { +@@ -217,6 +240,17 @@ func (x *NodeNavigator) MoveToRoot() { x.curr = x.root } diff --git a/patches/xpath.patch b/patches/xpath.patch index 704d60fd1601..9d5ee75e82ec 100644 --- a/patches/xpath.patch +++ b/patches/xpath.patch @@ -1,28 +1,27 @@ diff --git a/build.go b/build.go -index 74f266b..d7d3aab 100644 +index b7f850f..1f65aec 100644 --- a/build.go +++ b/build.go -@@ -44,7 +44,9 @@ func axisPredicate(root *axisNode) func(NodeNavigator) bool { +@@ -44,7 +44,8 @@ func axisPredicate(root *axisNode) func(NodeNavigator) bool { predicate := func(n NodeNavigator) bool { if typ == n.NodeType() || typ == allNode || typ == TextNode { if nametest { - if root.LocalName == n.LocalName() && root.Prefix == n.Prefix() { + prefix := n.Prefix() -+ if root.LocalName == n.LocalName() && -+ ((root.Prefix == prefix) || (prefix == n.CurrentPrefix())) { ++ if root.LocalName == n.LocalName() && (root.Prefix == prefix || prefix == n.CurrentPrefix()) { return true } } else { -@@ -107,7 +109,7 @@ func (b *builder) processAxisNode(root *axisNode) (query, error) { +@@ -118,7 +119,7 @@ func (b *builder) processAxisNode(root *axisNode) (query, error) { } return v } - qyOutput = &childQuery{Input: qyInput, Predicate: filter} -+ qyOutput = &childQuery{Name: &root.LocalName, Prefix: &root.Prefix, Input: qyInput, Predicate: filter} ++ qyOutput = &childQuery{Name: &root.LocalName, Prefix: &root.Prefix, Input: qyInput, Predicate: filter} case "descendant": qyOutput = &descendantQuery{Input: qyInput, Predicate: predicate} case "descendant-or-self": -@@ -130,9 +132,66 @@ func (b *builder) processAxisNode(root *axisNode) (query, error) { +@@ -141,9 +142,64 @@ func (b *builder) processAxisNode(root *axisNode) (query, error) { err = fmt.Errorf("unknown axe type: %s", root.AxeType) return nil, err } @@ -43,9 +42,7 @@ index 74f266b..d7d3aab 100644 +} + +func (b *builder) setCaller(callee, caller query) { -+ + isCallerFilterQ := false -+ + switch typ := caller.(type) { + case *parentQuery: + isCallerFilterQ = typ.SFilter.UnderFilter @@ -89,7 +86,7 @@ index 74f266b..d7d3aab 100644 // processFilterNode builds query for the XPath filter predicate. func (b *builder) processFilterNode(root *filterNode) (query, error) { b.flag |= filterFlag -@@ -146,6 +205,10 @@ func (b *builder) processFilterNode(root *filterNode) (query, error) { +@@ -157,6 +213,10 @@ func (b *builder) processFilterNode(root *filterNode) (query, error) { return nil, err } qyOutput := &filterQuery{Input: qyInput, Predicate: qyCond} @@ -100,28 +97,25 @@ index 74f266b..d7d3aab 100644 return qyOutput, nil } -@@ -339,6 +402,9 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) { +@@ -369,6 +429,7 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) { return nil, err } qyOutput = &functionQuery{Input: argQuery, Func: countFunc} -+ + b.setCaller(argQuery, qyOutput) -+ case "sum": if len(root.Args) == 0 { return nil, fmt.Errorf("xpath: sum(node-sets) function must with have parameters node-sets") -@@ -379,6 +445,10 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) { - args = append(args, q) +@@ -418,6 +479,9 @@ func (b *builder) processFunctionNode(root *functionNode) (query, error) { + return nil, err } - qyOutput = &functionQuery{Input: b.firstInput, Func: concatFunc(args...)} + qyOutput = &transformFunctionQuery{Input: argQuery, Func: reverseFunc} + case "current": + qyOutput = &functionQuery{Input: ¤tQuery{}, Func: currentFunc} + b.setCaller(qyOutput.(*functionQuery).Input, qyOutput) -+ default: return nil, fmt.Errorf("not yet support this function %s()", root.FuncName) } -@@ -396,13 +466,15 @@ func (b *builder) processOperatorNode(root *operatorNode) (query, error) { +@@ -435,13 +499,15 @@ func (b *builder) processOperatorNode(root *operatorNode) (query, error) { } var qyOutput query switch root.Op { @@ -138,7 +132,7 @@ index 74f266b..d7d3aab 100644 case "div": exprFunc = divFunc case "mod": -@@ -435,6 +507,10 @@ func (b *builder) processOperatorNode(root *operatorNode) (query, error) { +@@ -474,6 +540,10 @@ func (b *builder) processOperatorNode(root *operatorNode) (query, error) { case "|": qyOutput = &unionQuery{Left: left, Right: right} } @@ -150,25 +144,27 @@ index 74f266b..d7d3aab 100644 } diff --git a/func.go b/func.go -index a2f0dce..4abde27 100644 +index bcfee55..a0a80a4 100644 --- a/func.go +++ b/func.go -@@ -21,6 +21,11 @@ func predicate(q query) func(NodeNavigator) bool { +@@ -36,6 +36,11 @@ func predicate(q query) func(NodeNavigator) bool { return func(NodeNavigator) bool { return true } } -+// currentFunc is a XPath Node Set functions current(). ++// currentFunc is a XPath Node Set functions current() +func currentFunc(q query, t iterator) interface{} { -+ return q.Evaluate(t) ++ return functionArgs(q).Evaluate(t) +} + // positionFunc is a XPath Node Set functions position(). func positionFunc(q query, t iterator) interface{} { var ( -@@ -58,16 +63,59 @@ func lastFunc(q query, t iterator) interface{} { +@@ -73,16 +78,56 @@ func lastFunc(q query, t iterator) interface{} { // countFunc is a XPath Node Set functions count(node-set). func countFunc(q query, t iterator) interface{} { var count = 0 +- q = functionArgs(q) ++ //q = functionArgs(q) + var fQuery *functionQuery = nil + + switch qtyp := q.(type) { @@ -193,7 +189,6 @@ index a2f0dce..4abde27 100644 switch typ := q.Evaluate(t).(type) { case query: for node := typ.Select(t); node != nil; node = typ.Select(t) { -+ + tmpNode := node.Copy() + if (strings.HasSuffix(node.LocalName(), "_LIST") == false) { + //Go to leaf's parent i.e. list @@ -206,7 +201,6 @@ index a2f0dce..4abde27 100644 + //which is already counted during path evaluation + continue + } -+ + } + if test(node) { @@ -214,73 +208,40 @@ index a2f0dce..4abde27 100644 } } } -- return float64(count) + if (fQuery != nil) && (fQuery.CountFuncVal > 0) { -+ // -1 since first data always gets added before ++ // -1 since first data always gets added before + //starting xpath evaluation, then count is fetched from Redis + return (float64(count) + (fQuery.CountFuncVal)) ++ } + -+ } else { -+ return float64(count) + return float64(count) + } + +@@ -561,6 +606,9 @@ func functionArgs(q query) query { + if _, ok := q.(*functionQuery); ok { + return q + } ++ if _, ok := q.(*currentQuery); ok { ++ return q + } + return q.Clone() } - // sumFunc is a XPath Node Set functions sum(node-set). diff --git a/operator.go b/operator.go -index 308d3cb..e40b4b7 100644 +index 8c2f31f..d726a5d 100644 --- a/operator.go +++ b/operator.go -@@ -45,7 +45,13 @@ var logicalFuncs = [][]logical{ - } - - // number vs number --func cmpNumberNumberF(op string, a, b float64) bool { -+func cmpNumberNumberF(op string, a, b float64) (r bool) { -+ defer func() { -+ res := &r -+ Log("cmpNumberNumberF(): (%f %s %f) = %t", -+ a, op, b, *res) -+ }() -+ - switch op { - case "=": - return a == b -@@ -64,7 +70,13 @@ func cmpNumberNumberF(op string, a, b float64) bool { - } - - // string vs string --func cmpStringStringF(op string, a, b string) bool { -+func cmpStringStringF(op string, a, b string)(r bool) { -+ defer func(){ -+ res := &r -+ Log("cmpStringStringF(): ('%v' %s '%v') == %v", -+ a, op, b, *res) -+ }() -+ - switch op { - case "=": - return a == b -@@ -82,7 +94,13 @@ func cmpStringStringF(op string, a, b string) bool { - return false - } - --func cmpBooleanBooleanF(op string, a, b bool) bool { -+func cmpBooleanBooleanF(op string, a, b bool) (r bool) { -+ defer func(){ -+ res := &r -+ Log("cmpBooleanBooleanF(): (%v %s %v) = %v", -+ a, op, b, *res) -+ }() -+ - switch op { - case "or": - return a || b -@@ -163,6 +181,48 @@ func cmpNodeSetString(t iterator, op string, m, n interface{}) bool { - } - +@@ -165,15 +165,46 @@ func cmpNodeSetString(t iterator, op string, m, n interface{}) bool { func cmpNodeSetNodeSet(t iterator, op string, m, n interface{}) bool { -+ a := m.(query) -+ b := n.(query) + a := m.(query) + b := n.(query) +- x := a.Select(t) +- if x == nil { +- return false +- } +- y := b.Select(t) +- if y == nil { +- return false + + for { + node := a.Select(t) @@ -313,26 +274,23 @@ index 308d3cb..e40b4b7 100644 + } + } + } else { -+ // + if cmpStringStringF(op, opnd1, opnd2) { + return true + } + } + } -+ } + } +- return cmpStringStringF(op, x.Value(), y.Value()) + - return false ++ return false } + func cmpStringNumeric(t iterator, op string, m, n interface{}) bool { diff --git a/query.go b/query.go -index afeb890..d3322cf 100644 +index 47f8076..b66285b 100644 --- a/query.go +++ b/query.go -@@ -1,10 +1,12 @@ - package xpath -- - import ( - "bytes" +@@ -5,6 +5,9 @@ import ( "fmt" "hash/fnv" "reflect" @@ -342,7 +300,7 @@ index afeb890..d3322cf 100644 ) type iterator interface { -@@ -33,10 +35,251 @@ func (nopQuery) Evaluate(iterator) interface{} { return nil } +@@ -33,10 +36,234 @@ func (nopQuery) Evaluate(iterator) interface{} { return nil } func (nopQuery) Clone() query { return nopQuery{} } @@ -368,10 +326,8 @@ index afeb890..d3322cf 100644 + if (val != nil) { + typ.SFilter.Predicate = fmt.Sprintf("%v", val) + } -+ + sf = &typ.SFilter + case *childQuery: -+ + //Reach to the parent list or first filter and then parent list + var caller query = typ.Caller + fQuery := false @@ -383,17 +339,15 @@ index afeb890..d3322cf 100644 + fQuery = true + } else { + //Once filter query is reached, look for child query only -+ if (fQuery == true) && -+ (reflect.TypeOf(caller) != reflect.TypeOf(&childQuery{})) { ++ if (fQuery == true) && (reflect.TypeOf(caller) != reflect.TypeOf(&childQuery{})) { + caller = nil + break + } + + fieldVal = reflect.ValueOf(caller).Elem().FieldByName("Caller") -+ + } + if fieldVal.IsValid() && fieldVal.IsNil() == false { -+ //caller = caller.Caller ... previous caller ++ //caller = caller.Caller ... previous caller + caller = fieldVal.Interface().(query) + } else { + caller = nil @@ -401,8 +355,7 @@ index afeb890..d3322cf 100644 + } + + nameVal := reflect.ValueOf(caller).Elem().FieldByName("Name") -+ if nameVal.IsValid() && -+ strings.HasSuffix(nameVal.Elem().String(), "_LIST") { ++ if nameVal.IsValid() && strings.HasSuffix(nameVal.Elem().String(), "_LIST") { + //List element found + break + } else if (fQuery == true) { @@ -442,8 +395,7 @@ index afeb890..d3322cf 100644 + case *functionQuery: // current()/ + break + case *parentQuery: // current()/../ -+ //Just break, since the value should be used for -+ //filter script ++ //Just break, since the value should be used for filter script + break + default: + if (isChildAKey == true) { @@ -481,16 +433,9 @@ index afeb890..d3322cf 100644 + } + if (sfl != nil && sfr != nil) { + if (strings.Contains(sfr.Predicate, ",")) { //multi value -+ //typ.SFilter.Predicate = fmt.Sprintf( -+ // "(string.match('%s', %s..'[,]*') ~= nil)", -+ // sfr.Predicate, sfl.Predicate) -+ typ.SFilter.Predicate = "(string.match('" + -+ sfr.Predicate + "', " + sfl.Predicate + "..'[,]*') ~= nil)" ++ typ.SFilter.Predicate = "(string.match('" + sfr.Predicate + "', " + sfl.Predicate + "..'[,]*') ~= nil)" + } else { -+ //typ.SFilter.Predicate = fmt.Sprintf("(%s %s '%s')", -+ //sfl.Predicate, op, sfr.Predicate) -+ typ.SFilter.Predicate = "(" + sfl.Predicate + op + "'" + -+ sfr.Predicate + "')" ++ typ.SFilter.Predicate = "(" + sfl.Predicate + op + "'" + sfr.Predicate + "')" + } + } + @@ -505,12 +450,10 @@ index afeb890..d3322cf 100644 + } + + if (sfl != nil && sfr != nil) { -+ typ.SFilter.Predicate = fmt.Sprintf("(%s %s %s)", -+ sfl.Predicate, op, sfr.Predicate) ++ typ.SFilter.Predicate = fmt.Sprintf("(%s %s %s)", sfl.Predicate, op, sfr.Predicate) + } + + sf = &typ.SFilter -+ + case *functionQuery: + sfi := setScriptFilter(typ.Input, nil) + if (sfi != nil) { @@ -551,8 +494,7 @@ index afeb890..d3322cf 100644 + + nodeLocalName := node.LocalName() + -+ if (rootLocalName == nodeLocalName) && -+ (rootPrefix == node.Prefix()) { ++ if (rootLocalName == nodeLocalName) && (rootPrefix == node.Prefix()) { + return node + } + @@ -570,7 +512,6 @@ index afeb890..d3322cf 100644 + + return n + } -+ + c.iterator = nil + + return nil @@ -594,14 +535,14 @@ index afeb890..d3322cf 100644 } func (c *contextQuery) Select(t iterator) (n NodeNavigator) { -@@ -164,13 +407,103 @@ func (a *attributeQuery) Clone() query { +@@ -165,13 +392,97 @@ func (a *attributeQuery) Clone() query { return &attributeQuery{Input: a.Input.Clone(), Predicate: a.Predicate} } +type scriptFilter struct { + Key []string //all keys in slice |*|Key2|* -+ Predicate string //Keys and fields as lua condition in filter -+ // - (h.Key1 == 'Test' and h.Field1 == 'test') ++ Predicate string //Keys and fields as lua condition in filter ++ // - (h.Key1 == 'Test' and h.Field1 == 'test') + Fields string //Fields to retrieve |Field1|Field2|Field3| + UnderFilter bool //If the query is within filter query +} @@ -612,12 +553,12 @@ index afeb890..d3322cf 100644 + Prefix *string posit int iterator func() NodeNavigator -- + Input query Predicate func(NodeNavigator) bool + Caller query + SFilter scriptFilter -+ execFilter bool // Execute filter only once during expression ++ execFilter bool // Execute filter only once during expression +} + +//Check for count("../TABLE_LIST"), count("../TABLE_LIST/field"), @@ -651,21 +592,17 @@ index afeb890..d3322cf 100644 + +//Execute filter if no predicate is provided +func executeFilterWithoutPred(c *childQuery) { -+ + //Should be a list and filter should have not excuted already -+ if ((strings.HasSuffix(*c.Name, "_LIST")) == false) || -+ (c.execFilter == true) { ++ if (strings.HasSuffix(*c.Name, "_LIST") == false) || (c.execFilter == true) { + return + } + + //Should not be a filterQuery i.e. no predicate -+ if (c.Caller == nil) || -+ (reflect.TypeOf(c.Caller) == reflect.TypeOf(&filterQuery{})) { ++ if (c.Caller == nil) || (reflect.TypeOf(c.Caller) == reflect.TypeOf(&filterQuery{})) { + return + } + + funcQ, fieldName := checkIfCountFunc(c) -+ + listName := *c.Name + listName = listName[:len(listName) - len("_LIST")] + @@ -687,19 +624,16 @@ index afeb890..d3322cf 100644 + } + + if (funcQ != nil) { //Within a count function -+ funcQ.CountFuncVal = getDepDataCntClbk(depDataCtxt, -+ redisTblname + "|*", keyNames, "", fieldName) ++ funcQ.CountFuncVal = getDepDataCntClbk(depDataCtxt, redisTblname + "|*", keyNames, "", fieldName) + } else { -+ getDepDataClbk(depDataCtxt, []string{}, -+ redisTblname + "|*", -+ keyNames, "true", "", "") ++ getDepDataClbk(depDataCtxt, []string{}, redisTblname + "|*", keyNames, "true", "", "") + } + + c.execFilter = true } func (c *childQuery) Select(t iterator) NodeNavigator { -@@ -181,6 +514,10 @@ func (c *childQuery) Select(t iterator) NodeNavigator { +@@ -182,6 +493,10 @@ func (c *childQuery) Select(t iterator) NodeNavigator { if node == nil { return nil } @@ -710,7 +644,7 @@ index afeb890..d3322cf 100644 node = node.Copy() first := true c.iterator = func() NodeNavigator { -@@ -198,6 +535,10 @@ func (c *childQuery) Select(t iterator) NodeNavigator { +@@ -199,6 +514,10 @@ func (c *childQuery) Select(t iterator) NodeNavigator { if node := c.iterator(); node != nil { c.posit++ @@ -721,7 +655,7 @@ index afeb890..d3322cf 100644 return node } c.iterator = nil -@@ -207,6 +548,12 @@ func (c *childQuery) Select(t iterator) NodeNavigator { +@@ -208,6 +527,12 @@ func (c *childQuery) Select(t iterator) NodeNavigator { func (c *childQuery) Evaluate(t iterator) interface{} { c.Input.Evaluate(t) c.iterator = nil @@ -734,7 +668,7 @@ index afeb890..d3322cf 100644 return c } -@@ -215,7 +562,7 @@ func (c *childQuery) Test(n NodeNavigator) bool { +@@ -216,7 +541,7 @@ func (c *childQuery) Test(n NodeNavigator) bool { } func (c *childQuery) Clone() query { @@ -743,7 +677,7 @@ index afeb890..d3322cf 100644 } // position returns a position of current NodeNavigator. -@@ -473,6 +820,8 @@ func (p *precedingQuery) position() int { +@@ -479,6 +804,8 @@ func (p *precedingQuery) position() int { type parentQuery struct { Input query Predicate func(NodeNavigator) bool @@ -752,7 +686,7 @@ index afeb890..d3322cf 100644 } func (p *parentQuery) Select(t iterator) NodeNavigator { -@@ -505,6 +854,8 @@ func (p *parentQuery) Test(n NodeNavigator) bool { +@@ -511,6 +838,8 @@ func (p *parentQuery) Test(n NodeNavigator) bool { type selfQuery struct { Input query Predicate func(NodeNavigator) bool @@ -761,22 +695,17 @@ index afeb890..d3322cf 100644 } func (s *selfQuery) Select(t iterator) NodeNavigator { -@@ -538,10 +889,14 @@ type filterQuery struct { - Input query +@@ -545,6 +874,9 @@ type filterQuery struct { Predicate query posit int -+ //execFilter bool // Execute filter only once during expression + positmap map[int]int ++ //execFilter bool // Execute filter only once during expression + Caller query + SFilter scriptFilter } func (f *filterQuery) do(t iterator) bool { - val := reflect.ValueOf(f.Predicate.Evaluate(t)) -+ - switch val.Kind() { - case reflect.Bool: - return val.Bool() -@@ -562,21 +917,198 @@ func (f *filterQuery) position() int { +@@ -569,7 +901,149 @@ func (f *filterQuery) position() int { return f.posit } @@ -789,7 +718,6 @@ index afeb890..d3322cf 100644 +} + +func checkForKeyFilter(keys []string, predicate string) string { -+ + if (predicate == "") { + return "" + } @@ -805,8 +733,7 @@ index afeb890..d3322cf 100644 + keyFilter[idx] = "*" //fill with default pattern + } + -+ //All are keys in predicate, form the key filter and -+ //remove generic predicate ++ //All are keys in predicate, form the key filter and remove generic predicate + + //first split by 'and' + for _, keyEqExpr := range strings.Split(tmpPredicate, " and ") { @@ -838,17 +765,17 @@ index afeb890..d3322cf 100644 + switch typ := f.Predicate.(type) { + case *logicalQuery: + f.SFilter = typ.SFilter -+ Log("executeFilter(): getting filtered data, predicate=%s", f.SFilter.Predicate) ++ Log("executeFilter() for logicalQuery: getting filtered data, predicate=%s", f.SFilter.Predicate) + case *booleanQuery: + f.SFilter = typ.SFilter -+ Log("executeFilter(): getting filtered data, predicate=%s", f.SFilter.Predicate) ++ Log("executeFilter() for booleanQuery: getting filtered data, predicate=%s", f.SFilter.Predicate) + } + //All filter must be executed only once + //Need to excute filter script and then collect leaf data + //for multiple data it should be separated by "," + //Filter script should have - strings.match("Eth1,Eth2,Eth4", "Eth1[,]*)) + -+ //Get leaf data ++ //Get leaf data + var cq *childQuery = nil + if (f.Caller != nil) { + switch typ := f.Caller.(type) { @@ -860,7 +787,6 @@ index afeb890..d3322cf 100644 + if (f.Input != nil) { + switch typ := f.Input.(type) { + case *childQuery: -+ + listName := *typ.Name + listName = listName[:len(listName) - len("_LIST")] + @@ -892,8 +818,6 @@ index afeb890..d3322cf 100644 + keyFilter = redisTblname + "|*" + } + -+ -+ + //Check if count(), just store the count from + //Redis without fetching data + funcQ, fieldName := checkIfCountFunc(f) @@ -917,36 +841,24 @@ index afeb890..d3322cf 100644 + + //Set single field data to child + cq.SFilter.Predicate = data -+ Log("executeFilter(): value returned for '%s' is '%s' " + -+ "inside predicate", cq.SFilter.Fields, data) ++ Log("executeFilter(): value returned for '%s' is '%s' inside predicate", cq.SFilter.Fields, data) + } else { + //Just filter query -+ getDepDataClbk(depDataCtxt, []string{}, -+ keyFilter, -+ keyNames, -+ f.SFilter.Predicate, "", "") ++ getDepDataClbk(depDataCtxt, []string{}, keyFilter, keyNames, f.SFilter.Predicate, "", "") + } + } + } -+ +} + func (f *filterQuery) Select(t iterator) NodeNavigator { - + success := false - for { - - node := f.Input.Select(t) - if node == nil { - return node - } -+ - node = node.Copy() - - t.Current().MoveTo(node) -+ - if f.do(t) { - f.posit++ + if f.positmap == nil { + f.positmap = make(map[int]int) + } +@@ -588,6 +1062,27 @@ func (f *filterQuery) Select(t iterator) NodeNavigator { + level := getNodeDepth(f.Input) + f.positmap[level]++ + f.posit = f.positmap[level] + success = true + } + @@ -960,8 +872,7 @@ index afeb890..d3322cf 100644 + //check the filter flag in list node + switch typ := f.Input.(type) { + case *childQuery: -+ if strings.HasSuffix(*typ.Name, "_LIST") && -+ (typ.execFilter == false) { ++ if strings.HasSuffix(*typ.Name, "_LIST") && (typ.execFilter == false) { + executeFilter(f) + typ.execFilter = true + } @@ -971,11 +882,8 @@ index afeb890..d3322cf 100644 + if (success == true) { return node } -+ - f.posit = 0 } - } -@@ -595,9 +1127,19 @@ func (f *filterQuery) Clone() query { +@@ -608,9 +1103,19 @@ func (f *filterQuery) Clone() query { type functionQuery struct { Input query // Node Set Func func(query, iterator) interface{} // The xpath function. @@ -988,14 +896,14 @@ index afeb890..d3322cf 100644 func (f *functionQuery) Select(t iterator) NodeNavigator { + _, ok := f.Input.(*currentQuery) -+ if ok == true { ++ if ok { + f.SFilter = f.Input.(*currentQuery).SFilter -+ return f.Input.(*currentQuery).Select(t) ++ return f.Input.(*currentQuery).Select(t) + } return nil } -@@ -614,6 +1156,8 @@ func (f *functionQuery) Clone() query { +@@ -655,6 +1160,8 @@ func (f *transformFunctionQuery) Clone() query { // constantQuery is an XPath constant operand. type constantQuery struct { Val interface{} @@ -1004,7 +912,7 @@ index afeb890..d3322cf 100644 } func (c *constantQuery) Select(t iterator) NodeNavigator { -@@ -621,6 +1165,7 @@ func (c *constantQuery) Select(t iterator) NodeNavigator { +@@ -662,6 +1169,7 @@ func (c *constantQuery) Select(t iterator) NodeNavigator { } func (c *constantQuery) Evaluate(t iterator) interface{} { @@ -1012,7 +920,7 @@ index afeb890..d3322cf 100644 return c.Val } -@@ -633,6 +1178,8 @@ type logicalQuery struct { +@@ -674,6 +1182,8 @@ type logicalQuery struct { Left, Right query Do func(iterator, interface{}, interface{}) interface{} @@ -1021,11 +929,8 @@ index afeb890..d3322cf 100644 } func (l *logicalQuery) Select(t iterator) NodeNavigator { -@@ -649,9 +1196,16 @@ func (l *logicalQuery) Select(t iterator) NodeNavigator { - } - +@@ -692,7 +1202,13 @@ func (l *logicalQuery) Select(t iterator) NodeNavigator { func (l *logicalQuery) Evaluate(t iterator) interface{} { -+ m := l.Left.Evaluate(t) n := l.Right.Evaluate(t) - return l.Do(t, m, n) @@ -1039,7 +944,7 @@ index afeb890..d3322cf 100644 } func (l *logicalQuery) Clone() query { -@@ -672,7 +1226,7 @@ func (n *numericQuery) Select(t iterator) NodeNavigator { +@@ -713,7 +1229,7 @@ func (n *numericQuery) Select(t iterator) NodeNavigator { func (n *numericQuery) Evaluate(t iterator) interface{} { m := n.Left.Evaluate(t) k := n.Right.Evaluate(t) @@ -1048,7 +953,7 @@ index afeb890..d3322cf 100644 } func (n *numericQuery) Clone() query { -@@ -683,6 +1237,8 @@ type booleanQuery struct { +@@ -724,6 +1240,8 @@ type booleanQuery struct { IsOr bool Left, Right query iterator func() NodeNavigator @@ -1057,13 +962,9 @@ index afeb890..d3322cf 100644 } func (b *booleanQuery) Select(t iterator) NodeNavigator { -@@ -750,14 +1306,26 @@ func (b *booleanQuery) Select(t iterator) NodeNavigator { - } - +@@ -793,12 +1311,20 @@ func (b *booleanQuery) Select(t iterator) NodeNavigator { func (b *booleanQuery) Evaluate(t iterator) interface{} { -+ m := b.Left.Evaluate(t) -+ left := asBool(t, m) + + if (b.SFilter.UnderFilter == true) { @@ -1077,19 +978,17 @@ index afeb890..d3322cf 100644 return false } - m = b.Right.Evaluate(t) -+ + if (b.SFilter.UnderFilter == false) { + m = b.Right.Evaluate(t) + } -+ return asBool(t, m) } diff --git a/xpath.go b/xpath.go -index d6c9912..2319860 100644 +index 5f6aa89..b10245b 100644 --- a/xpath.go +++ b/xpath.go -@@ -44,6 +44,10 @@ type NodeNavigator interface { +@@ -45,6 +45,10 @@ type NodeNavigator interface { // Copy does a deep copy of the NodeNavigator and all its components. Copy() NodeNavigator @@ -1100,15 +999,7 @@ index d6c9912..2319860 100644 // MoveToRoot moves the NodeNavigator to the root node of the current node. MoveToRoot() -@@ -117,6 +121,7 @@ func (f iteratorFunc) Current() NodeNavigator { - // Evaluate returns the result of the expression. - // The result type of the expression is one of the follow: bool,float64,string,NodeIterator). - func (expr *Expr) Evaluate(root NodeNavigator) interface{} { -+ - val := expr.q.Evaluate(iteratorFunc(func() NodeNavigator { return root })) - switch val.(type) { - case query: -@@ -147,11 +152,48 @@ func Compile(expr string) (*Expr, error) { +@@ -151,6 +155,12 @@ func Compile(expr string) (*Expr, error) { return &Expr{s: expr, q: qy}, nil } @@ -1121,10 +1012,8 @@ index d6c9912..2319860 100644 // MustCompile compiles an XPath expression string and ignored error. func MustCompile(expr string) *Expr { exp, err := Compile(expr) - if err != nil { - return &Expr{s: expr, q: nopQuery{}} +@@ -159,3 +169,27 @@ func MustCompile(expr string) *Expr { } -+ return exp } + @@ -1132,21 +1021,16 @@ index d6c9912..2319860 100644 + getKeysClbk = keyFetchCb +} + -+func SetDepDataClbk(ctxt interface{}, -+ depDataCb func(interface{}, []string, string, string, string, string, string) string) { -+ ++func SetDepDataClbk(ctxt interface{}, depDataCb func(interface{}, []string, string, string, string, string, string) string) { + depDataCtxt = ctxt + getDepDataClbk = depDataCb +} + -+func SetDepDataCntClbk(ctxt interface{}, -+ depDataCntCb func(interface{}, string, string, string, string) float64) { -+ ++func SetDepDataCntClbk(ctxt interface{}, depDataCntCb func(interface{}, string, string, string, string) float64) { + depDataCtxt = ctxt + getDepDataCntClbk = depDataCntCb +} + -+ +func SetLogCallback(clbk func(string, ...interface{})) { + logClbk = clbk +} @@ -1156,4 +1040,3 @@ index d6c9912..2319860 100644 + logClbk(fmt, args...) + } +} -+