From b1636844ff1ff0f02a7e17c38e5705148cae4fd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 7 Oct 2022 07:20:50 +0000 Subject: [PATCH] Bump github.com/antchfx/xmlquery Bumps [github.com/antchfx/xmlquery](https://github.com/antchfx/xmlquery) from 1.2.3 to 1.3.1. - [Release notes](https://github.com/antchfx/xmlquery/releases) - [Commits](https://github.com/antchfx/xmlquery/compare/v1.2.3...v1.3.1) --- updated-dependencies: - dependency-name: github.com/antchfx/xmlquery dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- ql/test/query-tests/Security/CWE-643/go.mod | 6 +- .../ChrisTrenkamp/goxpath/.travis.yml | 16 + .../ChrisTrenkamp/goxpath/README.md | 2 + .../ChrisTrenkamp/goxpath/coverage.sh | 17 + .../ChrisTrenkamp/goxpath/goxpath.go | 117 + .../goxpath/internal/execxp/execxp.go | 27 + .../internal/execxp/findutil/findUtil.go | 307 + .../goxpath/internal/execxp/intfns/boolfns.go | 74 + .../goxpath/internal/execxp/intfns/intfns.go | 41 + .../internal/execxp/intfns/nodesetfns.go | 131 + .../goxpath/internal/execxp/intfns/numfns.go | 71 + .../internal/execxp/intfns/stringfns.go | 141 + .../goxpath/internal/execxp/operators.go | 212 + .../goxpath/internal/execxp/paths.go | 396 + .../goxpath/internal/xsort/xsort.go | 20 + .../ChrisTrenkamp/goxpath/lexer/lexer.go | 419 + .../ChrisTrenkamp/goxpath/lexer/paths.go | 219 + .../ChrisTrenkamp/goxpath/lexer/xmlchars.go | 316 + .../ChrisTrenkamp/goxpath/marshal.go | 105 + .../ChrisTrenkamp/goxpath/parser/ast.go | 113 + .../ChrisTrenkamp/goxpath/parser/parser.go | 200 + .../goxpath/parser/pathexpr/pathexpr.go | 11 + .../github.com/ChrisTrenkamp/goxpath/stub.go | 54 - .../ChrisTrenkamp/goxpath/tree/interfaces.go | 18 + .../ChrisTrenkamp/goxpath/tree/stub.go | 78 - .../ChrisTrenkamp/goxpath/tree/tree.go | 221 + .../ChrisTrenkamp/goxpath/tree/xfn.go | 52 + .../ChrisTrenkamp/goxpath/tree/xtypes.go | 113 + .../ChrisTrenkamp/goxpath/xconst/xconst.go | 66 + .../github.com/antchfx/htmlquery/.gitignore | 32 + .../github.com/antchfx/htmlquery/.travis.yml | 18 + .../github.com/antchfx/htmlquery/README.md | 168 + .../github.com/antchfx/htmlquery/cache.go | 42 + .../github.com/antchfx/htmlquery/query.go | 338 + .../github.com/antchfx/htmlquery/stub.go | 26 - .../github.com/antchfx/jsonquery/.gitignore | 32 + .../github.com/antchfx/jsonquery/.travis.yml | 16 + .../github.com/antchfx/jsonquery/README.md | 175 + .../github.com/antchfx/jsonquery/books.json | 36 + .../github.com/antchfx/jsonquery/cache.go | 43 + .../github.com/antchfx/jsonquery/node.go | 157 + .../github.com/antchfx/jsonquery/query.go | 177 + .../github.com/antchfx/jsonquery/stub.go | 50 - .../github.com/antchfx/xmlquery/.gitignore | 32 + .../github.com/antchfx/xmlquery/.travis.yml | 15 + .../github.com/antchfx/xmlquery/README.md | 256 + .../github.com/antchfx/xmlquery/books.xml | 121 + .../github.com/antchfx/xmlquery/cache.go | 43 + .../vendor/github.com/antchfx/xmlquery/go.mod | 9 + .../github.com/antchfx/xmlquery/node.go | 221 + .../github.com/antchfx/xmlquery/parse.go | 311 + .../github.com/antchfx/xmlquery/query.go | 299 + .../github.com/antchfx/xmlquery/stub.go | 67 - .../github.com/antchfx/xpath/.gitignore | 32 + .../github.com/antchfx/xpath/.travis.yml | 12 + .../vendor/github.com/antchfx/xpath/README.md | 172 + .../vendor/github.com/antchfx/xpath/build.go | 522 + .../vendor/github.com/antchfx/xpath/func.go | 585 + .../github.com/antchfx/xpath/func_go110.go | 16 + .../antchfx/xpath/func_pre_go110.go | 22 + .../github.com/antchfx/xpath/operator.go | 305 + .../vendor/github.com/antchfx/xpath/parse.go | 1186 + .../vendor/github.com/antchfx/xpath/query.go | 923 + .../vendor/github.com/antchfx/xpath/stub.go | 64 - .../vendor/github.com/antchfx/xpath/xpath.go | 161 + .../github.com/go-xmlpath/xmlpath/README.md | 4 + .../github.com/go-xmlpath/xmlpath/doc.go | 75 + .../github.com/go-xmlpath/xmlpath/parser.go | 396 + .../github.com/go-xmlpath/xmlpath/path.go | 790 + .../github.com/go-xmlpath/xmlpath/stub.go | 56 - .../github.com/golang/groupcache/LICENSE | 191 + .../github.com/golang/groupcache/lru/lru.go | 133 + .../github.com/jbowtie/gokogiri/help/help.go | 74 + .../github.com/jbowtie/gokogiri/util/util.go | 20 + .../jbowtie/gokogiri/xml/attribute.go | 37 + .../github.com/jbowtie/gokogiri/xml/cdata.go | 12 + .../jbowtie/gokogiri/xml/comment.go | 5 + .../jbowtie/gokogiri/xml/document.go | 455 + .../jbowtie/gokogiri/xml/element.go | 5 + .../jbowtie/gokogiri/xml/fragment.go | 115 + .../github.com/jbowtie/gokogiri/xml/helper.c | 195 + .../github.com/jbowtie/gokogiri/xml/helper.h | 37 + .../github.com/jbowtie/gokogiri/xml/node.go | 1186 + .../jbowtie/gokogiri/xml/nodeset.go | 48 + .../github.com/jbowtie/gokogiri/xml/pi.go | 5 + .../github.com/jbowtie/gokogiri/xml/stub.go | 2372 - .../github.com/jbowtie/gokogiri/xml/text.go | 24 + .../jbowtie/gokogiri/xpath/expression.go | 81 + .../github.com/jbowtie/gokogiri/xpath/stub.go | 24 - .../github.com/jbowtie/gokogiri/xpath/util.go | 146 + .../jbowtie/gokogiri/xpath/xpath.go | 274 + .../santhosh-tekuri/xpathparser/.travis.yml | 10 + .../santhosh-tekuri/xpathparser/README.md | 22 + .../santhosh-tekuri/xpathparser/doc.go | 16 + .../santhosh-tekuri/xpathparser/lexer.go | 301 + .../santhosh-tekuri/xpathparser/name.go | 352 + .../santhosh-tekuri/xpathparser/parser.go | 435 + .../santhosh-tekuri/xpathparser/stub.go | 20 - .../santhosh-tekuri/xpathparser/xpath.go | 288 + .../CWE-643/vendor/golang.org/x/net/AUTHORS | 3 + .../vendor/golang.org/x/net/CONTRIBUTORS | 3 + .../CWE-643/vendor/golang.org/x/net/LICENSE | 27 + .../CWE-643/vendor/golang.org/x/net/PATENTS | 22 + .../vendor/golang.org/x/net/html/atom/atom.go | 78 + .../golang.org/x/net/html/atom/table.go | 783 + .../golang.org/x/net/html/charset/charset.go | 257 + .../vendor/golang.org/x/net/html/const.go | 111 + .../vendor/golang.org/x/net/html/doc.go | 106 + .../vendor/golang.org/x/net/html/doctype.go | 156 + .../vendor/golang.org/x/net/html/entity.go | 2253 + .../vendor/golang.org/x/net/html/escape.go | 258 + .../vendor/golang.org/x/net/html/foreign.go | 225 + .../vendor/golang.org/x/net/html/node.go | 225 + .../vendor/golang.org/x/net/html/parse.go | 2425 + .../vendor/golang.org/x/net/html/render.go | 273 + .../vendor/golang.org/x/net/html/token.go | 1224 + .../CWE-643/vendor/golang.org/x/text/AUTHORS | 3 + .../vendor/golang.org/x/text/CONTRIBUTORS | 3 + .../CWE-643/vendor/golang.org/x/text/LICENSE | 27 + .../CWE-643/vendor/golang.org/x/text/PATENTS | 22 + .../x/text/encoding/charmap/charmap.go | 249 + .../x/text/encoding/charmap/tables.go | 7410 +++ .../golang.org/x/text/encoding/encoding.go | 335 + .../x/text/encoding/htmlindex/htmlindex.go | 86 + .../x/text/encoding/htmlindex/map.go | 105 + .../x/text/encoding/htmlindex/tables.go | 352 + .../internal/identifier/identifier.go | 81 + .../text/encoding/internal/identifier/mib.go | 1621 + .../x/text/encoding/internal/internal.go | 75 + .../x/text/encoding/japanese/all.go | 12 + .../x/text/encoding/japanese/eucjp.go | 225 + .../x/text/encoding/japanese/iso2022jp.go | 299 + .../x/text/encoding/japanese/shiftjis.go | 189 + .../x/text/encoding/japanese/tables.go | 26971 ++++++++++ .../x/text/encoding/korean/euckr.go | 177 + .../x/text/encoding/korean/tables.go | 34152 ++++++++++++ .../x/text/encoding/simplifiedchinese/all.go | 12 + .../x/text/encoding/simplifiedchinese/gbk.go | 269 + .../encoding/simplifiedchinese/hzgb2312.go | 245 + .../text/encoding/simplifiedchinese/tables.go | 43999 ++++++++++++++++ .../text/encoding/traditionalchinese/big5.go | 199 + .../encoding/traditionalchinese/tables.go | 37142 +++++++++++++ .../x/text/encoding/unicode/override.go | 82 + .../x/text/encoding/unicode/unicode.go | 434 + .../golang.org/x/text/internal/tag/tag.go | 100 + .../internal/utf8internal/utf8internal.go | 87 + .../golang.org/x/text/language/Makefile | 16 + .../golang.org/x/text/language/common.go | 16 + .../golang.org/x/text/language/coverage.go | 197 + .../vendor/golang.org/x/text/language/doc.go | 102 + .../golang.org/x/text/language/go1_1.go | 38 + .../golang.org/x/text/language/go1_2.go | 11 + .../golang.org/x/text/language/index.go | 783 + .../golang.org/x/text/language/language.go | 907 + .../golang.org/x/text/language/lookup.go | 396 + .../golang.org/x/text/language/match.go | 933 + .../golang.org/x/text/language/parse.go | 859 + .../golang.org/x/text/language/tables.go | 3686 ++ .../vendor/golang.org/x/text/language/tags.go | 143 + .../vendor/golang.org/x/text/runes/cond.go | 187 + .../vendor/golang.org/x/text/runes/runes.go | 355 + .../golang.org/x/text/transform/transform.go | 705 + .../Security/CWE-643/vendor/modules.txt | 44 +- 163 files changed, 188405 insertions(+), 2816 deletions(-) create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/README.md create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/marshal.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.gitignore create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.travis.yml create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/README.md create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/cache.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/query.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.gitignore create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.travis.yml create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/README.md create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/books.json create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/cache.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/node.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/query.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.gitignore create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.travis.yml create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/README.md create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/books.xml create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/cache.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/go.mod create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/node.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/parse.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/query.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.gitignore create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.travis.yml create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/README.md create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/build.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_go110.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_pre_go110.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/operator.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/parse.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/query.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/xpath.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/README.md create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/doc.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/parser.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/path.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/LICENSE create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/lru/lru.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/help/help.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/util/util.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/attribute.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/cdata.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/comment.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/document.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/element.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/fragment.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.c create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.h create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/node.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/nodeset.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/pi.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/text.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/expression.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/util.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/xpath.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/.travis.yml create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/README.md create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/doc.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/lexer.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/name.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/parser.go delete mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/stub.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/xpath.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/AUTHORS create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/CONTRIBUTORS create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/LICENSE create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/PATENTS create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/atom.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/table.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/charset/charset.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/const.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doc.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doctype.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/entity.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/escape.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/foreign.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/node.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/parse.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/render.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/token.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/AUTHORS create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/CONTRIBUTORS create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/LICENSE create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/PATENTS create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/charmap/charmap.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/charmap/tables.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/encoding.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/htmlindex/htmlindex.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/htmlindex/map.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/htmlindex/tables.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/internal/identifier/identifier.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/internal/identifier/mib.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/internal/internal.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/japanese/all.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/japanese/eucjp.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/japanese/iso2022jp.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/japanese/shiftjis.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/japanese/tables.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/korean/euckr.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/korean/tables.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/simplifiedchinese/all.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/simplifiedchinese/gbk.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/simplifiedchinese/hzgb2312.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/simplifiedchinese/tables.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/traditionalchinese/big5.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/traditionalchinese/tables.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/unicode/override.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/encoding/unicode/unicode.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/internal/tag/tag.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/internal/utf8internal/utf8internal.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/Makefile create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/common.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/coverage.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/doc.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/go1_1.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/go1_2.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/index.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/language.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/lookup.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/match.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/parse.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/tables.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/language/tags.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/runes/cond.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/runes/runes.go create mode 100644 ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/text/transform/transform.go diff --git a/ql/test/query-tests/Security/CWE-643/go.mod b/ql/test/query-tests/Security/CWE-643/go.mod index fc7016cc9..8db9a5a3f 100644 --- a/ql/test/query-tests/Security/CWE-643/go.mod +++ b/ql/test/query-tests/Security/CWE-643/go.mod @@ -6,9 +6,11 @@ require ( github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d github.com/antchfx/htmlquery v1.2.2 github.com/antchfx/jsonquery v1.1.2 - github.com/antchfx/xmlquery v1.2.3 - github.com/antchfx/xpath v1.1.5 + github.com/antchfx/xmlquery v1.3.1 + github.com/antchfx/xpath v1.1.10 github.com/go-xmlpath/xmlpath v0.0.0-20150820204837-860cbeca3ebc github.com/jbowtie/gokogiri v0.0.0-20190301021639-37f655d3078f github.com/santhosh-tekuri/xpathparser v1.0.0 + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/xmlpath.v2 v2.0.0-20150820204837-860cbeca3ebc // indirect ) diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml new file mode 100644 index 000000000..53c84e840 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml @@ -0,0 +1,16 @@ +language: go + +go: + - 1.6 + +before_install: + - go get -u github.com/ChrisTrenkamp/goxpath + - go get -u github.com/ChrisTrenkamp/goxpath/cmd/goxpath + - go get -u github.com/wadey/gocovmerge + +script: + - go list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}}' ./... | xargs -I {} bash -c {} + - gocovmerge `ls *.coverprofile` > coverage.txt + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/README.md b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/README.md new file mode 100644 index 000000000..deb49624a --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/README.md @@ -0,0 +1,2 @@ +# goxpath [![GoDoc](https://godoc.org/gopkg.in/src-d/go-git.v2?status.svg)](https://godoc.org/github.com/ChrisTrenkamp/goxpath) [![Build Status](https://travis-ci.org/ChrisTrenkamp/goxpath.svg?branch=master)](https://travis-ci.org/ChrisTrenkamp/goxpath) [![codecov.io](https://codecov.io/github/ChrisTrenkamp/goxpath/coverage.svg?branch=master)](https://codecov.io/github/ChrisTrenkamp/goxpath?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/ChrisTrenkamp/goxpath)](https://goreportcard.com/report/github.com/ChrisTrenkamp/goxpath) +An XPath 1.0 implementation written in Go. See the [wiki](https://github.com/ChrisTrenkamp/goxpath/wiki) for more information. diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh new file mode 100644 index 000000000..0e35d7de7 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh @@ -0,0 +1,17 @@ +#!/bin/bash +cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +go get github.com/ChrisTrenkamp/goxpath/cmd/goxpath +if [ $? != 0 ]; then + exit 1 +fi +go test >/dev/null 2>&1 +if [ $? != 0 ]; then + go test + exit 1 +fi +gometalinter --deadline=1m ./... +go list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}} >/dev/null' ./... | xargs -I {} bash -c {} 2>/dev/null +gocovmerge `ls *.coverprofile` > coverage.txt +go tool cover -html=coverage.txt -o coverage.html +firefox coverage.html +rm coverage.html coverage.txt *.coverprofile diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go new file mode 100644 index 000000000..189ebb9c2 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go @@ -0,0 +1,117 @@ +package goxpath + +import ( + "encoding/xml" + "fmt" + + "github.com/ChrisTrenkamp/goxpath/internal/execxp" + "github.com/ChrisTrenkamp/goxpath/parser" + "github.com/ChrisTrenkamp/goxpath/tree" +) + +//Opts defines namespace mappings and custom functions for XPath expressions. +type Opts struct { + NS map[string]string + Funcs map[xml.Name]tree.Wrap + Vars map[string]tree.Result +} + +//FuncOpts is a function wrapper for Opts. +type FuncOpts func(*Opts) + +//XPathExec is the XPath executor, compiled from an XPath string +type XPathExec struct { + n *parser.Node +} + +//Parse parses the XPath expression, xp, returning an XPath executor. +func Parse(xp string) (XPathExec, error) { + n, err := parser.Parse(xp) + return XPathExec{n: n}, err +} + +//MustParse is like Parse, but panics instead of returning an error. +func MustParse(xp string) XPathExec { + ret, err := Parse(xp) + if err != nil { + panic(err) + } + return ret +} + +//Exec executes the XPath expression, xp, against the tree, t, with the +//namespace mappings, ns, and returns the result as a stringer. +func (xp XPathExec) Exec(t tree.Node, opts ...FuncOpts) (tree.Result, error) { + o := &Opts{ + NS: make(map[string]string), + Funcs: make(map[xml.Name]tree.Wrap), + Vars: make(map[string]tree.Result), + } + for _, i := range opts { + i(o) + } + return execxp.Exec(xp.n, t, o.NS, o.Funcs, o.Vars) +} + +//ExecBool is like Exec, except it will attempt to convert the result to its boolean value. +func (xp XPathExec) ExecBool(t tree.Node, opts ...FuncOpts) (bool, error) { + res, err := xp.Exec(t, opts...) + if err != nil { + return false, err + } + + b, ok := res.(tree.IsBool) + if !ok { + return false, fmt.Errorf("Cannot convert result to a boolean") + } + + return bool(b.Bool()), nil +} + +//ExecNum is like Exec, except it will attempt to convert the result to its number value. +func (xp XPathExec) ExecNum(t tree.Node, opts ...FuncOpts) (float64, error) { + res, err := xp.Exec(t, opts...) + if err != nil { + return 0, err + } + + n, ok := res.(tree.IsNum) + if !ok { + return 0, fmt.Errorf("Cannot convert result to a number") + } + + return float64(n.Num()), nil +} + +//ExecNode is like Exec, except it will attempt to return the result as a node-set. +func (xp XPathExec) ExecNode(t tree.Node, opts ...FuncOpts) (tree.NodeSet, error) { + res, err := xp.Exec(t, opts...) + if err != nil { + return nil, err + } + + n, ok := res.(tree.NodeSet) + if !ok { + return nil, fmt.Errorf("Cannot convert result to a node-set") + } + + return n, nil +} + +//MustExec is like Exec, but panics instead of returning an error. +func (xp XPathExec) MustExec(t tree.Node, opts ...FuncOpts) tree.Result { + res, err := xp.Exec(t, opts...) + if err != nil { + panic(err) + } + return res +} + +//ParseExec parses the XPath string, xpstr, and runs Exec. +func ParseExec(xpstr string, t tree.Node, opts ...FuncOpts) (tree.Result, error) { + xp, err := Parse(xpstr) + if err != nil { + return nil, err + } + return xp.Exec(t, opts...) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go new file mode 100644 index 000000000..7b3251568 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go @@ -0,0 +1,27 @@ +package execxp + +import ( + "encoding/xml" + + "github.com/ChrisTrenkamp/goxpath/parser" + "github.com/ChrisTrenkamp/goxpath/tree" +) + +//Exec executes the XPath expression, xp, against the tree, t, with the +//namespace mappings, ns. +func Exec(n *parser.Node, t tree.Node, ns map[string]string, fns map[xml.Name]tree.Wrap, v map[string]tree.Result) (tree.Result, error) { + f := xpFilt{ + t: t, + ns: ns, + ctx: tree.NodeSet{t}, + fns: fns, + variables: v, + } + + return exec(&f, n) +} + +func exec(f *xpFilt, n *parser.Node) (tree.Result, error) { + err := xfExec(f, n) + return f.ctx, err +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go new file mode 100644 index 000000000..058f79a0b --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go @@ -0,0 +1,307 @@ +package findutil + +import ( + "encoding/xml" + + "github.com/ChrisTrenkamp/goxpath/parser/pathexpr" + "github.com/ChrisTrenkamp/goxpath/tree" + "github.com/ChrisTrenkamp/goxpath/xconst" +) + +const ( + wildcard = "*" +) + +type findFunc func(tree.Node, *pathexpr.PathExpr, *[]tree.Node) + +var findMap = map[string]findFunc{ + xconst.AxisAncestor: findAncestor, + xconst.AxisAncestorOrSelf: findAncestorOrSelf, + xconst.AxisAttribute: findAttribute, + xconst.AxisChild: findChild, + xconst.AxisDescendent: findDescendent, + xconst.AxisDescendentOrSelf: findDescendentOrSelf, + xconst.AxisFollowing: findFollowing, + xconst.AxisFollowingSibling: findFollowingSibling, + xconst.AxisNamespace: findNamespace, + xconst.AxisParent: findParent, + xconst.AxisPreceding: findPreceding, + xconst.AxisPrecedingSibling: findPrecedingSibling, + xconst.AxisSelf: findSelf, +} + +//Find finds nodes based on the pathexpr.PathExpr +func Find(x tree.Node, p pathexpr.PathExpr) []tree.Node { + ret := []tree.Node{} + + if p.Axis == "" { + findChild(x, &p, &ret) + return ret + } + + f := findMap[p.Axis] + f(x, &p, &ret) + + return ret +} + +func findAncestor(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if x.GetNodeType() == tree.NtRoot { + return + } + + addNode(x.GetParent(), p, ret) + findAncestor(x.GetParent(), p, ret) +} + +func findAncestorOrSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + findSelf(x, p, ret) + findAncestor(x, p, ret) +} + +func findAttribute(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if ele, ok := x.(tree.Elem); ok { + for _, i := range ele.GetAttrs() { + addNode(i, p, ret) + } + } +} + +func findChild(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if ele, ok := x.(tree.Elem); ok { + ch := ele.GetChildren() + for i := range ch { + addNode(ch[i], p, ret) + } + } +} + +func findDescendent(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if ele, ok := x.(tree.Elem); ok { + ch := ele.GetChildren() + for i := range ch { + addNode(ch[i], p, ret) + findDescendent(ch[i], p, ret) + } + } +} + +func findDescendentOrSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + findSelf(x, p, ret) + findDescendent(x, p, ret) +} + +func findFollowing(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if x.GetNodeType() == tree.NtRoot { + return + } + par := x.GetParent() + ch := par.GetChildren() + i := 0 + for x != ch[i] { + i++ + } + i++ + for i < len(ch) { + findDescendentOrSelf(ch[i], p, ret) + i++ + } + findFollowing(par, p, ret) +} + +func findFollowingSibling(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if x.GetNodeType() == tree.NtRoot { + return + } + par := x.GetParent() + ch := par.GetChildren() + i := 0 + for x != ch[i] { + i++ + } + i++ + for i < len(ch) { + findSelf(ch[i], p, ret) + i++ + } +} + +func findNamespace(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if ele, ok := x.(tree.NSElem); ok { + ns := tree.BuildNS(ele) + for _, i := range ns { + addNode(i, p, ret) + } + } +} + +func findParent(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if x.GetNodeType() != tree.NtRoot { + addNode(x.GetParent(), p, ret) + } +} + +func findPreceding(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if x.GetNodeType() == tree.NtRoot { + return + } + par := x.GetParent() + ch := par.GetChildren() + i := len(ch) - 1 + for x != ch[i] { + i-- + } + i-- + for i >= 0 { + findDescendentOrSelf(ch[i], p, ret) + i-- + } + findPreceding(par, p, ret) +} + +func findPrecedingSibling(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + if x.GetNodeType() == tree.NtRoot { + return + } + par := x.GetParent() + ch := par.GetChildren() + i := len(ch) - 1 + for x != ch[i] { + i-- + } + i-- + for i >= 0 { + findSelf(ch[i], p, ret) + i-- + } +} + +func findSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + addNode(x, p, ret) +} + +func addNode(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) { + add := false + tok := x.GetToken() + + switch x.GetNodeType() { + case tree.NtAttr: + add = evalAttr(p, tok.(xml.Attr)) + case tree.NtChd: + add = evalChd(p) + case tree.NtComm: + add = evalComm(p) + case tree.NtElem, tree.NtRoot: + add = evalEle(p, tok.(xml.StartElement)) + case tree.NtNs: + add = evalNS(p, tok.(xml.Attr)) + case tree.NtPi: + add = evalPI(p) + } + + if add { + *ret = append(*ret, x) + } +} + +func evalAttr(p *pathexpr.PathExpr, a xml.Attr) bool { + if p.NodeType == "" { + if p.Name.Space != wildcard { + if a.Name.Space != p.NS[p.Name.Space] { + return false + } + } + + if p.Name.Local == wildcard && p.Axis == xconst.AxisAttribute { + return true + } + + if p.Name.Local == a.Name.Local { + return true + } + } else { + if p.NodeType == xconst.NodeTypeNode { + return true + } + } + + return false +} + +func evalChd(p *pathexpr.PathExpr) bool { + if p.NodeType == xconst.NodeTypeText || p.NodeType == xconst.NodeTypeNode { + return true + } + + return false +} + +func evalComm(p *pathexpr.PathExpr) bool { + if p.NodeType == xconst.NodeTypeComment || p.NodeType == xconst.NodeTypeNode { + return true + } + + return false +} + +func evalEle(p *pathexpr.PathExpr, ele xml.StartElement) bool { + if p.NodeType == "" { + return checkNameAndSpace(p, ele) + } + + if p.NodeType == xconst.NodeTypeNode { + return true + } + + return false +} + +func checkNameAndSpace(p *pathexpr.PathExpr, ele xml.StartElement) bool { + if p.Name.Local == wildcard && p.Name.Space == "" { + return true + } + + if p.Name.Space != wildcard && ele.Name.Space != p.NS[p.Name.Space] { + return false + } + + if p.Name.Local == wildcard && p.Axis != xconst.AxisAttribute && p.Axis != xconst.AxisNamespace { + return true + } + + if p.Name.Local == ele.Name.Local { + return true + } + + return false +} + +func evalNS(p *pathexpr.PathExpr, ns xml.Attr) bool { + if p.NodeType == "" { + if p.Name.Space != "" && p.Name.Space != wildcard { + return false + } + + if p.Name.Local == wildcard && p.Axis == xconst.AxisNamespace { + return true + } + + if p.Name.Local == ns.Name.Local { + return true + } + } else { + if p.NodeType == xconst.NodeTypeNode { + return true + } + } + + return false +} + +func evalPI(p *pathexpr.PathExpr) bool { + if p.NodeType == xconst.NodeTypeProcInst || p.NodeType == xconst.NodeTypeNode { + return true + } + + return false +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go new file mode 100644 index 000000000..5480ebcc4 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go @@ -0,0 +1,74 @@ +package intfns + +import ( + "fmt" + + "github.com/ChrisTrenkamp/goxpath/tree" + "golang.org/x/text/language" +) + +func boolean(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + if b, ok := args[0].(tree.IsBool); ok { + return b.Bool(), nil + } + + return nil, fmt.Errorf("Cannot convert object to a boolean") +} + +func not(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + b, ok := args[0].(tree.IsBool) + if !ok { + return nil, fmt.Errorf("Cannot convert object to a boolean") + } + return !b.Bool(), nil +} + +func _true(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + return tree.Bool(true), nil +} + +func _false(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + return tree.Bool(false), nil +} + +func lang(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + lStr := args[0].String() + + var n tree.Elem + + for _, i := range c.NodeSet { + if i.GetNodeType() == tree.NtElem { + n = i.(tree.Elem) + } else { + n = i.GetParent() + } + + for n.GetNodeType() != tree.NtRoot { + if attr, ok := tree.GetAttribute(n, "lang", tree.XMLSpace); ok { + return checkLang(lStr, attr.Value), nil + } + n = n.GetParent() + } + } + + return tree.Bool(false), nil +} + +func checkLang(srcStr, targStr string) tree.Bool { + srcLang := language.Make(srcStr) + srcRegion, srcRegionConf := srcLang.Region() + + targLang := language.Make(targStr) + targRegion, targRegionConf := targLang.Region() + + if srcRegionConf == language.Exact && targRegionConf != language.Exact { + return tree.Bool(false) + } + + if srcRegion != targRegion && srcRegionConf == language.Exact && targRegionConf == language.Exact { + return tree.Bool(false) + } + + _, _, conf := language.NewMatcher([]language.Tag{srcLang}).Match(targLang) + return tree.Bool(conf >= language.High) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go new file mode 100644 index 000000000..8b09fa99f --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go @@ -0,0 +1,41 @@ +package intfns + +import ( + "encoding/xml" + + "github.com/ChrisTrenkamp/goxpath/tree" +) + +//BuiltIn contains the list of built-in XPath functions +var BuiltIn = map[xml.Name]tree.Wrap{ + //String functions + {Local: "string"}: {Fn: _string, NArgs: 1, LastArgOpt: tree.Optional}, + {Local: "concat"}: {Fn: concat, NArgs: 3, LastArgOpt: tree.Variadic}, + {Local: "starts-with"}: {Fn: startsWith, NArgs: 2}, + {Local: "contains"}: {Fn: contains, NArgs: 2}, + {Local: "substring-before"}: {Fn: substringBefore, NArgs: 2}, + {Local: "substring-after"}: {Fn: substringAfter, NArgs: 2}, + {Local: "substring"}: {Fn: substring, NArgs: 3, LastArgOpt: tree.Optional}, + {Local: "string-length"}: {Fn: stringLength, NArgs: 1, LastArgOpt: tree.Optional}, + {Local: "normalize-space"}: {Fn: normalizeSpace, NArgs: 1, LastArgOpt: tree.Optional}, + {Local: "translate"}: {Fn: translate, NArgs: 3}, + //Node set functions + {Local: "last"}: {Fn: last}, + {Local: "position"}: {Fn: position}, + {Local: "count"}: {Fn: count, NArgs: 1}, + {Local: "local-name"}: {Fn: localName, NArgs: 1, LastArgOpt: tree.Optional}, + {Local: "namespace-uri"}: {Fn: namespaceURI, NArgs: 1, LastArgOpt: tree.Optional}, + {Local: "name"}: {Fn: name, NArgs: 1, LastArgOpt: tree.Optional}, + //boolean functions + {Local: "boolean"}: {Fn: boolean, NArgs: 1}, + {Local: "not"}: {Fn: not, NArgs: 1}, + {Local: "true"}: {Fn: _true}, + {Local: "false"}: {Fn: _false}, + {Local: "lang"}: {Fn: lang, NArgs: 1}, + //number functions + {Local: "number"}: {Fn: number, NArgs: 1, LastArgOpt: tree.Optional}, + {Local: "sum"}: {Fn: sum, NArgs: 1}, + {Local: "floor"}: {Fn: floor, NArgs: 1}, + {Local: "ceiling"}: {Fn: ceiling, NArgs: 1}, + {Local: "round"}: {Fn: round, NArgs: 1}, +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go new file mode 100644 index 000000000..7286a3042 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go @@ -0,0 +1,131 @@ +package intfns + +import ( + "encoding/xml" + "fmt" + + "github.com/ChrisTrenkamp/goxpath/tree" +) + +func last(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + return tree.Num(c.Size), nil +} + +func position(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + return tree.Num(c.Pos), nil +} + +func count(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + n, ok := args[0].(tree.NodeSet) + if !ok { + return nil, fmt.Errorf("Cannot convert object to a node-set") + } + + return tree.Num(len(n)), nil +} + +func localName(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + var n tree.NodeSet + ok := true + if len(args) == 1 { + n, ok = args[0].(tree.NodeSet) + } else { + n = c.NodeSet + } + if !ok { + return nil, fmt.Errorf("Cannot convert object to a node-set") + } + + ret := "" + if len(n) == 0 { + return tree.String(ret), nil + } + node := n[0] + + tok := node.GetToken() + + switch node.GetNodeType() { + case tree.NtElem: + ret = tok.(xml.StartElement).Name.Local + case tree.NtAttr: + ret = tok.(xml.Attr).Name.Local + case tree.NtPi: + ret = tok.(xml.ProcInst).Target + } + + return tree.String(ret), nil +} + +func namespaceURI(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + var n tree.NodeSet + ok := true + if len(args) == 1 { + n, ok = args[0].(tree.NodeSet) + } else { + n = c.NodeSet + } + if !ok { + return nil, fmt.Errorf("Cannot convert object to a node-set") + } + + ret := "" + if len(n) == 0 { + return tree.String(ret), nil + } + node := n[0] + + tok := node.GetToken() + + switch node.GetNodeType() { + case tree.NtElem: + ret = tok.(xml.StartElement).Name.Space + case tree.NtAttr: + ret = tok.(xml.Attr).Name.Space + } + + return tree.String(ret), nil +} + +func name(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + var n tree.NodeSet + ok := true + if len(args) == 1 { + n, ok = args[0].(tree.NodeSet) + } else { + n = c.NodeSet + } + if !ok { + return nil, fmt.Errorf("Cannot convert object to a node-set") + } + + ret := "" + if len(n) == 0 { + return tree.String(ret), nil + } + node := n[0] + + switch node.GetNodeType() { + case tree.NtElem: + t := node.GetToken().(xml.StartElement) + space := "" + + if t.Name.Space != "" { + space = fmt.Sprintf("{%s}", t.Name.Space) + } + + ret = fmt.Sprintf("%s%s", space, t.Name.Local) + case tree.NtAttr: + t := node.GetToken().(xml.Attr) + space := "" + + if t.Name.Space != "" { + space = fmt.Sprintf("{%s}", t.Name.Space) + } + + ret = fmt.Sprintf("%s%s", space, t.Name.Local) + case tree.NtPi: + ret = fmt.Sprintf("%s", node.GetToken().(xml.ProcInst).Target) + } + + return tree.String(ret), nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go new file mode 100644 index 000000000..464403f96 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go @@ -0,0 +1,71 @@ +package intfns + +import ( + "fmt" + "math" + + "github.com/ChrisTrenkamp/goxpath/tree" +) + +func number(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + if b, ok := args[0].(tree.IsNum); ok { + return b.Num(), nil + } + + return nil, fmt.Errorf("Cannot convert object to a number") +} + +func sum(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + n, ok := args[0].(tree.NodeSet) + if !ok { + return nil, fmt.Errorf("Cannot convert object to a node-set") + } + + ret := 0.0 + for _, i := range n { + ret += float64(tree.GetNodeNum(i)) + } + + return tree.Num(ret), nil +} + +func floor(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + n, ok := args[0].(tree.IsNum) + if !ok { + return nil, fmt.Errorf("Cannot convert object to a number") + } + + return tree.Num(math.Floor(float64(n.Num()))), nil +} + +func ceiling(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + n, ok := args[0].(tree.IsNum) + if !ok { + return nil, fmt.Errorf("Cannot convert object to a number") + } + + return tree.Num(math.Ceil(float64(n.Num()))), nil +} + +func round(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + isn, ok := args[0].(tree.IsNum) + if !ok { + return nil, fmt.Errorf("Cannot convert object to a number") + } + + n := isn.Num() + + if math.IsNaN(float64(n)) || math.IsInf(float64(n), 0) { + return n, nil + } + + if n < -0.5 { + n = tree.Num(int(n - 0.5)) + } else if n > 0.5 { + n = tree.Num(int(n + 0.5)) + } else { + n = 0 + } + + return n, nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go new file mode 100644 index 000000000..4e6a73a09 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go @@ -0,0 +1,141 @@ +package intfns + +import ( + "math" + "regexp" + "strings" + + "github.com/ChrisTrenkamp/goxpath/tree" +) + +func _string(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + if len(args) == 1 { + return tree.String(args[0].String()), nil + } + + return tree.String(c.NodeSet.String()), nil +} + +func concat(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + ret := "" + + for _, i := range args { + ret += i.String() + } + + return tree.String(ret), nil +} + +func startsWith(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + return tree.Bool(strings.Index(args[0].String(), args[1].String()) == 0), nil +} + +func contains(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + return tree.Bool(strings.Contains(args[0].String(), args[1].String())), nil +} + +func substringBefore(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + ind := strings.Index(args[0].String(), args[1].String()) + if ind == -1 { + return tree.String(""), nil + } + + return tree.String(args[0].String()[:ind]), nil +} + +func substringAfter(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + ind := strings.Index(args[0].String(), args[1].String()) + if ind == -1 { + return tree.String(""), nil + } + + return tree.String(args[0].String()[ind+len(args[1].String()):]), nil +} + +func substring(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + str := args[0].String() + + bNum, bErr := round(c, args[1]) + if bErr != nil { + return nil, bErr + } + + b := bNum.(tree.Num).Num() + + if float64(b-1) >= float64(len(str)) || math.IsNaN(float64(b)) { + return tree.String(""), nil + } + + if len(args) == 2 { + if b <= 1 { + b = 1 + } + + return tree.String(str[int(b)-1:]), nil + } + + eNum, eErr := round(c, args[2]) + if eErr != nil { + return nil, eErr + } + + e := eNum.(tree.Num).Num() + + if e <= 0 || math.IsNaN(float64(e)) || (math.IsInf(float64(b), 0) && math.IsInf(float64(e), 0)) { + return tree.String(""), nil + } + + if b <= 1 { + e = b + e - 1 + b = 1 + } + + if float64(b+e-1) >= float64(len(str)) { + e = tree.Num(len(str)) - b + 1 + } + + return tree.String(str[int(b)-1 : int(b+e)-1]), nil +} + +func stringLength(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + var str string + if len(args) == 1 { + str = args[0].String() + } else { + str = c.NodeSet.String() + } + + return tree.Num(len(str)), nil +} + +var spaceTrim = regexp.MustCompile(`\s+`) + +func normalizeSpace(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + var str string + if len(args) == 1 { + str = args[0].String() + } else { + str = c.NodeSet.String() + } + + str = strings.TrimSpace(str) + + return tree.String(spaceTrim.ReplaceAllString(str, " ")), nil +} + +func translate(c tree.Ctx, args ...tree.Result) (tree.Result, error) { + ret := args[0].String() + src := args[1].String() + repl := args[2].String() + + for i := range src { + r := "" + if i < len(repl) { + r = string(repl[i]) + } + + ret = strings.Replace(ret, string(src[i]), r, -1) + } + + return tree.String(ret), nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go new file mode 100644 index 000000000..d41ba7fcc --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go @@ -0,0 +1,212 @@ +package execxp + +import ( + "fmt" + "math" + + "github.com/ChrisTrenkamp/goxpath/tree" +) + +func bothNodeOperator(left tree.NodeSet, right tree.NodeSet, f *xpFilt, op string) error { + var err error + for _, l := range left { + for _, r := range right { + lStr := l.ResValue() + rStr := r.ResValue() + + if eqOps[op] { + err = equalsOperator(tree.String(lStr), tree.String(rStr), f, op) + if err == nil && f.ctx.String() == tree.True { + return nil + } + } else { + err = numberOperator(tree.String(lStr), tree.String(rStr), f, op) + if err == nil && f.ctx.String() == tree.True { + return nil + } + } + } + } + + f.ctx = tree.Bool(false) + + return nil +} + +func leftNodeOperator(left tree.NodeSet, right tree.Result, f *xpFilt, op string) error { + var err error + for _, l := range left { + lStr := l.ResValue() + + if eqOps[op] { + err = equalsOperator(tree.String(lStr), right, f, op) + if err == nil && f.ctx.String() == tree.True { + return nil + } + } else { + err = numberOperator(tree.String(lStr), right, f, op) + if err == nil && f.ctx.String() == tree.True { + return nil + } + } + } + + f.ctx = tree.Bool(false) + + return nil +} + +func rightNodeOperator(left tree.Result, right tree.NodeSet, f *xpFilt, op string) error { + var err error + for _, r := range right { + rStr := r.ResValue() + + if eqOps[op] { + err = equalsOperator(left, tree.String(rStr), f, op) + if err == nil && f.ctx.String() == "true" { + return nil + } + } else { + err = numberOperator(left, tree.String(rStr), f, op) + if err == nil && f.ctx.String() == "true" { + return nil + } + } + } + + f.ctx = tree.Bool(false) + + return nil +} + +func equalsOperator(left, right tree.Result, f *xpFilt, op string) error { + _, lOK := left.(tree.Bool) + _, rOK := right.(tree.Bool) + + if lOK || rOK { + lTest, lt := left.(tree.IsBool) + rTest, rt := right.(tree.IsBool) + if !lt || !rt { + return fmt.Errorf("Cannot convert argument to boolean") + } + + if op == "=" { + f.ctx = tree.Bool(lTest.Bool() == rTest.Bool()) + } else { + f.ctx = tree.Bool(lTest.Bool() != rTest.Bool()) + } + + return nil + } + + _, lOK = left.(tree.Num) + _, rOK = right.(tree.Num) + if lOK || rOK { + return numberOperator(left, right, f, op) + } + + lStr := left.String() + rStr := right.String() + + if op == "=" { + f.ctx = tree.Bool(lStr == rStr) + } else { + f.ctx = tree.Bool(lStr != rStr) + } + + return nil +} + +func numberOperator(left, right tree.Result, f *xpFilt, op string) error { + lt, lOK := left.(tree.IsNum) + rt, rOK := right.(tree.IsNum) + if !lOK || !rOK { + return fmt.Errorf("Cannot convert data type to number") + } + + ln, rn := lt.Num(), rt.Num() + + switch op { + case "*": + f.ctx = ln * rn + case "div": + if rn != 0 { + f.ctx = ln / rn + } else { + if ln == 0 { + f.ctx = tree.Num(math.NaN()) + } else { + if math.Signbit(float64(ln)) == math.Signbit(float64(rn)) { + f.ctx = tree.Num(math.Inf(1)) + } else { + f.ctx = tree.Num(math.Inf(-1)) + } + } + } + case "mod": + f.ctx = tree.Num(int(ln) % int(rn)) + case "+": + f.ctx = ln + rn + case "-": + f.ctx = ln - rn + case "=": + f.ctx = tree.Bool(ln == rn) + case "!=": + f.ctx = tree.Bool(ln != rn) + case "<": + f.ctx = tree.Bool(ln < rn) + case "<=": + f.ctx = tree.Bool(ln <= rn) + case ">": + f.ctx = tree.Bool(ln > rn) + case ">=": + f.ctx = tree.Bool(ln >= rn) + } + + return nil +} + +func andOrOperator(left, right tree.Result, f *xpFilt, op string) error { + lt, lOK := left.(tree.IsBool) + rt, rOK := right.(tree.IsBool) + + if !lOK || !rOK { + return fmt.Errorf("Cannot convert argument to boolean") + } + + l, r := lt.Bool(), rt.Bool() + + if op == "and" { + f.ctx = l && r + } else { + f.ctx = l || r + } + + return nil +} + +func unionOperator(left, right tree.Result, f *xpFilt, op string) error { + lNode, lOK := left.(tree.NodeSet) + rNode, rOK := right.(tree.NodeSet) + + if !lOK || !rOK { + return fmt.Errorf("Cannot convert data type to node-set") + } + + uniq := make(map[int]tree.Node) + for _, i := range lNode { + uniq[i.Pos()] = i + } + for _, i := range rNode { + uniq[i.Pos()] = i + } + + res := make(tree.NodeSet, 0, len(uniq)) + for _, v := range uniq { + res = append(res, v) + } + + f.ctx = res + + return nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go new file mode 100644 index 000000000..5a78138ee --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go @@ -0,0 +1,396 @@ +package execxp + +import ( + "encoding/xml" + "fmt" + "strconv" + "strings" + + "github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil" + "github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns" + "github.com/ChrisTrenkamp/goxpath/internal/xsort" + "github.com/ChrisTrenkamp/goxpath/lexer" + "github.com/ChrisTrenkamp/goxpath/parser" + "github.com/ChrisTrenkamp/goxpath/parser/pathexpr" + "github.com/ChrisTrenkamp/goxpath/tree" + "github.com/ChrisTrenkamp/goxpath/xconst" +) + +type xpFilt struct { + t tree.Node + ctx tree.Result + expr pathexpr.PathExpr + ns map[string]string + ctxPos int + ctxSize int + proxPos map[int]int + fns map[xml.Name]tree.Wrap + variables map[string]tree.Result +} + +type xpExecFn func(*xpFilt, string) + +var xpFns = map[lexer.XItemType]xpExecFn{ + lexer.XItemAbsLocPath: xfAbsLocPath, + lexer.XItemAbbrAbsLocPath: xfAbbrAbsLocPath, + lexer.XItemRelLocPath: xfRelLocPath, + lexer.XItemAbbrRelLocPath: xfAbbrRelLocPath, + lexer.XItemAxis: xfAxis, + lexer.XItemAbbrAxis: xfAbbrAxis, + lexer.XItemNCName: xfNCName, + lexer.XItemQName: xfQName, + lexer.XItemNodeType: xfNodeType, + lexer.XItemProcLit: xfProcInstLit, + lexer.XItemStrLit: xfStrLit, + lexer.XItemNumLit: xfNumLit, +} + +func xfExec(f *xpFilt, n *parser.Node) (err error) { + for n != nil { + if fn, ok := xpFns[n.Val.Typ]; ok { + fn(f, n.Val.Val) + n = n.Left + } else if n.Val.Typ == lexer.XItemPredicate { + if err = xfPredicate(f, n.Left); err != nil { + return + } + + n = n.Right + } else if n.Val.Typ == lexer.XItemFunction { + if err = xfFunction(f, n); err != nil { + return + } + + n = n.Right + } else if n.Val.Typ == lexer.XItemOperator { + lf := xpFilt{ + t: f.t, + ns: f.ns, + ctx: f.ctx, + ctxPos: f.ctxPos, + ctxSize: f.ctxSize, + proxPos: f.proxPos, + fns: f.fns, + variables: f.variables, + } + left, err := exec(&lf, n.Left) + if err != nil { + return err + } + + rf := xpFilt{ + t: f.t, + ns: f.ns, + ctx: f.ctx, + fns: f.fns, + variables: f.variables, + } + right, err := exec(&rf, n.Right) + if err != nil { + return err + } + + return xfOperator(left, right, f, n.Val.Val) + } else if n.Val.Typ == lexer.XItemVariable { + if res, ok := f.variables[n.Val.Val]; ok { + f.ctx = res + return nil + } + return fmt.Errorf("Invalid variable '%s'", n.Val.Val) + } else if string(n.Val.Typ) == "" { + n = n.Left + //} else { + // return fmt.Errorf("Cannot process " + string(n.Val.Typ)) + } + } + + return +} + +func xfPredicate(f *xpFilt, n *parser.Node) (err error) { + res := f.ctx.(tree.NodeSet) + newRes := make(tree.NodeSet, 0, len(res)) + + for i := range res { + pf := xpFilt{ + t: f.t, + ns: f.ns, + ctxPos: i, + ctxSize: f.ctxSize, + ctx: tree.NodeSet{res[i]}, + fns: f.fns, + variables: f.variables, + } + + predRes, err := exec(&pf, n) + if err != nil { + return err + } + + ok, err := checkPredRes(predRes, f, res[i]) + if err != nil { + return err + } + + if ok { + newRes = append(newRes, res[i]) + } + } + + f.proxPos = make(map[int]int) + for pos, j := range newRes { + f.proxPos[j.Pos()] = pos + 1 + } + + f.ctx = newRes + f.ctxSize = len(newRes) + + return +} + +func checkPredRes(ret tree.Result, f *xpFilt, node tree.Node) (bool, error) { + if num, ok := ret.(tree.Num); ok { + if float64(f.proxPos[node.Pos()]) == float64(num) { + return true, nil + } + return false, nil + } + + if b, ok := ret.(tree.IsBool); ok { + return bool(b.Bool()), nil + } + + return false, fmt.Errorf("Cannot convert argument to boolean") +} + +func xfFunction(f *xpFilt, n *parser.Node) error { + spl := strings.Split(n.Val.Val, ":") + var name xml.Name + if len(spl) == 1 { + name.Local = spl[0] + } else { + name.Space = f.ns[spl[0]] + name.Local = spl[1] + } + fn, ok := intfns.BuiltIn[name] + if !ok { + fn, ok = f.fns[name] + } + + if ok { + args := []tree.Result{} + param := n.Left + + for param != nil { + pf := xpFilt{ + t: f.t, + ctx: f.ctx, + ns: f.ns, + ctxPos: f.ctxPos, + ctxSize: f.ctxSize, + fns: f.fns, + variables: f.variables, + } + res, err := exec(&pf, param.Left) + if err != nil { + return err + } + + args = append(args, res) + param = param.Right + } + + filt, err := fn.Call(tree.Ctx{NodeSet: f.ctx.(tree.NodeSet), Size: f.ctxSize, Pos: f.ctxPos + 1}, args...) + f.ctx = filt + return err + } + + return fmt.Errorf("Unknown function: %s", n.Val.Val) +} + +var eqOps = map[string]bool{ + "=": true, + "!=": true, +} + +var booleanOps = map[string]bool{ + "=": true, + "!=": true, + "<": true, + "<=": true, + ">": true, + ">=": true, +} + +var numOps = map[string]bool{ + "*": true, + "div": true, + "mod": true, + "+": true, + "-": true, + "=": true, + "!=": true, + "<": true, + "<=": true, + ">": true, + ">=": true, +} + +var andOrOps = map[string]bool{ + "and": true, + "or": true, +} + +func xfOperator(left, right tree.Result, f *xpFilt, op string) error { + if booleanOps[op] { + lNode, lOK := left.(tree.NodeSet) + rNode, rOK := right.(tree.NodeSet) + if lOK && rOK { + return bothNodeOperator(lNode, rNode, f, op) + } + + if lOK { + return leftNodeOperator(lNode, right, f, op) + } + + if rOK { + return rightNodeOperator(left, rNode, f, op) + } + + if eqOps[op] { + return equalsOperator(left, right, f, op) + } + } + + if numOps[op] { + return numberOperator(left, right, f, op) + } + + if andOrOps[op] { + return andOrOperator(left, right, f, op) + } + + //if op == "|" { + return unionOperator(left, right, f, op) + //} + + //return fmt.Errorf("Unknown operator " + op) +} + +func xfAbsLocPath(f *xpFilt, val string) { + i := f.t + for i.GetNodeType() != tree.NtRoot { + i = i.GetParent() + } + f.ctx = tree.NodeSet{i} +} + +func xfAbbrAbsLocPath(f *xpFilt, val string) { + i := f.t + for i.GetNodeType() != tree.NtRoot { + i = i.GetParent() + } + f.ctx = tree.NodeSet{i} + f.expr = abbrPathExpr() + find(f) +} + +func xfRelLocPath(f *xpFilt, val string) { +} + +func xfAbbrRelLocPath(f *xpFilt, val string) { + f.expr = abbrPathExpr() + find(f) +} + +func xfAxis(f *xpFilt, val string) { + f.expr.Axis = val +} + +func xfAbbrAxis(f *xpFilt, val string) { + f.expr.Axis = xconst.AxisAttribute +} + +func xfNCName(f *xpFilt, val string) { + f.expr.Name.Space = val +} + +func xfQName(f *xpFilt, val string) { + f.expr.Name.Local = val + find(f) +} + +func xfNodeType(f *xpFilt, val string) { + f.expr.NodeType = val + find(f) +} + +func xfProcInstLit(f *xpFilt, val string) { + filt := tree.NodeSet{} + for _, i := range f.ctx.(tree.NodeSet) { + if i.GetToken().(xml.ProcInst).Target == val { + filt = append(filt, i) + } + } + f.ctx = filt +} + +func xfStrLit(f *xpFilt, val string) { + f.ctx = tree.String(val) +} + +func xfNumLit(f *xpFilt, val string) { + num, _ := strconv.ParseFloat(val, 64) + f.ctx = tree.Num(num) +} + +func abbrPathExpr() pathexpr.PathExpr { + return pathexpr.PathExpr{ + Name: xml.Name{}, + Axis: xconst.AxisDescendentOrSelf, + NodeType: xconst.NodeTypeNode, + } +} + +func find(f *xpFilt) { + dupFilt := make(map[int]tree.Node) + f.proxPos = make(map[int]int) + + if f.expr.Axis == "" && f.expr.NodeType == "" && f.expr.Name.Space == "" { + if f.expr.Name.Local == "." { + f.expr = pathexpr.PathExpr{ + Name: xml.Name{}, + Axis: xconst.AxisSelf, + NodeType: xconst.NodeTypeNode, + } + } + + if f.expr.Name.Local == ".." { + f.expr = pathexpr.PathExpr{ + Name: xml.Name{}, + Axis: xconst.AxisParent, + NodeType: xconst.NodeTypeNode, + } + } + } + + f.expr.NS = f.ns + + for _, i := range f.ctx.(tree.NodeSet) { + for pos, j := range findutil.Find(i, f.expr) { + dupFilt[j.Pos()] = j + f.proxPos[j.Pos()] = pos + 1 + } + } + + res := make(tree.NodeSet, 0, len(dupFilt)) + for _, i := range dupFilt { + res = append(res, i) + } + + xsort.SortNodes(res) + + f.expr = pathexpr.PathExpr{} + f.ctxSize = len(res) + f.ctx = res +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go new file mode 100644 index 000000000..95f57c249 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go @@ -0,0 +1,20 @@ +package xsort + +import ( + "sort" + + "github.com/ChrisTrenkamp/goxpath/tree" +) + +type nodeSort []tree.Node + +func (ns nodeSort) Len() int { return len(ns) } +func (ns nodeSort) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] } +func (ns nodeSort) Less(i, j int) bool { + return ns[i].Pos() < ns[j].Pos() +} + +//SortNodes sorts the array by the node document order +func SortNodes(res []tree.Node) { + sort.Sort(nodeSort(res)) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go new file mode 100644 index 000000000..29f53c42a --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go @@ -0,0 +1,419 @@ +package lexer + +import ( + "fmt" + "strings" + "unicode" + "unicode/utf8" +) + +const ( + //XItemError is an error with the parser input + XItemError XItemType = "Error" + //XItemAbsLocPath is an absolute path + XItemAbsLocPath = "Absolute path" + //XItemAbbrAbsLocPath represents an abbreviated absolute path + XItemAbbrAbsLocPath = "Abbreviated absolute path" + //XItemAbbrRelLocPath marks the start of a path expression + XItemAbbrRelLocPath = "Abbreviated relative path" + //XItemRelLocPath represents a relative location path + XItemRelLocPath = "Relative path" + //XItemEndPath marks the end of a path + XItemEndPath = "End path instruction" + //XItemAxis marks an axis specifier of a path + XItemAxis = "Axis" + //XItemAbbrAxis marks an abbreviated axis specifier (just @ at this point) + XItemAbbrAxis = "Abbreviated attribute axis" + //XItemNCName marks a namespace name in a node test + XItemNCName = "Namespace" + //XItemQName marks the local name in an a node test + XItemQName = "Local name" + //XItemNodeType marks a node type in a node test + XItemNodeType = "Node type" + //XItemProcLit marks a processing-instruction literal + XItemProcLit = "processing-instruction" + //XItemFunction marks a function call + XItemFunction = "function" + //XItemArgument marks a function argument + XItemArgument = "function argument" + //XItemEndFunction marks the end of a function + XItemEndFunction = "end of function" + //XItemPredicate marks a predicate in an axis + XItemPredicate = "predicate" + //XItemEndPredicate marks a predicate in an axis + XItemEndPredicate = "end of predicate" + //XItemStrLit marks a string literal + XItemStrLit = "string literal" + //XItemNumLit marks a numeric literal + XItemNumLit = "numeric literal" + //XItemOperator marks an operator + XItemOperator = "operator" + //XItemVariable marks a variable reference + XItemVariable = "variable" +) + +const ( + eof = -(iota + 1) +) + +//XItemType is the parser token types +type XItemType string + +//XItem is the token emitted from the parser +type XItem struct { + Typ XItemType + Val string +} + +type stateFn func(*Lexer) stateFn + +//Lexer lexes out XPath expressions +type Lexer struct { + input string + start int + pos int + width int + items chan XItem +} + +//Lex an XPath expresion on the io.Reader +func Lex(xpath string) chan XItem { + l := &Lexer{ + input: xpath, + items: make(chan XItem), + } + go l.run() + return l.items +} + +func (l *Lexer) run() { + for state := startState; state != nil; { + state = state(l) + } + + if l.peek() != eof { + l.errorf("Malformed XPath expression") + } + + close(l.items) +} + +func (l *Lexer) emit(t XItemType) { + l.items <- XItem{t, l.input[l.start:l.pos]} + l.start = l.pos +} + +func (l *Lexer) emitVal(t XItemType, val string) { + l.items <- XItem{t, val} + l.start = l.pos +} + +func (l *Lexer) next() (r rune) { + if l.pos >= len(l.input) { + l.width = 0 + return eof + } + + r, l.width = utf8.DecodeRuneInString(l.input[l.pos:]) + + l.pos += l.width + + return r +} + +func (l *Lexer) ignore() { + l.start = l.pos +} + +func (l *Lexer) backup() { + l.pos -= l.width +} + +func (l *Lexer) peek() rune { + r := l.next() + + l.backup() + return r +} + +func (l *Lexer) peekAt(n int) rune { + if n <= 1 { + return l.peek() + } + + width := 0 + var ret rune + + for count := 0; count < n; count++ { + r, s := utf8.DecodeRuneInString(l.input[l.pos+width:]) + width += s + + if l.pos+width > len(l.input) { + return eof + } + + ret = r + } + + return ret +} + +func (l *Lexer) accept(valid string) bool { + if strings.ContainsRune(valid, l.next()) { + return true + } + + l.backup() + return false +} + +func (l *Lexer) acceptRun(valid string) { + for strings.ContainsRune(valid, l.next()) { + } + l.backup() +} + +func (l *Lexer) skip(num int) { + for i := 0; i < num; i++ { + l.next() + } + l.ignore() +} + +func (l *Lexer) skipWS(ig bool) { + for { + n := l.next() + + if n == eof || !unicode.IsSpace(n) { + break + } + } + + l.backup() + + if ig { + l.ignore() + } +} + +func (l *Lexer) errorf(format string, args ...interface{}) stateFn { + l.items <- XItem{ + XItemError, + fmt.Sprintf(format, args...), + } + + return nil +} + +func isElemChar(r rune) bool { + return string(r) != ":" && string(r) != "/" && + (unicode.Is(first, r) || unicode.Is(second, r) || string(r) == "*") && + r != eof +} + +func startState(l *Lexer) stateFn { + l.skipWS(true) + + if string(l.peek()) == "/" { + l.next() + l.ignore() + + if string(l.next()) == "/" { + l.ignore() + return abbrAbsLocPathState + } + + l.backup() + return absLocPathState + } else if string(l.peek()) == `'` || string(l.peek()) == `"` { + if err := getStrLit(l, XItemStrLit); err != nil { + return l.errorf(err.Error()) + } + + if l.peek() != eof { + return startState + } + } else if getNumLit(l) { + l.skipWS(true) + if l.peek() != eof { + return startState + } + } else if string(l.peek()) == "$" { + l.next() + l.ignore() + r := l.peek() + for unicode.Is(first, r) || unicode.Is(second, r) { + l.next() + r = l.peek() + } + tok := l.input[l.start:l.pos] + if len(tok) == 0 { + return l.errorf("Empty variable name") + } + l.emit(XItemVariable) + l.skipWS(true) + if l.peek() != eof { + return startState + } + } else if st := findOperatorState(l); st != nil { + return st + } else { + if isElemChar(l.peek()) { + colons := 0 + + for { + if isElemChar(l.peek()) { + l.next() + } else if string(l.peek()) == ":" { + l.next() + colons++ + } else { + break + } + } + + if string(l.peek()) == "(" && colons <= 1 { + tok := l.input[l.start:l.pos] + err := procFunc(l, tok) + if err != nil { + return l.errorf(err.Error()) + } + + l.skipWS(true) + + if string(l.peek()) == "/" { + l.next() + l.ignore() + + if string(l.next()) == "/" { + l.ignore() + return abbrRelLocPathState + } + + l.backup() + return relLocPathState + } + + return startState + } + + l.pos = l.start + return relLocPathState + } else if string(l.peek()) == "@" { + return relLocPathState + } + } + + return nil +} + +func strPeek(str string, l *Lexer) bool { + for i := 0; i < len(str); i++ { + if string(l.peekAt(i+1)) != string(str[i]) { + return false + } + } + return true +} + +func findOperatorState(l *Lexer) stateFn { + l.skipWS(true) + + switch string(l.peek()) { + case ">", "<", "!": + l.next() + if string(l.peek()) == "=" { + l.next() + } + l.emit(XItemOperator) + return startState + case "|", "+", "-", "*", "=": + l.next() + l.emit(XItemOperator) + return startState + case "(": + l.next() + l.emit(XItemOperator) + for state := startState; state != nil; { + state = state(l) + } + l.skipWS(true) + if string(l.next()) != ")" { + return l.errorf("Missing end )") + } + l.emit(XItemOperator) + return startState + } + + if strPeek("and", l) { + l.next() + l.next() + l.next() + l.emit(XItemOperator) + return startState + } + + if strPeek("or", l) { + l.next() + l.next() + l.emit(XItemOperator) + return startState + } + + if strPeek("mod", l) { + l.next() + l.next() + l.next() + l.emit(XItemOperator) + return startState + } + + if strPeek("div", l) { + l.next() + l.next() + l.next() + l.emit(XItemOperator) + return startState + } + + return nil +} + +func getStrLit(l *Lexer, tok XItemType) error { + q := l.next() + var r rune + + l.ignore() + + for r != q { + r = l.next() + if r == eof { + return fmt.Errorf("Unexpected end of string literal.") + } + } + + l.backup() + l.emit(tok) + l.next() + l.ignore() + + return nil +} + +func getNumLit(l *Lexer) bool { + const dig = "0123456789" + l.accept("-") + start := l.pos + l.acceptRun(dig) + + if l.pos == start { + return false + } + + if l.accept(".") { + l.acceptRun(dig) + } + + l.emit(XItemNumLit) + return true +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go new file mode 100644 index 000000000..dac30d6b6 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go @@ -0,0 +1,219 @@ +package lexer + +import ( + "fmt" + + "github.com/ChrisTrenkamp/goxpath/xconst" +) + +func absLocPathState(l *Lexer) stateFn { + l.emit(XItemAbsLocPath) + return stepState +} + +func abbrAbsLocPathState(l *Lexer) stateFn { + l.emit(XItemAbbrAbsLocPath) + return stepState +} + +func relLocPathState(l *Lexer) stateFn { + l.emit(XItemRelLocPath) + return stepState +} + +func abbrRelLocPathState(l *Lexer) stateFn { + l.emit(XItemAbbrRelLocPath) + return stepState +} + +func stepState(l *Lexer) stateFn { + l.skipWS(true) + r := l.next() + + for isElemChar(r) { + r = l.next() + } + + l.backup() + tok := l.input[l.start:l.pos] + + state, err := parseSeparators(l, tok) + if err != nil { + return l.errorf(err.Error()) + } + + return getNextPathState(l, state) +} + +func parseSeparators(l *Lexer, tok string) (XItemType, error) { + l.skipWS(false) + state := XItemType(XItemQName) + r := l.peek() + + if string(r) == ":" && string(l.peekAt(2)) == ":" { + var err error + if state, err = getAxis(l, tok); err != nil { + return state, fmt.Errorf(err.Error()) + } + } else if string(r) == ":" { + state = XItemNCName + l.emitVal(state, tok) + l.skip(1) + l.skipWS(true) + } else if string(r) == "@" { + state = XItemAbbrAxis + l.emitVal(state, tok) + l.skip(1) + l.skipWS(true) + } else if string(r) == "(" { + var err error + if state, err = getNT(l, tok); err != nil { + return state, fmt.Errorf(err.Error()) + } + } else if len(tok) > 0 { + l.emitVal(state, tok) + } + + return state, nil +} + +func getAxis(l *Lexer, tok string) (XItemType, error) { + var state XItemType + for i := range xconst.AxisNames { + if tok == xconst.AxisNames[i] { + state = XItemAxis + } + } + if state != XItemAxis { + return state, fmt.Errorf("Invalid Axis specifier, %s", tok) + } + l.emitVal(state, tok) + l.skip(2) + l.skipWS(true) + return state, nil +} + +func getNT(l *Lexer, tok string) (XItemType, error) { + isNT := false + for _, i := range xconst.NodeTypes { + if tok == i { + isNT = true + break + } + } + + if isNT { + return procNT(l, tok) + } + + return XItemError, fmt.Errorf("Invalid node-type " + tok) +} + +func procNT(l *Lexer, tok string) (XItemType, error) { + state := XItemType(XItemNodeType) + l.emitVal(state, tok) + l.skip(1) + l.skipWS(true) + n := l.peek() + if tok == xconst.NodeTypeProcInst && (string(n) == `"` || string(n) == `'`) { + if err := getStrLit(l, XItemProcLit); err != nil { + return state, fmt.Errorf(err.Error()) + } + l.skipWS(true) + n = l.next() + } + + if string(n) != ")" { + return state, fmt.Errorf("Missing ) at end of NodeType declaration.") + } + + l.skip(1) + return state, nil +} + +func procFunc(l *Lexer, tok string) error { + state := XItemType(XItemFunction) + l.emitVal(state, tok) + l.skip(1) + l.skipWS(true) + if string(l.peek()) != ")" { + l.emit(XItemArgument) + for { + for state := startState; state != nil; { + state = state(l) + } + l.skipWS(true) + + if string(l.peek()) == "," { + l.emit(XItemArgument) + l.skip(1) + } else if string(l.peek()) == ")" { + l.emit(XItemEndFunction) + l.skip(1) + break + } else if l.peek() == eof { + return fmt.Errorf("Missing ) at end of function declaration.") + } + } + } else { + l.emit(XItemEndFunction) + l.skip(1) + } + + return nil +} + +func getNextPathState(l *Lexer, state XItemType) stateFn { + isMultiPart := state == XItemAxis || state == XItemAbbrAxis || state == XItemNCName + + l.skipWS(true) + + for string(l.peek()) == "[" { + if err := getPred(l); err != nil { + return l.errorf(err.Error()) + } + } + + if string(l.peek()) == "/" && !isMultiPart { + l.skip(1) + if string(l.peek()) == "/" { + l.skip(1) + return abbrRelLocPathState + } + l.skipWS(true) + return relLocPathState + } else if isMultiPart && isElemChar(l.peek()) { + return stepState + } + + if isMultiPart { + return l.errorf("Step is not complete") + } + + l.emit(XItemEndPath) + return findOperatorState +} + +func getPred(l *Lexer) error { + l.emit(XItemPredicate) + l.skip(1) + l.skipWS(true) + + if string(l.peek()) == "]" { + return fmt.Errorf("Missing content in predicate.") + } + + for state := startState; state != nil; { + state = state(l) + } + + l.skipWS(true) + if string(l.peek()) != "]" { + return fmt.Errorf("Missing ] at end of predicate.") + } + l.skip(1) + l.emit(XItemEndPredicate) + l.skipWS(true) + + return nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go new file mode 100644 index 000000000..4e6bc8f67 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go @@ -0,0 +1,316 @@ +package lexer + +import "unicode" + +//first and second was copied from src/encoding/xml/xml.go +var first = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x003A, 0x003A, 1}, + {0x0041, 0x005A, 1}, + {0x005F, 0x005F, 1}, + {0x0061, 0x007A, 1}, + {0x00C0, 0x00D6, 1}, + {0x00D8, 0x00F6, 1}, + {0x00F8, 0x00FF, 1}, + {0x0100, 0x0131, 1}, + {0x0134, 0x013E, 1}, + {0x0141, 0x0148, 1}, + {0x014A, 0x017E, 1}, + {0x0180, 0x01C3, 1}, + {0x01CD, 0x01F0, 1}, + {0x01F4, 0x01F5, 1}, + {0x01FA, 0x0217, 1}, + {0x0250, 0x02A8, 1}, + {0x02BB, 0x02C1, 1}, + {0x0386, 0x0386, 1}, + {0x0388, 0x038A, 1}, + {0x038C, 0x038C, 1}, + {0x038E, 0x03A1, 1}, + {0x03A3, 0x03CE, 1}, + {0x03D0, 0x03D6, 1}, + {0x03DA, 0x03E0, 2}, + {0x03E2, 0x03F3, 1}, + {0x0401, 0x040C, 1}, + {0x040E, 0x044F, 1}, + {0x0451, 0x045C, 1}, + {0x045E, 0x0481, 1}, + {0x0490, 0x04C4, 1}, + {0x04C7, 0x04C8, 1}, + {0x04CB, 0x04CC, 1}, + {0x04D0, 0x04EB, 1}, + {0x04EE, 0x04F5, 1}, + {0x04F8, 0x04F9, 1}, + {0x0531, 0x0556, 1}, + {0x0559, 0x0559, 1}, + {0x0561, 0x0586, 1}, + {0x05D0, 0x05EA, 1}, + {0x05F0, 0x05F2, 1}, + {0x0621, 0x063A, 1}, + {0x0641, 0x064A, 1}, + {0x0671, 0x06B7, 1}, + {0x06BA, 0x06BE, 1}, + {0x06C0, 0x06CE, 1}, + {0x06D0, 0x06D3, 1}, + {0x06D5, 0x06D5, 1}, + {0x06E5, 0x06E6, 1}, + {0x0905, 0x0939, 1}, + {0x093D, 0x093D, 1}, + {0x0958, 0x0961, 1}, + {0x0985, 0x098C, 1}, + {0x098F, 0x0990, 1}, + {0x0993, 0x09A8, 1}, + {0x09AA, 0x09B0, 1}, + {0x09B2, 0x09B2, 1}, + {0x09B6, 0x09B9, 1}, + {0x09DC, 0x09DD, 1}, + {0x09DF, 0x09E1, 1}, + {0x09F0, 0x09F1, 1}, + {0x0A05, 0x0A0A, 1}, + {0x0A0F, 0x0A10, 1}, + {0x0A13, 0x0A28, 1}, + {0x0A2A, 0x0A30, 1}, + {0x0A32, 0x0A33, 1}, + {0x0A35, 0x0A36, 1}, + {0x0A38, 0x0A39, 1}, + {0x0A59, 0x0A5C, 1}, + {0x0A5E, 0x0A5E, 1}, + {0x0A72, 0x0A74, 1}, + {0x0A85, 0x0A8B, 1}, + {0x0A8D, 0x0A8D, 1}, + {0x0A8F, 0x0A91, 1}, + {0x0A93, 0x0AA8, 1}, + {0x0AAA, 0x0AB0, 1}, + {0x0AB2, 0x0AB3, 1}, + {0x0AB5, 0x0AB9, 1}, + {0x0ABD, 0x0AE0, 0x23}, + {0x0B05, 0x0B0C, 1}, + {0x0B0F, 0x0B10, 1}, + {0x0B13, 0x0B28, 1}, + {0x0B2A, 0x0B30, 1}, + {0x0B32, 0x0B33, 1}, + {0x0B36, 0x0B39, 1}, + {0x0B3D, 0x0B3D, 1}, + {0x0B5C, 0x0B5D, 1}, + {0x0B5F, 0x0B61, 1}, + {0x0B85, 0x0B8A, 1}, + {0x0B8E, 0x0B90, 1}, + {0x0B92, 0x0B95, 1}, + {0x0B99, 0x0B9A, 1}, + {0x0B9C, 0x0B9C, 1}, + {0x0B9E, 0x0B9F, 1}, + {0x0BA3, 0x0BA4, 1}, + {0x0BA8, 0x0BAA, 1}, + {0x0BAE, 0x0BB5, 1}, + {0x0BB7, 0x0BB9, 1}, + {0x0C05, 0x0C0C, 1}, + {0x0C0E, 0x0C10, 1}, + {0x0C12, 0x0C28, 1}, + {0x0C2A, 0x0C33, 1}, + {0x0C35, 0x0C39, 1}, + {0x0C60, 0x0C61, 1}, + {0x0C85, 0x0C8C, 1}, + {0x0C8E, 0x0C90, 1}, + {0x0C92, 0x0CA8, 1}, + {0x0CAA, 0x0CB3, 1}, + {0x0CB5, 0x0CB9, 1}, + {0x0CDE, 0x0CDE, 1}, + {0x0CE0, 0x0CE1, 1}, + {0x0D05, 0x0D0C, 1}, + {0x0D0E, 0x0D10, 1}, + {0x0D12, 0x0D28, 1}, + {0x0D2A, 0x0D39, 1}, + {0x0D60, 0x0D61, 1}, + {0x0E01, 0x0E2E, 1}, + {0x0E30, 0x0E30, 1}, + {0x0E32, 0x0E33, 1}, + {0x0E40, 0x0E45, 1}, + {0x0E81, 0x0E82, 1}, + {0x0E84, 0x0E84, 1}, + {0x0E87, 0x0E88, 1}, + {0x0E8A, 0x0E8D, 3}, + {0x0E94, 0x0E97, 1}, + {0x0E99, 0x0E9F, 1}, + {0x0EA1, 0x0EA3, 1}, + {0x0EA5, 0x0EA7, 2}, + {0x0EAA, 0x0EAB, 1}, + {0x0EAD, 0x0EAE, 1}, + {0x0EB0, 0x0EB0, 1}, + {0x0EB2, 0x0EB3, 1}, + {0x0EBD, 0x0EBD, 1}, + {0x0EC0, 0x0EC4, 1}, + {0x0F40, 0x0F47, 1}, + {0x0F49, 0x0F69, 1}, + {0x10A0, 0x10C5, 1}, + {0x10D0, 0x10F6, 1}, + {0x1100, 0x1100, 1}, + {0x1102, 0x1103, 1}, + {0x1105, 0x1107, 1}, + {0x1109, 0x1109, 1}, + {0x110B, 0x110C, 1}, + {0x110E, 0x1112, 1}, + {0x113C, 0x1140, 2}, + {0x114C, 0x1150, 2}, + {0x1154, 0x1155, 1}, + {0x1159, 0x1159, 1}, + {0x115F, 0x1161, 1}, + {0x1163, 0x1169, 2}, + {0x116D, 0x116E, 1}, + {0x1172, 0x1173, 1}, + {0x1175, 0x119E, 0x119E - 0x1175}, + {0x11A8, 0x11AB, 0x11AB - 0x11A8}, + {0x11AE, 0x11AF, 1}, + {0x11B7, 0x11B8, 1}, + {0x11BA, 0x11BA, 1}, + {0x11BC, 0x11C2, 1}, + {0x11EB, 0x11F0, 0x11F0 - 0x11EB}, + {0x11F9, 0x11F9, 1}, + {0x1E00, 0x1E9B, 1}, + {0x1EA0, 0x1EF9, 1}, + {0x1F00, 0x1F15, 1}, + {0x1F18, 0x1F1D, 1}, + {0x1F20, 0x1F45, 1}, + {0x1F48, 0x1F4D, 1}, + {0x1F50, 0x1F57, 1}, + {0x1F59, 0x1F5B, 0x1F5B - 0x1F59}, + {0x1F5D, 0x1F5D, 1}, + {0x1F5F, 0x1F7D, 1}, + {0x1F80, 0x1FB4, 1}, + {0x1FB6, 0x1FBC, 1}, + {0x1FBE, 0x1FBE, 1}, + {0x1FC2, 0x1FC4, 1}, + {0x1FC6, 0x1FCC, 1}, + {0x1FD0, 0x1FD3, 1}, + {0x1FD6, 0x1FDB, 1}, + {0x1FE0, 0x1FEC, 1}, + {0x1FF2, 0x1FF4, 1}, + {0x1FF6, 0x1FFC, 1}, + {0x2126, 0x2126, 1}, + {0x212A, 0x212B, 1}, + {0x212E, 0x212E, 1}, + {0x2180, 0x2182, 1}, + {0x3007, 0x3007, 1}, + {0x3021, 0x3029, 1}, + {0x3041, 0x3094, 1}, + {0x30A1, 0x30FA, 1}, + {0x3105, 0x312C, 1}, + {0x4E00, 0x9FA5, 1}, + {0xAC00, 0xD7A3, 1}, + }, +} + +var second = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x002D, 0x002E, 1}, + {0x0030, 0x0039, 1}, + {0x00B7, 0x00B7, 1}, + {0x02D0, 0x02D1, 1}, + {0x0300, 0x0345, 1}, + {0x0360, 0x0361, 1}, + {0x0387, 0x0387, 1}, + {0x0483, 0x0486, 1}, + {0x0591, 0x05A1, 1}, + {0x05A3, 0x05B9, 1}, + {0x05BB, 0x05BD, 1}, + {0x05BF, 0x05BF, 1}, + {0x05C1, 0x05C2, 1}, + {0x05C4, 0x0640, 0x0640 - 0x05C4}, + {0x064B, 0x0652, 1}, + {0x0660, 0x0669, 1}, + {0x0670, 0x0670, 1}, + {0x06D6, 0x06DC, 1}, + {0x06DD, 0x06DF, 1}, + {0x06E0, 0x06E4, 1}, + {0x06E7, 0x06E8, 1}, + {0x06EA, 0x06ED, 1}, + {0x06F0, 0x06F9, 1}, + {0x0901, 0x0903, 1}, + {0x093C, 0x093C, 1}, + {0x093E, 0x094C, 1}, + {0x094D, 0x094D, 1}, + {0x0951, 0x0954, 1}, + {0x0962, 0x0963, 1}, + {0x0966, 0x096F, 1}, + {0x0981, 0x0983, 1}, + {0x09BC, 0x09BC, 1}, + {0x09BE, 0x09BF, 1}, + {0x09C0, 0x09C4, 1}, + {0x09C7, 0x09C8, 1}, + {0x09CB, 0x09CD, 1}, + {0x09D7, 0x09D7, 1}, + {0x09E2, 0x09E3, 1}, + {0x09E6, 0x09EF, 1}, + {0x0A02, 0x0A3C, 0x3A}, + {0x0A3E, 0x0A3F, 1}, + {0x0A40, 0x0A42, 1}, + {0x0A47, 0x0A48, 1}, + {0x0A4B, 0x0A4D, 1}, + {0x0A66, 0x0A6F, 1}, + {0x0A70, 0x0A71, 1}, + {0x0A81, 0x0A83, 1}, + {0x0ABC, 0x0ABC, 1}, + {0x0ABE, 0x0AC5, 1}, + {0x0AC7, 0x0AC9, 1}, + {0x0ACB, 0x0ACD, 1}, + {0x0AE6, 0x0AEF, 1}, + {0x0B01, 0x0B03, 1}, + {0x0B3C, 0x0B3C, 1}, + {0x0B3E, 0x0B43, 1}, + {0x0B47, 0x0B48, 1}, + {0x0B4B, 0x0B4D, 1}, + {0x0B56, 0x0B57, 1}, + {0x0B66, 0x0B6F, 1}, + {0x0B82, 0x0B83, 1}, + {0x0BBE, 0x0BC2, 1}, + {0x0BC6, 0x0BC8, 1}, + {0x0BCA, 0x0BCD, 1}, + {0x0BD7, 0x0BD7, 1}, + {0x0BE7, 0x0BEF, 1}, + {0x0C01, 0x0C03, 1}, + {0x0C3E, 0x0C44, 1}, + {0x0C46, 0x0C48, 1}, + {0x0C4A, 0x0C4D, 1}, + {0x0C55, 0x0C56, 1}, + {0x0C66, 0x0C6F, 1}, + {0x0C82, 0x0C83, 1}, + {0x0CBE, 0x0CC4, 1}, + {0x0CC6, 0x0CC8, 1}, + {0x0CCA, 0x0CCD, 1}, + {0x0CD5, 0x0CD6, 1}, + {0x0CE6, 0x0CEF, 1}, + {0x0D02, 0x0D03, 1}, + {0x0D3E, 0x0D43, 1}, + {0x0D46, 0x0D48, 1}, + {0x0D4A, 0x0D4D, 1}, + {0x0D57, 0x0D57, 1}, + {0x0D66, 0x0D6F, 1}, + {0x0E31, 0x0E31, 1}, + {0x0E34, 0x0E3A, 1}, + {0x0E46, 0x0E46, 1}, + {0x0E47, 0x0E4E, 1}, + {0x0E50, 0x0E59, 1}, + {0x0EB1, 0x0EB1, 1}, + {0x0EB4, 0x0EB9, 1}, + {0x0EBB, 0x0EBC, 1}, + {0x0EC6, 0x0EC6, 1}, + {0x0EC8, 0x0ECD, 1}, + {0x0ED0, 0x0ED9, 1}, + {0x0F18, 0x0F19, 1}, + {0x0F20, 0x0F29, 1}, + {0x0F35, 0x0F39, 2}, + {0x0F3E, 0x0F3F, 1}, + {0x0F71, 0x0F84, 1}, + {0x0F86, 0x0F8B, 1}, + {0x0F90, 0x0F95, 1}, + {0x0F97, 0x0F97, 1}, + {0x0F99, 0x0FAD, 1}, + {0x0FB1, 0x0FB7, 1}, + {0x0FB9, 0x0FB9, 1}, + {0x20D0, 0x20DC, 1}, + {0x20E1, 0x3005, 0x3005 - 0x20E1}, + {0x302A, 0x302F, 1}, + {0x3031, 0x3035, 1}, + {0x3099, 0x309A, 1}, + {0x309D, 0x309E, 1}, + {0x30FC, 0x30FE, 1}, + }, +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/marshal.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/marshal.go new file mode 100644 index 000000000..e1045f20e --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/marshal.go @@ -0,0 +1,105 @@ +package goxpath + +import ( + "bytes" + "encoding/xml" + "io" + + "github.com/ChrisTrenkamp/goxpath/tree" +) + +//Marshal prints the result tree, r, in XML form to w. +func Marshal(n tree.Node, w io.Writer) error { + return marshal(n, w) +} + +//MarshalStr is like Marhal, but returns a string. +func MarshalStr(n tree.Node) (string, error) { + ret := bytes.NewBufferString("") + err := marshal(n, ret) + + return ret.String(), err +} + +func marshal(n tree.Node, w io.Writer) error { + e := xml.NewEncoder(w) + err := encTok(n, e) + if err != nil { + return err + } + + return e.Flush() +} + +func encTok(n tree.Node, e *xml.Encoder) error { + switch n.GetNodeType() { + case tree.NtAttr: + return encAttr(n.GetToken().(xml.Attr), e) + case tree.NtElem: + return encEle(n.(tree.Elem), e) + case tree.NtNs: + return encNS(n.GetToken().(xml.Attr), e) + case tree.NtRoot: + for _, i := range n.(tree.Elem).GetChildren() { + err := encTok(i, e) + if err != nil { + return err + } + } + return nil + } + + //case tree.NtChd, tree.NtComm, tree.NtPi: + return e.EncodeToken(n.GetToken()) +} + +func encAttr(a xml.Attr, e *xml.Encoder) error { + str := a.Name.Local + `="` + a.Value + `"` + + if a.Name.Space != "" { + str += ` xmlns="` + a.Name.Space + `"` + } + + pi := xml.ProcInst{ + Target: "attribute", + Inst: ([]byte)(str), + } + + return e.EncodeToken(pi) +} + +func encNS(ns xml.Attr, e *xml.Encoder) error { + pi := xml.ProcInst{ + Target: "namespace", + Inst: ([]byte)(ns.Value), + } + return e.EncodeToken(pi) +} + +func encEle(n tree.Elem, e *xml.Encoder) error { + ele := xml.StartElement{ + Name: n.GetToken().(xml.StartElement).Name, + } + + attrs := n.GetAttrs() + ele.Attr = make([]xml.Attr, len(attrs)) + for i := range attrs { + ele.Attr[i] = attrs[i].GetToken().(xml.Attr) + } + + err := e.EncodeToken(ele) + if err != nil { + return err + } + + if x, ok := n.(tree.Elem); ok { + for _, i := range x.GetChildren() { + err := encTok(i, e) + if err != nil { + return err + } + } + } + + return e.EncodeToken(ele.End()) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go new file mode 100644 index 000000000..08196c62e --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go @@ -0,0 +1,113 @@ +package parser + +import "github.com/ChrisTrenkamp/goxpath/lexer" + +//NodeType enumerations +const ( + Empty lexer.XItemType = "" +) + +//Node builds an AST tree for operating on XPath expressions +type Node struct { + Val lexer.XItem + Left *Node + Right *Node + Parent *Node + next *Node +} + +var beginPathType = map[lexer.XItemType]bool{ + lexer.XItemAbsLocPath: true, + lexer.XItemAbbrAbsLocPath: true, + lexer.XItemAbbrRelLocPath: true, + lexer.XItemRelLocPath: true, + lexer.XItemFunction: true, +} + +func (n *Node) add(i lexer.XItem) { + if n.Val.Typ == Empty { + n.Val = i + } else if n.Left == nil && n.Right == nil { + n.Left = &Node{Val: n.Val, Parent: n} + n.Val = i + } else if beginPathType[n.Val.Typ] { + next := &Node{Val: n.Val, Left: n.Left, Right: n.Right, Parent: n} + n.Left, n.Right = next, nil + n.Val = i + } else if n.Right == nil { + n.Right = &Node{Val: i, Parent: n} + } else { + next := &Node{Val: n.Val, Left: n.Left, Right: n.Right, Parent: n} + n.Left, n.Right = next, nil + n.Val = i + } + n.next = n +} + +func (n *Node) push(i lexer.XItem) { + if n.Left == nil { + n.Left = &Node{Val: i, Parent: n} + n.next = n.Left + } else if n.Right == nil { + n.Right = &Node{Val: i, Parent: n} + n.next = n.Right + } else { + next := &Node{Val: i, Left: n.Right, Parent: n} + n.Right = next + n.next = n.Right + } +} + +func (n *Node) pushNotEmpty(i lexer.XItem) { + if n.Val.Typ == Empty { + n.add(i) + } else { + n.push(i) + } +} + +/* +func (n *Node) prettyPrint(depth, width int) { + nodes := []*Node{} + n.getLine(depth, &nodes) + fmt.Printf("%*s", (width-depth)*2, "") + toggle := true + if len(nodes) > 1 { + for _, i := range nodes { + if i != nil { + if toggle { + fmt.Print("/ ") + } else { + fmt.Print("\\ ") + } + } + toggle = !toggle + } + fmt.Println() + fmt.Printf("%*s", (width-depth)*2, "") + } + for _, i := range nodes { + if i != nil { + fmt.Print(i.Val.Val, " ") + } + } + fmt.Println() +} + +func (n *Node) getLine(depth int, ret *[]*Node) { + if depth <= 0 && n != nil { + *ret = append(*ret, n) + return + } + if n.Left != nil { + n.Left.getLine(depth-1, ret) + } else if depth-1 <= 0 { + *ret = append(*ret, nil) + } + if n.Right != nil { + n.Right.getLine(depth-1, ret) + } else if depth-1 <= 0 { + *ret = append(*ret, nil) + } +} +*/ diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go new file mode 100644 index 000000000..e5ce8222f --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go @@ -0,0 +1,200 @@ +package parser + +import ( + "fmt" + + "github.com/ChrisTrenkamp/goxpath/lexer" +) + +type stateType int + +const ( + defState stateType = iota + xpathState + funcState + paramState + predState + parenState +) + +type parseStack struct { + stack []*Node + stateTypes []stateType + cur *Node +} + +func (p *parseStack) push(t stateType) { + p.stack = append(p.stack, p.cur) + p.stateTypes = append(p.stateTypes, t) +} + +func (p *parseStack) pop() { + stackPos := len(p.stack) - 1 + + p.cur = p.stack[stackPos] + p.stack = p.stack[:stackPos] + p.stateTypes = p.stateTypes[:stackPos] +} + +func (p *parseStack) curState() stateType { + if len(p.stateTypes) == 0 { + return defState + } + return p.stateTypes[len(p.stateTypes)-1] +} + +type lexFn func(*parseStack, lexer.XItem) + +var parseMap = map[lexer.XItemType]lexFn{ + lexer.XItemAbsLocPath: xiXPath, + lexer.XItemAbbrAbsLocPath: xiXPath, + lexer.XItemAbbrRelLocPath: xiXPath, + lexer.XItemRelLocPath: xiXPath, + lexer.XItemEndPath: xiEndPath, + lexer.XItemAxis: xiXPath, + lexer.XItemAbbrAxis: xiXPath, + lexer.XItemNCName: xiXPath, + lexer.XItemQName: xiXPath, + lexer.XItemNodeType: xiXPath, + lexer.XItemProcLit: xiXPath, + lexer.XItemFunction: xiFunc, + lexer.XItemArgument: xiFuncArg, + lexer.XItemEndFunction: xiEndFunc, + lexer.XItemPredicate: xiPred, + lexer.XItemEndPredicate: xiEndPred, + lexer.XItemStrLit: xiValue, + lexer.XItemNumLit: xiValue, + lexer.XItemOperator: xiOp, + lexer.XItemVariable: xiValue, +} + +var opPrecedence = map[string]int{ + "|": 1, + "*": 2, + "div": 2, + "mod": 2, + "+": 3, + "-": 3, + "=": 4, + "!=": 4, + "<": 4, + "<=": 4, + ">": 4, + ">=": 4, + "and": 5, + "or": 6, +} + +//Parse creates an AST tree for XPath expressions. +func Parse(xp string) (*Node, error) { + var err error + c := lexer.Lex(xp) + n := &Node{} + p := &parseStack{cur: n} + + for next := range c { + if next.Typ != lexer.XItemError { + parseMap[next.Typ](p, next) + } else if err == nil { + err = fmt.Errorf(next.Val) + } + } + + return n, err +} + +func xiXPath(p *parseStack, i lexer.XItem) { + if p.curState() == xpathState { + p.cur.push(i) + p.cur = p.cur.next + return + } + + if p.cur.Val.Typ == lexer.XItemFunction { + p.cur.Right = &Node{Val: i, Parent: p.cur} + p.cur.next = p.cur.Right + p.push(xpathState) + p.cur = p.cur.next + return + } + + p.cur.pushNotEmpty(i) + p.push(xpathState) + p.cur = p.cur.next +} + +func xiEndPath(p *parseStack, i lexer.XItem) { + p.pop() +} + +func xiFunc(p *parseStack, i lexer.XItem) { + if p.cur.Val.Typ == Empty { + p.cur.pushNotEmpty(i) + p.push(funcState) + p.cur = p.cur.next + return + } + p.cur.push(i) + p.cur = p.cur.next + p.push(funcState) +} + +func xiFuncArg(p *parseStack, i lexer.XItem) { + if p.curState() != funcState { + p.pop() + } + + p.cur.push(i) + p.cur = p.cur.next + p.push(paramState) + p.cur.push(lexer.XItem{Typ: Empty, Val: ""}) + p.cur = p.cur.next +} + +func xiEndFunc(p *parseStack, i lexer.XItem) { + if p.curState() == paramState { + p.pop() + } + p.pop() +} + +func xiPred(p *parseStack, i lexer.XItem) { + p.cur.push(i) + p.cur = p.cur.next + p.push(predState) + p.cur.push(lexer.XItem{Typ: Empty, Val: ""}) + p.cur = p.cur.next +} + +func xiEndPred(p *parseStack, i lexer.XItem) { + p.pop() +} + +func xiValue(p *parseStack, i lexer.XItem) { + p.cur.add(i) +} + +func xiOp(p *parseStack, i lexer.XItem) { + if i.Val == "(" { + p.cur.push(lexer.XItem{Typ: Empty, Val: ""}) + p.push(parenState) + p.cur = p.cur.next + return + } + + if i.Val == ")" { + p.pop() + return + } + + if p.cur.Val.Typ == lexer.XItemOperator { + if opPrecedence[p.cur.Val.Val] <= opPrecedence[i.Val] { + p.cur.add(i) + } else { + p.cur.push(i) + } + } else { + p.cur.add(i) + } + p.cur = p.cur.next +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go new file mode 100644 index 000000000..7fe69eb4a --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go @@ -0,0 +1,11 @@ +package pathexpr + +import "encoding/xml" + +//PathExpr represents XPath step's. xmltree.XMLTree uses it to find nodes. +type PathExpr struct { + Name xml.Name + Axis string + NodeType string + NS map[string]string +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/stub.go deleted file mode 100644 index 4b1e74cc1..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/stub.go +++ /dev/null @@ -1,54 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/ChrisTrenkamp/goxpath, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/ChrisTrenkamp/goxpath (exports: Opts,FuncOpts,XPathExec; functions: Parse,MustParse,ParseExec) - -// Package goxpath is a stub of github.com/ChrisTrenkamp/goxpath, generated by depstubber. -package goxpath - -import ( - xml "encoding/xml" -) - -type FuncOpts func(*Opts) - -func MustParse(_ string) XPathExec { - return XPathExec{} -} - -type Opts struct { - NS map[string]string - Funcs map[xml.Name]interface{} - Vars map[string]interface{} -} - -func Parse(_ string) (XPathExec, error) { - return XPathExec{}, nil -} - -func ParseExec(_ string, _ interface{}, _ ...FuncOpts) (interface{}, error) { - return nil, nil -} - -type XPathExec struct{} - -func (_ XPathExec) Exec(_ interface{}, _ ...FuncOpts) (interface{}, error) { - return nil, nil -} - -func (_ XPathExec) ExecBool(_ interface{}, _ ...FuncOpts) (bool, error) { - return false, nil -} - -func (_ XPathExec) ExecNode(_ interface{}, _ ...FuncOpts) (interface{}, error) { - return nil, nil -} - -func (_ XPathExec) ExecNum(_ interface{}, _ ...FuncOpts) (float64, error) { - return 0, nil -} - -func (_ XPathExec) MustExec(_ interface{}, _ ...FuncOpts) interface{} { - return nil -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go new file mode 100644 index 000000000..a6e642573 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go @@ -0,0 +1,18 @@ +package tree + +import "fmt" + +//Result is used for all data types. +type Result interface { + fmt.Stringer +} + +//IsBool is used for the XPath boolean function. It turns the data type to a bool. +type IsBool interface { + Bool() Bool +} + +//IsNum is used for the XPath number function. It turns the data type to a number. +type IsNum interface { + Num() Num +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/stub.go deleted file mode 100644 index 7cc3b01c6..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/stub.go +++ /dev/null @@ -1,78 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/ChrisTrenkamp/goxpath/tree, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/ChrisTrenkamp/goxpath/tree (exports: Node,String; functions: ) - -// Package tree is a stub of github.com/ChrisTrenkamp/goxpath/tree, generated by depstubber. -package tree - -import ( - xml "encoding/xml" -) - -type Bool bool - -func (_ Bool) Bool() Bool { - return false -} - -func (_ Bool) Num() Num { - return 0 -} - -func (_ Bool) String() string { - return "" -} - -type Elem interface { - GetAttrs() []Node - GetChildren() []Node - GetNodeType() NodeType - GetParent() Elem - GetToken() xml.Token - Pos() int - ResValue() string -} - -type Node interface { - GetNodeType() NodeType - GetParent() Elem - GetToken() xml.Token - Pos() int - ResValue() string -} - -type NodeType int - -func (_ NodeType) GetNodeType() NodeType { - return 0 -} - -type Num float64 - -func (_ Num) Bool() Bool { - return false -} - -func (_ Num) Num() Num { - return 0 -} - -func (_ Num) String() string { - return "" -} - -type String string - -func (_ String) Bool() Bool { - return false -} - -func (_ String) Num() Num { - return 0 -} - -func (_ String) String() string { - return "" -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go new file mode 100644 index 000000000..c5d6333d7 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go @@ -0,0 +1,221 @@ +package tree + +import ( + "encoding/xml" + "sort" +) + +//XMLSpace is the W3C XML namespace +const XMLSpace = "http://www.w3.org/XML/1998/namespace" + +//NodePos is a helper for representing the node's document order +type NodePos int + +//Pos returns the node's document order position +func (n NodePos) Pos() int { + return int(n) +} + +//NodeType is a safer way to determine a node's type than type assertions. +type NodeType int + +//GetNodeType returns the node's type. +func (t NodeType) GetNodeType() NodeType { + return t +} + +//These are all the possible node types +const ( + NtAttr NodeType = iota + NtChd + NtComm + NtElem + NtNs + NtRoot + NtPi +) + +//Node is a XPath result that is a node except elements +type Node interface { + //ResValue prints the node's string value + ResValue() string + //Pos returns the node's position in the document order + Pos() int + //GetToken returns the xml.Token representation of the node + GetToken() xml.Token + //GetParent returns the parent node, which will always be an XML element + GetParent() Elem + //GetNodeType returns the node's type + GetNodeType() NodeType +} + +//Elem is a XPath result that is an element node +type Elem interface { + Node + //GetChildren returns the elements children. + GetChildren() []Node + //GetAttrs returns the attributes of the element + GetAttrs() []Node +} + +//NSElem is a node that keeps track of namespaces. +type NSElem interface { + Elem + GetNS() map[xml.Name]string +} + +//NSBuilder is a helper-struct for satisfying the NSElem interface +type NSBuilder struct { + NS map[xml.Name]string +} + +//GetNS returns the namespaces found on the current element. It should not be +//confused with BuildNS, which actually resolves the namespace nodes. +func (ns NSBuilder) GetNS() map[xml.Name]string { + return ns.NS +} + +type nsValueSort []NS + +func (ns nsValueSort) Len() int { return len(ns) } +func (ns nsValueSort) Swap(i, j int) { + ns[i], ns[j] = ns[j], ns[i] +} +func (ns nsValueSort) Less(i, j int) bool { + return ns[i].Value < ns[j].Value +} + +//BuildNS resolves all the namespace nodes of the element and returns them +func BuildNS(t Elem) (ret []NS) { + vals := make(map[xml.Name]string) + + if nselem, ok := t.(NSElem); ok { + buildNS(nselem, vals) + + ret = make([]NS, 0, len(vals)) + i := 1 + + for k, v := range vals { + if !(k.Local == "xmlns" && k.Space == "" && v == "") { + ret = append(ret, NS{ + Attr: xml.Attr{Name: k, Value: v}, + Parent: t, + NodeType: NtNs, + }) + i++ + } + } + + sort.Sort(nsValueSort(ret)) + for i := range ret { + ret[i].NodePos = NodePos(t.Pos() + i + 1) + } + } + + return ret +} + +func buildNS(x NSElem, ret map[xml.Name]string) { + if x.GetNodeType() == NtRoot { + return + } + + if nselem, ok := x.GetParent().(NSElem); ok { + buildNS(nselem, ret) + } + + for k, v := range x.GetNS() { + ret[k] = v + } +} + +//NS is a namespace node. +type NS struct { + xml.Attr + Parent Elem + NodePos + NodeType +} + +//GetToken returns the xml.Token representation of the namespace. +func (ns NS) GetToken() xml.Token { + return ns.Attr +} + +//GetParent returns the parent node of the namespace. +func (ns NS) GetParent() Elem { + return ns.Parent +} + +//ResValue returns the string value of the namespace +func (ns NS) ResValue() string { + return ns.Attr.Value +} + +//GetAttribute is a convenience function for getting the specified attribute from an element. +//false is returned if the attribute is not found. +func GetAttribute(n Elem, local, space string) (xml.Attr, bool) { + attrs := n.GetAttrs() + for _, i := range attrs { + attr := i.GetToken().(xml.Attr) + if local == attr.Name.Local && space == attr.Name.Space { + return attr, true + } + } + return xml.Attr{}, false +} + +//GetAttributeVal is like GetAttribute, except it returns the attribute's value. +func GetAttributeVal(n Elem, local, space string) (string, bool) { + attr, ok := GetAttribute(n, local, space) + return attr.Value, ok +} + +//GetAttrValOrEmpty is like GetAttributeVal, except it returns an empty string if +//the attribute is not found instead of false. +func GetAttrValOrEmpty(n Elem, local, space string) string { + val, ok := GetAttributeVal(n, local, space) + if !ok { + return "" + } + return val +} + +//FindNodeByPos finds a node from the given position. Returns nil if the node +//is not found. +func FindNodeByPos(n Node, pos int) Node { + if n.Pos() == pos { + return n + } + + if elem, ok := n.(Elem); ok { + chldrn := elem.GetChildren() + for i := 1; i < len(chldrn); i++ { + if chldrn[i-1].Pos() <= pos && chldrn[i].Pos() > pos { + return FindNodeByPos(chldrn[i-1], pos) + } + } + + if len(chldrn) > 0 { + if chldrn[len(chldrn)-1].Pos() <= pos { + return FindNodeByPos(chldrn[len(chldrn)-1], pos) + } + } + + attrs := elem.GetAttrs() + for _, i := range attrs { + if i.Pos() == pos { + return i + } + } + + ns := BuildNS(elem) + for _, i := range ns { + if i.Pos() == pos { + return i + } + } + } + + return nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go new file mode 100644 index 000000000..7a940bb34 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go @@ -0,0 +1,52 @@ +package tree + +import ( + "fmt" +) + +//Ctx represents the current context position, size, node, and the current filtered result +type Ctx struct { + NodeSet + Pos int + Size int +} + +//Fn is a XPath function, written in Go +type Fn func(c Ctx, args ...Result) (Result, error) + +//LastArgOpt sets whether the last argument in a function is optional, variadic, or neither +type LastArgOpt int + +//LastArgOpt options +const ( + None LastArgOpt = iota + Optional + Variadic +) + +//Wrap interfaces XPath function calls with Go +type Wrap struct { + Fn Fn + //NArgs represents the number of arguments to the XPath function. -1 represents a single optional argument + NArgs int + LastArgOpt LastArgOpt +} + +//Call checks the arguments and calls Fn if they are valid +func (w Wrap) Call(c Ctx, args ...Result) (Result, error) { + switch w.LastArgOpt { + case Optional: + if len(args) == w.NArgs || len(args) == w.NArgs-1 { + return w.Fn(c, args...) + } + case Variadic: + if len(args) >= w.NArgs-1 { + return w.Fn(c, args...) + } + default: + if len(args) == w.NArgs { + return w.Fn(c, args...) + } + } + return nil, fmt.Errorf("Invalid number of arguments") +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go new file mode 100644 index 000000000..b9704109f --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go @@ -0,0 +1,113 @@ +package tree + +import ( + "fmt" + "math" + "strconv" + "strings" +) + +//Boolean strings +const ( + True = "true" + False = "false" +) + +//Bool is a boolean XPath type +type Bool bool + +//ResValue satisfies the Res interface for Bool +func (b Bool) String() string { + if b { + return True + } + + return False +} + +//Bool satisfies the HasBool interface for Bool's +func (b Bool) Bool() Bool { + return b +} + +//Num satisfies the HasNum interface for Bool's +func (b Bool) Num() Num { + if b { + return Num(1) + } + + return Num(0) +} + +//Num is a number XPath type +type Num float64 + +//ResValue satisfies the Res interface for Num +func (n Num) String() string { + if math.IsInf(float64(n), 0) { + if math.IsInf(float64(n), 1) { + return "Infinity" + } + return "-Infinity" + } + return fmt.Sprintf("%g", float64(n)) +} + +//Bool satisfies the HasBool interface for Num's +func (n Num) Bool() Bool { + return n != 0 +} + +//Num satisfies the HasNum interface for Num's +func (n Num) Num() Num { + return n +} + +//String is string XPath type +type String string + +//ResValue satisfies the Res interface for String +func (s String) String() string { + return string(s) +} + +//Bool satisfies the HasBool interface for String's +func (s String) Bool() Bool { + return Bool(len(s) > 0) +} + +//Num satisfies the HasNum interface for String's +func (s String) Num() Num { + num, err := strconv.ParseFloat(strings.TrimSpace(string(s)), 64) + if err != nil { + return Num(math.NaN()) + } + return Num(num) +} + +//NodeSet is a node-set XPath type +type NodeSet []Node + +//GetNodeNum converts the node to a string-value and to a number +func GetNodeNum(n Node) Num { + return String(n.ResValue()).Num() +} + +//String satisfies the Res interface for NodeSet +func (n NodeSet) String() string { + if len(n) == 0 { + return "" + } + + return n[0].ResValue() +} + +//Bool satisfies the HasBool interface for node-set's +func (n NodeSet) Bool() Bool { + return Bool(len(n) > 0) +} + +//Num satisfies the HasNum interface for NodeSet's +func (n NodeSet) Num() Num { + return String(n.String()).Num() +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go new file mode 100644 index 000000000..650991272 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go @@ -0,0 +1,66 @@ +package xconst + +const ( + //AxisAncestor represents the "ancestor" axis + AxisAncestor = "ancestor" + //AxisAncestorOrSelf represents the "ancestor-or-self" axis + AxisAncestorOrSelf = "ancestor-or-self" + //AxisAttribute represents the "attribute" axis + AxisAttribute = "attribute" + //AxisChild represents the "child" axis + AxisChild = "child" + //AxisDescendent represents the "descendant" axis + AxisDescendent = "descendant" + //AxisDescendentOrSelf represents the "descendant-or-self" axis + AxisDescendentOrSelf = "descendant-or-self" + //AxisFollowing represents the "following" axis + AxisFollowing = "following" + //AxisFollowingSibling represents the "following-sibling" axis + AxisFollowingSibling = "following-sibling" + //AxisNamespace represents the "namespace" axis + AxisNamespace = "namespace" + //AxisParent represents the "parent" axis + AxisParent = "parent" + //AxisPreceding represents the "preceding" axis + AxisPreceding = "preceding" + //AxisPrecedingSibling represents the "preceding-sibling" axis + AxisPrecedingSibling = "preceding-sibling" + //AxisSelf represents the "self" axis + AxisSelf = "self" +) + +//AxisNames is all the possible Axis identifiers wrapped in an array for convenience +var AxisNames = []string{ + AxisAncestor, + AxisAncestorOrSelf, + AxisAttribute, + AxisChild, + AxisDescendent, + AxisDescendentOrSelf, + AxisFollowing, + AxisFollowingSibling, + AxisNamespace, + AxisParent, + AxisPreceding, + AxisPrecedingSibling, + AxisSelf, +} + +const ( + //NodeTypeComment represents the "comment" node test + NodeTypeComment = "comment" + //NodeTypeText represents the "text" node test + NodeTypeText = "text" + //NodeTypeProcInst represents the "processing-instruction" node test + NodeTypeProcInst = "processing-instruction" + //NodeTypeNode represents the "node" node test + NodeTypeNode = "node" +) + +//NodeTypes is all the possible node tests wrapped in an array for convenience +var NodeTypes = []string{ + NodeTypeComment, + NodeTypeText, + NodeTypeProcInst, + NodeTypeNode, +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.gitignore b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.gitignore new file mode 100644 index 000000000..4d5d27b1d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.gitignore @@ -0,0 +1,32 @@ +# vscode +.vscode +debug +*.test + +./build + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.travis.yml b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.travis.yml new file mode 100644 index 000000000..384e03074 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/.travis.yml @@ -0,0 +1,18 @@ +language: go + +go: + - 1.7 + - 1.8 + - 1.9.x + - 1.12.x + - 1.13.x + +install: + - go get golang.org/x/net/html/charset + - go get golang.org/x/net/html + - go get github.com/antchfx/xpath + - go get github.com/mattn/goveralls + - go get github.com/golang/groupcache + +script: + - $HOME/gopath/bin/goveralls -service=travis-ci \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/README.md b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/README.md new file mode 100644 index 000000000..6e7775d57 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/README.md @@ -0,0 +1,168 @@ +htmlquery +==== +[![Build Status](https://travis-ci.org/antchfx/htmlquery.svg?branch=master)](https://travis-ci.org/antchfx/htmlquery) +[![Coverage Status](https://coveralls.io/repos/github/antchfx/htmlquery/badge.svg?branch=master)](https://coveralls.io/github/antchfx/htmlquery?branch=master) +[![GoDoc](https://godoc.org/github.com/antchfx/htmlquery?status.svg)](https://godoc.org/github.com/antchfx/htmlquery) +[![Go Report Card](https://goreportcard.com/badge/github.com/antchfx/htmlquery)](https://goreportcard.com/report/github.com/antchfx/htmlquery) + +Overview +==== + +`htmlquery` is an XPath query package for HTML, lets you extract data or evaluate from HTML documents by an XPath expression. + +`htmlquery` built-in the query object caching feature based on [LRU](https://godoc.org/github.com/golang/groupcache/lru), this feature will caching the recently used XPATH query string. Enable query caching can avoid re-compile XPath expression each query. + +Installation +==== + +``` +go get github.com/antchfx/htmlquery +``` + +Getting Started +==== + +#### Query, returns matched elements or error. + +```go +nodes, err := htmlquery.QueryAll(doc, "//a") +if err != nil { + panic(`not a valid XPath expression.`) +} +``` + +#### Load HTML document from URL. + +```go +doc, err := htmlquery.LoadURL("http://example.com/") +``` + +#### Load HTML from document. + +```go +filePath := "/home/user/sample.html" +doc, err := htmlquery.LoadDoc(filePath) +``` + +#### Load HTML document from string. + +```go +s := `....` +doc, err := htmlquery.Parse(strings.NewReader(s)) +``` + +#### Find all A elements. + +```go +list := htmlquery.Find(doc, "//a") +``` + +#### Find all A elements that have `href` attribute. + +```go +list := range htmlquery.Find(doc, "//a[@href]") +``` + +#### Find all A elements with `href` attribute and only return `href` value. + +```go +list := range htmlquery.Find(doc, "//a/@href") +for n := range list{ + fmt.Println(htmlquery.InnerText(n)) // output @href value without A element. +} +``` + +### Find the third A element. + +```go +a := htmlquery.FindOne(doc, "//a[3]") +``` + +#### Evaluate the number of all IMG element. + +```go +expr, _ := xpath.Compile("count(//img)") +v := expr.Evaluate(htmlquery.CreateXPathNavigator(doc)).(float64) +fmt.Printf("total count is %f", v) +``` + + +FAQ +==== + +#### `Find()` vs `QueryAll()`, which is better? + +`Find` and `QueryAll` both do the same things, searches all of matched html nodes. +The `Find` will panics if you give an error XPath query, but `QueryAll` will return an error for you. + +#### Can I save my query expression object for the next query? + +Yes, you can. We offer the `QuerySelector` and `QuerySelectorAll` methods, It will accept your query expression object. + +Cache a query expression object(or reused) will avoid re-compile XPath query expression, improve your query performance. + +#### XPath query object cache performance + +``` +goos: windows +goarch: amd64 +pkg: github.com/antchfx/htmlquery +BenchmarkSelectorCache-4 20000000 55.2 ns/op +BenchmarkDisableSelectorCache-4 500000 3162 ns/op +``` + +#### How to disable caching? + +``` +htmlquery.DisableSelectorCache = true +``` + +Changelogs +=== + +2019-11-19 +- Add built-in query object cache feature, avoid re-compilation for the same query string. [#16](https://github.com/antchfx/htmlquery/issues/16) +- Added LoadDoc [18](https://github.com/antchfx/htmlquery/pull/18) + +2019-10-05 +- Add new methods that compatible with invalid XPath expression error: `QueryAll` and `Query`. +- Add `QuerySelector` and `QuerySelectorAll` methods, supported reused your query object. + +2019-02-04 +- [#7](https://github.com/antchfx/htmlquery/issues/7) Removed deprecated `FindEach()` and `FindEachWithBreak()` methods. + +2018-12-28 +- Avoid adding duplicate elements to list for `Find()` method. [#6](https://github.com/antchfx/htmlquery/issues/6) + +Tutorial +=== + +```go +func main() { + doc, err := htmlquery.LoadURL("https://www.bing.com/search?q=golang") + if err != nil { + panic(err) + } + // Find all news item. + list, err := htmlquery.QueryAll(doc, "//ol/li") + if err != nil { + panic(err) + } + for i, n := range list { + a := htmlquery.FindOne(n, "//a") + fmt.Printf("%d %s(%s)\n", i, htmlquery.InnerText(a), htmlquery.SelectAttr(a, "href")) + } +} +``` + +List of supported XPath query packages +=== +| Name | Description | +| ------------------------------------------------- | ----------------------------------------- | +| [htmlquery](https://github.com/antchfx/htmlquery) | XPath query package for the HTML document | +| [xmlquery](https://github.com/antchfx/xmlquery) | XPath query package for the XML document | +| [jsonquery](https://github.com/antchfx/jsonquery) | XPath query package for the JSON document | + +Questions +=== +Please let me know if you have any questions. diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/cache.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/cache.go new file mode 100644 index 000000000..e27cd2897 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/cache.go @@ -0,0 +1,42 @@ +package htmlquery + +import ( + "sync" + + "github.com/antchfx/xpath" + "github.com/golang/groupcache/lru" +) + +// DisableSelectorCache will disable caching for the query selector if value is true. +var DisableSelectorCache = false + +// SelectorCacheMaxEntries allows how many selector object can be caching. Default is 50. +// Will disable caching if SelectorCacheMaxEntries <= 0. +var SelectorCacheMaxEntries = 50 + +var ( + cacheOnce sync.Once + cache *lru.Cache + cacheMutex sync.Mutex +) + +func getQuery(expr string) (*xpath.Expr, error) { + if DisableSelectorCache || SelectorCacheMaxEntries <= 0 { + return xpath.Compile(expr) + } + cacheOnce.Do(func() { + cache = lru.New(SelectorCacheMaxEntries) + }) + cacheMutex.Lock() + defer cacheMutex.Unlock() + if v, ok := cache.Get(expr); ok { + return v.(*xpath.Expr), nil + } + v, err := xpath.Compile(expr) + if err != nil { + return nil, err + } + cache.Add(expr, v) + return v, nil + +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/query.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/query.go new file mode 100644 index 000000000..db7578202 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/query.go @@ -0,0 +1,338 @@ +/* +Package htmlquery provides extract data from HTML documents using XPath expression. +*/ +package htmlquery + +import ( + "bufio" + "bytes" + "fmt" + "io" + "net/http" + "os" + + "github.com/antchfx/xpath" + "golang.org/x/net/html" + "golang.org/x/net/html/charset" +) + +var _ xpath.NodeNavigator = &NodeNavigator{} + +// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node. +func CreateXPathNavigator(top *html.Node) *NodeNavigator { + return &NodeNavigator{curr: top, root: top, attr: -1} +} + +// Find is like QueryAll but Will panics if the expression `expr` cannot be parsed. +// +// See `QueryAll()` function. +func Find(top *html.Node, expr string) []*html.Node { + nodes, err := QueryAll(top, expr) + if err != nil { + panic(err) + } + return nodes +} + +// FindOne is like Query but will panics if the expression `expr` cannot be parsed. +// See `Query()` function. +func FindOne(top *html.Node, expr string) *html.Node { + node, err := Query(top, expr) + if err != nil { + panic(err) + } + return node +} + +// QueryAll searches the html.Node that matches by the specified XPath expr. +// Return an error if the expression `expr` cannot be parsed. +func QueryAll(top *html.Node, expr string) ([]*html.Node, error) { + exp, err := getQuery(expr) + if err != nil { + return nil, err + } + nodes := QuerySelectorAll(top, exp) + return nodes, nil +} + +// Query searches the html.Node that matches by the specified XPath expr, +// and return the first element of matched html.Node. +// +// Return an error if the expression `expr` cannot be parsed. +func Query(top *html.Node, expr string) (*html.Node, error) { + exp, err := getQuery(expr) + if err != nil { + return nil, err + } + return QuerySelector(top, exp), nil +} + +// QuerySelector returns the first matched html.Node by the specified XPath selector. +func QuerySelector(top *html.Node, selector *xpath.Expr) *html.Node { + t := selector.Select(CreateXPathNavigator(top)) + if t.MoveNext() { + return getCurrentNode(t.Current().(*NodeNavigator)) + } + return nil +} + +// QuerySelectorAll searches all of the html.Node that matches the specified XPath selectors. +func QuerySelectorAll(top *html.Node, selector *xpath.Expr) []*html.Node { + var elems []*html.Node + t := selector.Select(CreateXPathNavigator(top)) + for t.MoveNext() { + nav := t.Current().(*NodeNavigator) + n := getCurrentNode(nav) + // avoid adding duplicate nodes. + if len(elems) > 0 && (elems[0] == n || (nav.NodeType() == xpath.AttributeNode && + nav.LocalName() == elems[0].Data && nav.Value() == InnerText(elems[0]))) { + continue + } + elems = append(elems, n) + } + return elems +} + +// LoadURL loads the HTML document from the specified URL. +func LoadURL(url string) (*html.Node, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + r, err := charset.NewReader(resp.Body, resp.Header.Get("Content-Type")) + if err != nil { + return nil, err + } + return html.Parse(r) +} + +// LoadDoc loads the HTML document from the specified file path. +func LoadDoc(path string) (*html.Node, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + return html.Parse(bufio.NewReader(f)) +} + +func getCurrentNode(n *NodeNavigator) *html.Node { + if n.NodeType() == xpath.AttributeNode { + childNode := &html.Node{ + Type: html.TextNode, + Data: n.Value(), + } + return &html.Node{ + Type: html.ElementNode, + Data: n.LocalName(), + FirstChild: childNode, + LastChild: childNode, + } + + } + return n.curr +} + +// Parse returns the parse tree for the HTML from the given Reader. +func Parse(r io.Reader) (*html.Node, error) { + return html.Parse(r) +} + +// InnerText returns the text between the start and end tags of the object. +func InnerText(n *html.Node) string { + var output func(*bytes.Buffer, *html.Node) + output = func(buf *bytes.Buffer, n *html.Node) { + switch n.Type { + case html.TextNode: + buf.WriteString(n.Data) + return + case html.CommentNode: + return + } + for child := n.FirstChild; child != nil; child = child.NextSibling { + output(buf, child) + } + } + + var buf bytes.Buffer + output(&buf, n) + return buf.String() +} + +// SelectAttr returns the attribute value with the specified name. +func SelectAttr(n *html.Node, name string) (val string) { + if n == nil { + return + } + if n.Type == html.ElementNode && n.Parent == nil && name == n.Data { + return InnerText(n) + } + for _, attr := range n.Attr { + if attr.Key == name { + val = attr.Val + break + } + } + return +} + +// OutputHTML returns the text including tags name. +func OutputHTML(n *html.Node, self bool) string { + var buf bytes.Buffer + if self { + html.Render(&buf, n) + } else { + for n := n.FirstChild; n != nil; n = n.NextSibling { + html.Render(&buf, n) + } + } + return buf.String() +} + +type NodeNavigator struct { + root, curr *html.Node + attr int +} + +func (h *NodeNavigator) Current() *html.Node { + return h.curr +} + +func (h *NodeNavigator) NodeType() xpath.NodeType { + switch h.curr.Type { + case html.CommentNode: + return xpath.CommentNode + case html.TextNode: + return xpath.TextNode + case html.DocumentNode: + return xpath.RootNode + case html.ElementNode: + if h.attr != -1 { + return xpath.AttributeNode + } + return xpath.ElementNode + case html.DoctypeNode: + // ignored declare and as Root-Node type. + return xpath.RootNode + } + panic(fmt.Sprintf("unknown HTML node type: %v", h.curr.Type)) +} + +func (h *NodeNavigator) LocalName() string { + if h.attr != -1 { + return h.curr.Attr[h.attr].Key + } + return h.curr.Data +} + +func (*NodeNavigator) Prefix() string { + return "" +} + +func (h *NodeNavigator) Value() string { + switch h.curr.Type { + case html.CommentNode: + return h.curr.Data + case html.ElementNode: + if h.attr != -1 { + return h.curr.Attr[h.attr].Val + } + return InnerText(h.curr) + case html.TextNode: + return h.curr.Data + } + return "" +} + +func (h *NodeNavigator) Copy() xpath.NodeNavigator { + n := *h + return &n +} + +func (h *NodeNavigator) MoveToRoot() { + h.curr = h.root +} + +func (h *NodeNavigator) MoveToParent() bool { + if h.attr != -1 { + h.attr = -1 + return true + } else if node := h.curr.Parent; node != nil { + h.curr = node + return true + } + return false +} + +func (h *NodeNavigator) MoveToNextAttribute() bool { + if h.attr >= len(h.curr.Attr)-1 { + return false + } + h.attr++ + return true +} + +func (h *NodeNavigator) MoveToChild() bool { + if h.attr != -1 { + return false + } + if node := h.curr.FirstChild; node != nil { + h.curr = node + return true + } + return false +} + +func (h *NodeNavigator) MoveToFirst() bool { + if h.attr != -1 || h.curr.PrevSibling == nil { + return false + } + for { + node := h.curr.PrevSibling + if node == nil { + break + } + h.curr = node + } + return true +} + +func (h *NodeNavigator) String() string { + return h.Value() +} + +func (h *NodeNavigator) MoveToNext() bool { + if h.attr != -1 { + return false + } + if node := h.curr.NextSibling; node != nil { + h.curr = node + return true + } + return false +} + +func (h *NodeNavigator) MoveToPrevious() bool { + if h.attr != -1 { + return false + } + if node := h.curr.PrevSibling; node != nil { + h.curr = node + return true + } + return false +} + +func (h *NodeNavigator) MoveTo(other xpath.NodeNavigator) bool { + node, ok := other.(*NodeNavigator) + if !ok || node.root != h.root { + return false + } + + h.curr = node.curr + h.attr = node.attr + return true +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/stub.go deleted file mode 100644 index 0bac0acfe..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/htmlquery/stub.go +++ /dev/null @@ -1,26 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/antchfx/htmlquery, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/antchfx/htmlquery (exports: ; functions: Find,FindOne,QueryAll,Query) - -// Package htmlquery is a stub of github.com/antchfx/htmlquery, generated by depstubber. -package htmlquery - -import () - -func Find(_ interface{}, _ string) []interface{} { - return nil -} - -func FindOne(_ interface{}, _ string) interface{} { - return nil -} - -func Query(_ interface{}, _ string) (interface{}, error) { - return nil, nil -} - -func QueryAll(_ interface{}, _ string) ([]interface{}, error) { - return nil, nil -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.gitignore b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.gitignore new file mode 100644 index 000000000..4d5d27b1d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.gitignore @@ -0,0 +1,32 @@ +# vscode +.vscode +debug +*.test + +./build + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.travis.yml b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.travis.yml new file mode 100644 index 000000000..e4f176de7 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/.travis.yml @@ -0,0 +1,16 @@ +language: go + +go: + - 1.7 + - 1.8 + - 1.9.x + - 1.12.x + - 1.13.x + +install: + - go get github.com/antchfx/xpath + - go get github.com/mattn/goveralls + - go get github.com/golang/groupcache + +script: + - $HOME/gopath/bin/goveralls -service=travis-ci \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/README.md b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/README.md new file mode 100644 index 000000000..162c289b9 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/README.md @@ -0,0 +1,175 @@ +jsonquery +==== +[![Build Status](https://travis-ci.org/antchfx/jsonquery.svg?branch=master)](https://travis-ci.org/antchfx/jsonquery) +[![Coverage Status](https://coveralls.io/repos/github/antchfx/jsonquery/badge.svg?branch=master)](https://coveralls.io/github/antchfx/jsonquery?branch=master) +[![GoDoc](https://godoc.org/github.com/antchfx/jsonquery?status.svg)](https://godoc.org/github.com/antchfx/jsonquery) +[![Go Report Card](https://goreportcard.com/badge/github.com/antchfx/jsonquery)](https://goreportcard.com/report/github.com/antchfx/jsonquery) + +Overview +=== + +jsonquery is an XPath query package for JSON document, lets you extract data from JSON documents through an XPath expression. Built-in XPath expression cache avoid re-compile XPath expression each query. + +Getting Started +=== + +### Install Package +``` +go get github.com/antchfx/jsonquery +``` + +#### Load JSON document from URL. + +```go +doc, err := jsonquery.LoadURL("http://www.example.com/feed?json") +``` + +#### Load JSON document from string. + +```go +s :=`{ + "name":"John", + "age":31, + "city":"New York" + }` +doc, err := jsonquery.Parse(strings.NewReader(s)) +``` + +#### Load JSON document from io.Reader. + +```go +f, err := os.Open("./books.json") +doc, err := jsonquery.Parse(f) +``` + +#### Find authors of all books in the store. +```go +list := jsonquery.Find(doc, "store/book/*/author") +// or equal to +list := jsonquery.Find(doc, "//author") +// or by QueryAll() +nodes, err := jsonquery.QueryAll(doc, "//a") +``` + +#### Find the third book. + +```go +book := jsonquery.Find(doc, "//book/*[3]") +``` + +#### Find the last book. + +```go +book := jsonquery.Find(doc, "//book/*[last()]") +``` + +#### Find all books with isbn number. + +```go +list := jsonquery.Find(doc, "//book/*[isbn]") +``` + +#### Find all books cheapier than 10. + +```go +list := jsonquery.Find(doc, "//book/*[price<10]") +``` + +Examples +=== + +```go +func main() { + s := `{ + "name": "John", + "age" : 26, + "address" : { + "streetAddress": "naist street", + "city" : "Nara", + "postalCode" : "630-0192" + }, + "phoneNumbers": [ + { + "type" : "iPhone", + "number": "0123-4567-8888" + }, + { + "type" : "home", + "number": "0123-4567-8910" + } + ] + }` + doc, err := jsonquery.Parse(strings.NewReader(s)) + if err != nil { + panic(err) + } + name := jsonquery.FindOne(doc, "name") + fmt.Printf("name: %s\n", name.InnerText()) + var a []string + for _, n := range jsonquery.Find(doc, "phoneNumbers/*/number") { + a = append(a, n.InnerText()) + } + fmt.Printf("phone number: %s\n", strings.Join(a, ",")) + if n := jsonquery.FindOne(doc, "address/streetAddress"); n != nil { + fmt.Printf("address: %s\n", n.InnerText()) + } +} +``` + +Implement Principle +=== +If you are familiar with XPath and XML, you can quick start to known how +write your XPath expression. + +```json +{ +"name":"John", +"age":30, +"cars": [ + { "name":"Ford", "models":[ "Fiesta", "Focus", "Mustang" ] }, + { "name":"BMW", "models":[ "320", "X3", "X5" ] }, + { "name":"Fiat", "models":[ "500", "Panda" ] } +] +} +``` +The above JSON document will be convert to similar to XML document by the *JSONQuery*, like below: + +```XML +John +30 + + + Ford + + Fiesta + Focus + Mustang + + + + BMW + + 320 + X3 + X5 + + + + Fiat + + 500 + Panda + + + +``` + +Notes: `element` is empty element that have no any name. + +List of XPath query packages +=== +|Name |Description | +|--------------------------|----------------| +|[htmlquery](https://github.com/antchfx/htmlquery) | XPath query package for the HTML document| +|[xmlquery](https://github.com/antchfx/xmlquery) | XPath query package for the XML document| +|[jsonquery](https://github.com/antchfx/jsonquery) | XPath query package for the JSON document| diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/books.json b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/books.json new file mode 100644 index 000000000..e4bd94628 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/books.json @@ -0,0 +1,36 @@ +{ + "store": { + "book": [ + { + "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { + "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { + "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { + "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95 + } + } +} \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/cache.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/cache.go new file mode 100644 index 000000000..27b7a324a --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/cache.go @@ -0,0 +1,43 @@ +package jsonquery + +import ( + "sync" + + "github.com/golang/groupcache/lru" + + "github.com/antchfx/xpath" +) + +// DisableSelectorCache will disable caching for the query selector if value is true. +var DisableSelectorCache = false + +// SelectorCacheMaxEntries allows how many selector object can be caching. Default is 50. +// Will disable caching if SelectorCacheMaxEntries <= 0. +var SelectorCacheMaxEntries = 50 + +var ( + cacheOnce sync.Once + cache *lru.Cache + cacheMutex sync.Mutex +) + +func getQuery(expr string) (*xpath.Expr, error) { + if DisableSelectorCache || SelectorCacheMaxEntries <= 0 { + return xpath.Compile(expr) + } + cacheOnce.Do(func() { + cache = lru.New(SelectorCacheMaxEntries) + }) + cacheMutex.Lock() + defer cacheMutex.Unlock() + if v, ok := cache.Get(expr); ok { + return v.(*xpath.Expr), nil + } + v, err := xpath.Compile(expr) + if err != nil { + return nil, err + } + cache.Add(expr, v) + return v, nil + +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/node.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/node.go new file mode 100644 index 000000000..76032bb2d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/node.go @@ -0,0 +1,157 @@ +package jsonquery + +import ( + "bytes" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "sort" + "strconv" +) + +// A NodeType is the type of a Node. +type NodeType uint + +const ( + // DocumentNode is a document object that, as the root of the document tree, + // provides access to the entire XML document. + DocumentNode NodeType = iota + // ElementNode is an element. + ElementNode + // TextNode is the text content of a node. + TextNode +) + +// A Node consists of a NodeType and some Data (tag name for +// element nodes, content for text) and are part of a tree of Nodes. +type Node struct { + Parent, PrevSibling, NextSibling, FirstChild, LastChild *Node + + Type NodeType + Data string + + level int +} + +// ChildNodes gets all child nodes of the node. +func (n *Node) ChildNodes() []*Node { + var a []*Node + for nn := n.FirstChild; nn != nil; nn = nn.NextSibling { + a = append(a, nn) + } + return a +} + +// InnerText gets the value of the node and all its child nodes. +func (n *Node) InnerText() string { + var output func(*bytes.Buffer, *Node) + output = func(buf *bytes.Buffer, n *Node) { + if n.Type == TextNode { + buf.WriteString(n.Data) + return + } + for child := n.FirstChild; child != nil; child = child.NextSibling { + output(buf, child) + } + } + var buf bytes.Buffer + output(&buf, n) + return buf.String() +} + +// SelectElement finds the first of child elements with the +// specified name. +func (n *Node) SelectElement(name string) *Node { + for nn := n.FirstChild; nn != nil; nn = nn.NextSibling { + if nn.Data == name { + return nn + } + } + return nil +} + +// LoadURL loads the JSON document from the specified URL. +func LoadURL(url string) (*Node, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return Parse(resp.Body) +} + +func parseValue(x interface{}, top *Node, level int) { + addNode := func(n *Node) { + if n.level == top.level { + top.NextSibling = n + n.PrevSibling = top + n.Parent = top.Parent + if top.Parent != nil { + top.Parent.LastChild = n + } + } else if n.level > top.level { + n.Parent = top + if top.FirstChild == nil { + top.FirstChild = n + top.LastChild = n + } else { + t := top.LastChild + t.NextSibling = n + n.PrevSibling = t + top.LastChild = n + } + } + } + switch v := x.(type) { + case []interface{}: + for _, vv := range v { + n := &Node{Type: ElementNode, level: level} + addNode(n) + parseValue(vv, n, level+1) + } + case map[string]interface{}: + // The Go’s map iteration order is random. + // (https://blog.golang.org/go-maps-in-action#Iteration-order) + var keys []string + for key := range v { + keys = append(keys, key) + } + sort.Strings(keys) + for _, key := range keys { + n := &Node{Data: key, Type: ElementNode, level: level} + addNode(n) + parseValue(v[key], n, level+1) + } + case string: + n := &Node{Data: v, Type: TextNode, level: level} + addNode(n) + case float64: + s := strconv.FormatFloat(v, 'f', -1, 64) + n := &Node{Data: s, Type: TextNode, level: level} + addNode(n) + case bool: + s := strconv.FormatBool(v) + n := &Node{Data: s, Type: TextNode, level: level} + addNode(n) + } +} + +func parse(b []byte) (*Node, error) { + var v interface{} + if err := json.Unmarshal(b, &v); err != nil { + return nil, err + } + doc := &Node{Type: DocumentNode} + parseValue(v, doc, 1) + return doc, nil +} + +// Parse JSON document. +func Parse(r io.Reader) (*Node, error) { + b, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + return parse(b) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/query.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/query.go new file mode 100644 index 000000000..642180163 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/query.go @@ -0,0 +1,177 @@ +package jsonquery + +import ( + "fmt" + + "github.com/antchfx/xpath" +) + +var _ xpath.NodeNavigator = &NodeNavigator{} + +// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node. +func CreateXPathNavigator(top *Node) *NodeNavigator { + return &NodeNavigator{cur: top, root: top} +} + +// Find is like QueryAll but will panics if `expr` cannot be parsed. +func Find(top *Node, expr string) []*Node { + nodes, err := QueryAll(top, expr) + if err != nil { + panic(err) + } + return nodes +} + +// FindOne is like Query but will panics if `expr` cannot be parsed. +func FindOne(top *Node, expr string) *Node { + node, err := Query(top, expr) + if err != nil { + panic(err) + } + return node +} + +// QueryAll searches the Node that matches by the specified XPath expr. +// Return an error if the expression `expr` cannot be parsed. +func QueryAll(top *Node, expr string) ([]*Node, error) { + exp, err := getQuery(expr) + if err != nil { + return nil, err + } + return QuerySelectorAll(top, exp), nil +} + +// Query searches the Node that matches by the specified XPath expr, +// and returns first element of matched. +func Query(top *Node, expr string) (*Node, error) { + exp, err := getQuery(expr) + if err != nil { + return nil, err + } + return QuerySelector(top, exp), nil +} + +// QuerySelectorAll searches all of the Node that matches the specified XPath selectors. +func QuerySelectorAll(top *Node, selector *xpath.Expr) []*Node { + t := selector.Select(CreateXPathNavigator(top)) + var elems []*Node + for t.MoveNext() { + elems = append(elems, (t.Current().(*NodeNavigator)).cur) + } + return elems +} + +// QuerySelector returns the first matched XML Node by the specified XPath selector. +func QuerySelector(top *Node, selector *xpath.Expr) *Node { + t := selector.Select(CreateXPathNavigator(top)) + if t.MoveNext() { + return (t.Current().(*NodeNavigator)).cur + } + return nil +} + +// NodeNavigator is for navigating JSON document. +type NodeNavigator struct { + root, cur *Node +} + +func (a *NodeNavigator) Current() *Node { + return a.cur +} + +func (a *NodeNavigator) NodeType() xpath.NodeType { + switch a.cur.Type { + case TextNode: + return xpath.TextNode + case DocumentNode: + return xpath.RootNode + case ElementNode: + return xpath.ElementNode + default: + panic(fmt.Sprintf("unknown node type %v", a.cur.Type)) + } +} + +func (a *NodeNavigator) LocalName() string { + return a.cur.Data + +} + +func (a *NodeNavigator) Prefix() string { + return "" +} + +func (a *NodeNavigator) Value() string { + switch a.cur.Type { + case ElementNode: + return a.cur.InnerText() + case TextNode: + return a.cur.Data + } + return "" +} + +func (a *NodeNavigator) Copy() xpath.NodeNavigator { + n := *a + return &n +} + +func (a *NodeNavigator) MoveToRoot() { + a.cur = a.root +} + +func (a *NodeNavigator) MoveToParent() bool { + if n := a.cur.Parent; n != nil { + a.cur = n + return true + } + return false +} + +func (x *NodeNavigator) MoveToNextAttribute() bool { + return false +} + +func (a *NodeNavigator) MoveToChild() bool { + if n := a.cur.FirstChild; n != nil { + a.cur = n + return true + } + return false +} + +func (a *NodeNavigator) MoveToFirst() bool { + for n := a.cur.PrevSibling; n != nil; n = n.PrevSibling { + a.cur = n + } + return true +} + +func (a *NodeNavigator) String() string { + return a.Value() +} + +func (a *NodeNavigator) MoveToNext() bool { + if n := a.cur.NextSibling; n != nil { + a.cur = n + return true + } + return false +} + +func (a *NodeNavigator) MoveToPrevious() bool { + if n := a.cur.PrevSibling; n != nil { + a.cur = n + return true + } + return false +} + +func (a *NodeNavigator) MoveTo(other xpath.NodeNavigator) bool { + node, ok := other.(*NodeNavigator) + if !ok || node.root != a.root { + return false + } + a.cur = node.cur + return true +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/stub.go deleted file mode 100644 index 2948daae0..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/jsonquery/stub.go +++ /dev/null @@ -1,50 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/antchfx/jsonquery, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/antchfx/jsonquery (exports: Node; functions: Find,FindOne,QueryAll,Query) - -// Package jsonquery is a stub of github.com/antchfx/jsonquery, generated by depstubber. -package jsonquery - -import () - -func Find(_ *Node, _ string) []*Node { - return nil -} - -func FindOne(_ *Node, _ string) *Node { - return nil -} - -type Node struct { - Parent *Node - PrevSibling *Node - NextSibling *Node - FirstChild *Node - LastChild *Node - Type NodeType - Data string -} - -func (_ *Node) ChildNodes() []*Node { - return nil -} - -func (_ *Node) InnerText() string { - return "" -} - -func (_ *Node) SelectElement(_ string) *Node { - return nil -} - -type NodeType uint - -func Query(_ *Node, _ string) (*Node, error) { - return nil, nil -} - -func QueryAll(_ *Node, _ string) ([]*Node, error) { - return nil, nil -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.gitignore b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.gitignore new file mode 100644 index 000000000..4d5d27b1d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.gitignore @@ -0,0 +1,32 @@ +# vscode +.vscode +debug +*.test + +./build + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.travis.yml b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.travis.yml new file mode 100644 index 000000000..c4d55b39e --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/.travis.yml @@ -0,0 +1,15 @@ +language: go + +go: + - 1.9.x + - 1.12.x + - 1.13.x + +install: + - go get golang.org/x/net/html/charset + - go get github.com/antchfx/xpath + - go get github.com/mattn/goveralls + - go get github.com/golang/groupcache + +script: + - $HOME/gopath/bin/goveralls -service=travis-ci diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/README.md b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/README.md new file mode 100644 index 000000000..410ae4445 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/README.md @@ -0,0 +1,256 @@ +xmlquery +==== +[![Build Status](https://travis-ci.org/antchfx/xmlquery.svg?branch=master)](https://travis-ci.org/antchfx/xmlquery) +[![Coverage Status](https://coveralls.io/repos/github/antchfx/xmlquery/badge.svg?branch=master)](https://coveralls.io/github/antchfx/xmlquery?branch=master) +[![GoDoc](https://godoc.org/github.com/antchfx/xmlquery?status.svg)](https://godoc.org/github.com/antchfx/xmlquery) +[![Go Report Card](https://goreportcard.com/badge/github.com/antchfx/xmlquery)](https://goreportcard.com/report/github.com/antchfx/xmlquery) + +Overview +=== + +`xmlquery` is an XPath query package for XML document, lets you extract data or evaluate from XML documents by an XPath expression. + +`xmlquery` built-in the query object caching feature will caching the recently used XPATH query string. Enable caching can avoid re-compile XPath expression each query. + +Change Logs +=== + +2020-08-?? +- Add XML stream loading and parsing support. + +2019-11-11 +- Add XPath query caching. + +2019-10-05 +- Add new methods that compatible with invalid XPath expression error: `QueryAll` and `Query`. +- Add `QuerySelector` and `QuerySelectorAll` methods, supported reused your query object. +- PR [#12](https://github.com/antchfx/xmlquery/pull/12) (Thanks @FrancescoIlario) +- PR [#11](https://github.com/antchfx/xmlquery/pull/11) (Thanks @gjvnq) + +2018-12-23 +- added XML output will including comment node. [#9](https://github.com/antchfx/xmlquery/issues/9) + +2018-12-03 +- added support attribute name with namespace prefix and XML output. [#6](https://github.com/antchfx/xmlquery/issues/6) + +Installation +==== +``` + $ go get github.com/antchfx/xmlquery +``` + +Getting Started +=== + +### Find specified XPath query. + +```go +list, err := xmlquery.QueryAll(doc, "a") +if err != nil { + panic(err) +} +``` + +#### Parse an XML from URL. + +```go +doc, err := xmlquery.LoadURL("http://www.example.com/sitemap.xml") +``` + +#### Parse an XML from string. + +```go +s := `` +doc, err := xmlquery.Parse(strings.NewReader(s)) +``` + +#### Parse an XML from io.Reader. + +```go +f, err := os.Open("../books.xml") +doc, err := xmlquery.Parse(f) +``` + +#### Parse an XML in a stream fashion (simple case without element filtering). + +```go +f, err := os.Open("../books.xml") +p, err := xmlquery.CreateStreamParser(f, "/bookstore/book") +for { + n, err := p.Read() + if err == io.EOF { + break + } + if err != nil { + ... + } +} +``` + +#### Parse an XML in a stream fashion (simple case advanced element filtering). + +```go +f, err := os.Open("../books.xml") +p, err := xmlquery.CreateStreamParser(f, "/bookstore/book", "/bookstore/book[price>=10]") +for { + n, err := p.Read() + if err == io.EOF { + break + } + if err != nil { + ... + } +} +``` + +#### Find authors of all books in the bookstore. + +```go +list := xmlquery.Find(doc, "//book//author") +// or +list := xmlquery.Find(doc, "//author") +``` + +#### Find the second book. + +```go +book := xmlquery.FindOne(doc, "//book[2]") +``` + +#### Find all book elements and only get `id` attribute self. (New Feature) + +```go +list := xmlquery.Find(doc,"//book/@id") +``` + +#### Find all books with id is bk104. + +```go +list := xmlquery.Find(doc, "//book[@id='bk104']") +``` + +#### Find all books that price less than 5. + +```go +list := xmlquery.Find(doc, "//book[price<5]") +``` + +#### Evaluate the total price of all books. + +```go +expr, err := xpath.Compile("sum(//book/price)") +price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64) +fmt.Printf("total price: %f\n", price) +``` + +#### Evaluate the number of all books element. + +```go +expr, err := xpath.Compile("count(//book)") +price := expr.Evaluate(xmlquery.CreateXPathNavigator(doc)).(float64) +``` + +FAQ +==== + +#### `Find()` vs `QueryAll()`, which is better? + +`Find` and `QueryAll` both do the same things, searches all of matched html nodes. +The `Find` will panics if you give an error XPath query, but `QueryAll` will return an error for you. + +#### Can I save my query expression object for the next query? + +Yes, you can. We offer the `QuerySelector` and `QuerySelectorAll` methods, It will accept your query expression object. + +Cache a query expression object(or reused) will avoid re-compile XPath query expression, improve your query performance. + +#### Create XML document. + +```go +doc := &xmlquery.Node{ + Type: xmlquery.DeclarationNode, + Data: "xml", + Attr: []xml.Attr{ + xml.Attr{Name: xml.Name{Local: "version"}, Value: "1.0"}, + }, +} +root := &xmlquery.Node{ + Data: "rss", + Type: xmlquery.ElementNode, +} +doc.FirstChild = root +channel := &xmlquery.Node{ + Data: "channel", + Type: xmlquery.ElementNode, +} +root.FirstChild = channel +title := &xmlquery.Node{ + Data: "title", + Type: xmlquery.ElementNode, +} +title_text := &xmlquery.Node{ + Data: "W3Schools Home Page", + Type: xmlquery.TextNode, +} +title.FirstChild = title_text +channel.FirstChild = title +fmt.Println(doc.OutputXML(true)) +// W3Schools Home Page +``` + +Quick Tutorial +=== + +```go +import ( + "github.com/antchfx/xmlquery" +) + +func main(){ + s := ` + + + W3Schools Home Page + https://www.w3schools.com + Free web building tutorials + + RSS Tutorial + https://www.w3schools.com/xml/xml_rss.asp + New RSS tutorial on W3Schools + + + XML Tutorial + https://www.w3schools.com/xml + New XML tutorial on W3Schools + + +` + + doc, err := xmlquery.Parse(strings.NewReader(s)) + if err != nil { + panic(err) + } + channel := xmlquery.FindOne(doc, "//channel") + if n := channel.SelectElement("title"); n != nil { + fmt.Printf("title: %s\n", n.InnerText()) + } + if n := channel.SelectElement("link"); n != nil { + fmt.Printf("link: %s\n", n.InnerText()) + } + for i, n := range xmlquery.Find(doc, "//item/title") { + fmt.Printf("#%d %s\n", i, n.InnerText()) + } +} +``` + +List of supported XPath query packages +=== +| Name | Description | +| ------------------------------------------------- | ----------------------------------------- | +| [htmlquery](https://github.com/antchfx/htmlquery) | XPath query package for the HTML document | +| [xmlquery](https://github.com/antchfx/xmlquery) | XPath query package for the XML document | +| [jsonquery](https://github.com/antchfx/jsonquery) | XPath query package for the JSON document | + + Questions +=== +Please let me know if you have any questions diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/books.xml b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/books.xml new file mode 100644 index 000000000..85a74b588 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/books.xml @@ -0,0 +1,121 @@ + + + + + Gambardella, Matthew + XML Developer's Guide + Computer + 44.95 + 2000-10-01 + An in-depth look at creating applications + with XML. + + + Ralls, Kim + Midnight Rain + Fantasy + 5.95 + 2000-12-16 + A former architect battles corporate zombies, + an evil sorceress, and her own childhood to become queen + of the world. + + + Corets, Eva + Maeve Ascendant + Fantasy + 5.95 + 2000-11-17 + After the collapse of a nanotechnology + society in England, the young survivors lay the + foundation for a new society. + + + Corets, Eva + Oberon's Legacy + Fantasy + 5.95 + 2001-03-10 + In post-apocalypse England, the mysterious + agent known only as Oberon helps to create a new life + for the inhabitants of London. Sequel to Maeve + Ascendant. + + + Corets, Eva + The Sundered Grail + Fantasy + 5.95 + 2001-09-10 + The two daughters of Maeve, half-sisters, + battle one another for control of England. Sequel to + Oberon's Legacy. + + + Randall, Cynthia + Lover Birds + Romance + 4.95 + 2000-09-02 + When Carla meets Paul at an ornithology + conference, tempers fly as feathers get ruffled. + + + Thurman, Paula + Splish Splash + Romance + 4.95 + 2000-11-02 + A deep sea diver finds true love twenty + thousand leagues beneath the sea. + + + Knorr, Stefan + Creepy Crawlies + Horror + 4.95 + 2000-12-06 + An anthology of horror stories about roaches, + centipedes, scorpions and other insects. + + + Kress, Peter + Paradox Lost + Science Fiction + 6.95 + 2000-11-02 + After an inadvertant trip through a Heisenberg + Uncertainty Device, James Salway discovers the problems + of being quantum. + + + O'Brien, Tim + Microsoft .NET: The Programming Bible + Computer + 36.95 + 2000-12-09 + Microsoft's .NET initiative is explored in + detail in this deep programmer's reference. + + + O'Brien, Tim + MSXML3: A Comprehensive Guide + Computer + 36.95 + 2000-12-01 + The Microsoft MSXML3 parser is covered in + detail, with attention to XML DOM interfaces, XSLT processing, + SAX and more. + + + Galos, Mike + Visual Studio 7: A Comprehensive Guide + Computer + 49.95 + 2001-04-16 + Microsoft Visual Studio 7 is explored in depth, + looking at how Visual Basic, Visual C++, C#, and ASP+ are + integrated into a comprehensive development + environment. + + \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/cache.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/cache.go new file mode 100644 index 000000000..3abffcdc5 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/cache.go @@ -0,0 +1,43 @@ +package xmlquery + +import ( + "sync" + + "github.com/golang/groupcache/lru" + + "github.com/antchfx/xpath" +) + +// DisableSelectorCache will disable caching for the query selector if value is true. +var DisableSelectorCache = false + +// SelectorCacheMaxEntries allows how many selector object can be caching. Default is 50. +// Will disable caching if SelectorCacheMaxEntries <= 0. +var SelectorCacheMaxEntries = 50 + +var ( + cacheOnce sync.Once + cache *lru.Cache + cacheMutex sync.Mutex +) + +func getQuery(expr string) (*xpath.Expr, error) { + if DisableSelectorCache || SelectorCacheMaxEntries <= 0 { + return xpath.Compile(expr) + } + cacheOnce.Do(func() { + cache = lru.New(SelectorCacheMaxEntries) + }) + cacheMutex.Lock() + defer cacheMutex.Unlock() + if v, ok := cache.Get(expr); ok { + return v.(*xpath.Expr), nil + } + v, err := xpath.Compile(expr) + if err != nil { + return nil, err + } + cache.Add(expr, v) + return v, nil + +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/go.mod b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/go.mod new file mode 100644 index 000000000..b6f453eac --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/go.mod @@ -0,0 +1,9 @@ +module github.com/antchfx/xmlquery + +go 1.14 + +require ( + github.com/antchfx/xpath v1.1.10 + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e + golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc +) diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/node.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/node.go new file mode 100644 index 000000000..e05374823 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/node.go @@ -0,0 +1,221 @@ +package xmlquery + +import ( + "bytes" + "encoding/xml" + "fmt" + "strings" +) + +// A NodeType is the type of a Node. +type NodeType uint + +const ( + // DocumentNode is a document object that, as the root of the document tree, + // provides access to the entire XML document. + DocumentNode NodeType = iota + // DeclarationNode is the document type declaration, indicated by the following + // tag (for example, ). + DeclarationNode + // ElementNode is an element (for example, ). + ElementNode + // TextNode is the text content of a node. + TextNode + // CharDataNode node + CharDataNode + // CommentNode a comment (for example, ). + CommentNode + // AttributeNode is an attribute of element. + AttributeNode +) + +// A Node consists of a NodeType and some Data (tag name for +// element nodes, content for text) and are part of a tree of Nodes. +type Node struct { + Parent, FirstChild, LastChild, PrevSibling, NextSibling *Node + + Type NodeType + Data string + Prefix string + NamespaceURI string + Attr []xml.Attr + + level int // node level in the tree +} + +// InnerText returns the text between the start and end tags of the object. +func (n *Node) InnerText() string { + var output func(*bytes.Buffer, *Node) + output = func(buf *bytes.Buffer, n *Node) { + switch n.Type { + case TextNode, CharDataNode: + buf.WriteString(n.Data) + case CommentNode: + default: + for child := n.FirstChild; child != nil; child = child.NextSibling { + output(buf, child) + } + } + } + + var buf bytes.Buffer + output(&buf, n) + return buf.String() +} + +func (n *Node) sanitizedData(preserveSpaces bool) string { + if preserveSpaces { + return strings.Trim(n.Data, "\n\t") + } + return strings.TrimSpace(n.Data) +} + +func calculatePreserveSpaces(n *Node, pastValue bool) bool { + if attr := n.SelectAttr("xml:space"); attr == "preserve" { + return true + } else if attr == "default" { + return false + } + return pastValue +} + +func outputXML(buf *bytes.Buffer, n *Node, preserveSpaces bool) { + preserveSpaces = calculatePreserveSpaces(n, preserveSpaces) + switch n.Type { + case TextNode, CharDataNode: + xml.EscapeText(buf, []byte(n.sanitizedData(preserveSpaces))) + return + case CommentNode: + buf.WriteString("") + return + case DeclarationNode: + buf.WriteString("") + } else { + buf.WriteString(">") + } + for child := n.FirstChild; child != nil; child = child.NextSibling { + outputXML(buf, child, preserveSpaces) + } + if n.Type != DeclarationNode { + if n.Prefix == "" { + buf.WriteString(fmt.Sprintf("", n.Data)) + } else { + buf.WriteString(fmt.Sprintf("", n.Prefix, n.Data)) + } + } +} + +// OutputXML returns the text that including tags name. +func (n *Node) OutputXML(self bool) string { + var buf bytes.Buffer + if self { + outputXML(&buf, n, false) + } else { + for n := n.FirstChild; n != nil; n = n.NextSibling { + outputXML(&buf, n, false) + } + } + + return buf.String() +} + +// AddAttr adds a new attribute specified by 'key' and 'val' to a node 'n'. +func AddAttr(n *Node, key, val string) { + var attr xml.Attr + if i := strings.Index(key, ":"); i > 0 { + attr = xml.Attr{ + Name: xml.Name{Space: key[:i], Local: key[i+1:]}, + Value: val, + } + } else { + attr = xml.Attr{ + Name: xml.Name{Local: key}, + Value: val, + } + } + + n.Attr = append(n.Attr, attr) +} + +// AddChild adds a new node 'n' to a node 'parent' as its last child. +func AddChild(parent, n *Node) { + n.Parent = parent + n.NextSibling = nil + if parent.FirstChild == nil { + parent.FirstChild = n + n.PrevSibling = nil + } else { + parent.LastChild.NextSibling = n + n.PrevSibling = parent.LastChild + } + + parent.LastChild = n +} + +// AddSibling adds a new node 'n' as a sibling of a given node 'sibling'. +// Note it is not necessarily true that the new node 'n' would be added +// immediately after 'sibling'. If 'sibling' isn't the last child of its +// parent, then the new node 'n' will be added at the end of the sibling +// chain of their parent. +func AddSibling(sibling, n *Node) { + for t := sibling.NextSibling; t != nil; t = t.NextSibling { + sibling = t + } + n.Parent = sibling.Parent + sibling.NextSibling = n + n.PrevSibling = sibling + n.NextSibling = nil + if sibling.Parent != nil { + sibling.Parent.LastChild = n + } +} + +// RemoveFromTree removes a node and its subtree from the document +// tree it is in. If the node is the root of the tree, then it's no-op. +func RemoveFromTree(n *Node) { + if n.Parent == nil { + return + } + if n.Parent.FirstChild == n { + if n.Parent.LastChild == n { + n.Parent.FirstChild = nil + n.Parent.LastChild = nil + } else { + n.Parent.FirstChild = n.NextSibling + n.NextSibling.PrevSibling = nil + } + } else { + if n.Parent.LastChild == n { + n.Parent.LastChild = n.PrevSibling + n.PrevSibling.NextSibling = nil + } else { + n.PrevSibling.NextSibling = n.NextSibling + n.NextSibling.PrevSibling = n.PrevSibling + } + } + n.Parent = nil + n.PrevSibling = nil + n.NextSibling = nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/parse.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/parse.go new file mode 100644 index 000000000..853ea0184 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/parse.go @@ -0,0 +1,311 @@ +package xmlquery + +import ( + "encoding/xml" + "errors" + "fmt" + "io" + "net/http" + "strings" + + "github.com/antchfx/xpath" + "golang.org/x/net/html/charset" +) + +// LoadURL loads the XML document from the specified URL. +func LoadURL(url string) (*Node, error) { + resp, err := http.Get(url) + if err != nil { + return nil, err + } + defer resp.Body.Close() + // Checking the HTTP Content-Type value from the response headers.(#39) + v := strings.ToLower(resp.Header.Get("Content-Type")) + if v == "text/xml" || v == "application/xml" { + return Parse(resp.Body) + } + return nil, fmt.Errorf("invalid XML document(%s)", v) +} + +// Parse returns the parse tree for the XML from the given Reader. +func Parse(r io.Reader) (*Node, error) { + p := createParser(r) + for { + _, err := p.parse() + if err == io.EOF { + return p.doc, nil + } + if err != nil { + return nil, err + } + } +} + +type parser struct { + decoder *xml.Decoder + doc *Node + space2prefix map[string]string + level int + prev *Node + streamElementXPath *xpath.Expr // Under streaming mode, this specifies the xpath to the target element node(s). + streamElementFilter *xpath.Expr // If specified, it provides a futher filtering on the target element. + streamNode *Node // Need to remmeber the last target node So we can clean it up upon next Read() call. + streamNodePrev *Node // Need to remember target node's prev so upon target node removal, we can restore correct prev. +} + +func createParser(r io.Reader) *parser { + p := &parser{ + decoder: xml.NewDecoder(r), + doc: &Node{Type: DocumentNode}, + space2prefix: make(map[string]string), + level: 0, + } + // http://www.w3.org/XML/1998/namespace is bound by definition to the prefix xml. + p.space2prefix["http://www.w3.org/XML/1998/namespace"] = "xml" + p.decoder.CharsetReader = charset.NewReaderLabel + p.prev = p.doc + return p +} + +func (p *parser) parse() (*Node, error) { + var streamElementNodeCounter int + + for { + tok, err := p.decoder.Token() + if err != nil { + return nil, err + } + + switch tok := tok.(type) { + case xml.StartElement: + if p.level == 0 { + // mising XML declaration + node := &Node{Type: DeclarationNode, Data: "xml", level: 1} + AddChild(p.prev, node) + p.level = 1 + p.prev = node + } + // https://www.w3.org/TR/xml-names/#scoping-defaulting + for _, att := range tok.Attr { + if att.Name.Local == "xmlns" { + p.space2prefix[att.Value] = "" + } else if att.Name.Space == "xmlns" { + p.space2prefix[att.Value] = att.Name.Local + } + } + + if tok.Name.Space != "" { + if _, found := p.space2prefix[tok.Name.Space]; !found { + return nil, errors.New("xmlquery: invalid XML document, namespace is missing") + } + } + + for i := 0; i < len(tok.Attr); i++ { + att := &tok.Attr[i] + if prefix, ok := p.space2prefix[att.Name.Space]; ok { + att.Name.Space = prefix + } + } + + node := &Node{ + Type: ElementNode, + Data: tok.Name.Local, + Prefix: p.space2prefix[tok.Name.Space], + NamespaceURI: tok.Name.Space, + Attr: tok.Attr, + level: p.level, + } + //fmt.Println(fmt.Sprintf("start > %s : %d", node.Data, node.level)) + if p.level == p.prev.level { + AddSibling(p.prev, node) + } else if p.level > p.prev.level { + AddChild(p.prev, node) + } else if p.level < p.prev.level { + for i := p.prev.level - p.level; i > 1; i-- { + p.prev = p.prev.Parent + } + AddSibling(p.prev.Parent, node) + } + // If we're in the streaming mode, we need to remember the node if it is the target node + // so that when we finish processing the node's EndElement, we know how/what to return to + // caller. Also we need to remove the target node from the tree upon next Read() call so + // memory doesn't grow unbounded. + if p.streamElementXPath != nil { + if p.streamNode == nil { + if QuerySelector(p.doc, p.streamElementXPath) != nil { + p.streamNode = node + p.streamNodePrev = p.prev + streamElementNodeCounter = 1 + } + } else { + streamElementNodeCounter++ + } + } + p.prev = node + p.level++ + case xml.EndElement: + p.level-- + // If we're in streaming mode, and we already have a potential streaming + // target node identified (p.streamNode != nil) then we need to check if + // this is the real one we want to return to caller. + if p.streamNode != nil { + streamElementNodeCounter-- + if streamElementNodeCounter == 0 { + // Now we know this element node is the at least passing the initial + // p.streamElementXPath check and is a potential target node candidate. + // We need to have 1 more check with p.streamElementFilter (if given) to + // ensure it is really the element node we want. + // The reason we need a two-step check process is because the following + // situation: + // b1 + // And say the p.streamElementXPath = "/AAA/BBB[. != 'b1']". Now during + // xml.StartElement time, the node is still empty, so it will pass + // the p.streamElementXPath check. However, eventually we know this + // shouldn't be returned to the caller. Having a second more fine-grained + // filter check ensures that. So in this case, the caller should really + // setup the stream parser with: + // streamElementXPath = "/AAA/BBB[" + // streamElementFilter = "/AAA/BBB[. != 'b1']" + if p.streamElementFilter == nil || QuerySelector(p.doc, p.streamElementFilter) != nil { + return p.streamNode, nil + } + // otherwise, this isn't our target node, clean things up. + // note we also remove the underlying *Node from the node tree, to prevent + // future stream node candidate selection error. + RemoveFromTree(p.streamNode) + p.prev = p.streamNodePrev + p.streamNode = nil + p.streamNodePrev = nil + } + } + case xml.CharData: + node := &Node{Type: CharDataNode, Data: string(tok), level: p.level} + if p.level == p.prev.level { + AddSibling(p.prev, node) + } else if p.level > p.prev.level { + AddChild(p.prev, node) + } else if p.level < p.prev.level { + for i := p.prev.level - p.level; i > 1; i-- { + p.prev = p.prev.Parent + } + AddSibling(p.prev.Parent, node) + } + case xml.Comment: + node := &Node{Type: CommentNode, Data: string(tok), level: p.level} + if p.level == p.prev.level { + AddSibling(p.prev, node) + } else if p.level > p.prev.level { + AddChild(p.prev, node) + } else if p.level < p.prev.level { + for i := p.prev.level - p.level; i > 1; i-- { + p.prev = p.prev.Parent + } + AddSibling(p.prev.Parent, node) + } + case xml.ProcInst: // Processing Instruction + if p.prev.Type != DeclarationNode { + p.level++ + } + node := &Node{Type: DeclarationNode, Data: tok.Target, level: p.level} + pairs := strings.Split(string(tok.Inst), " ") + for _, pair := range pairs { + pair = strings.TrimSpace(pair) + if i := strings.Index(pair, "="); i > 0 { + AddAttr(node, pair[:i], strings.Trim(pair[i+1:], `"`)) + } + } + if p.level == p.prev.level { + AddSibling(p.prev, node) + } else if p.level > p.prev.level { + AddChild(p.prev, node) + } + p.prev = node + case xml.Directive: + } + } +} + +// StreamParser enables loading and parsing an XML document in a streaming fashion. +type StreamParser struct { + p *parser +} + +// CreateStreamParser creates a StreamParser. Argument streamElementXPath is required. +// Argument streamElementFilter is optional and should only be used in advanced scenarios. +// +// Scenario 1: simple case: +// xml := `b1b2` +// sp, err := CreateStreamParser(strings.NewReader(xml), "/AAA/BBB") +// if err != nil { +// panic(err) +// } +// for { +// n, err := sp.Read() +// if err != nil { +// break +// } +// fmt.Println(n.OutputXML(true)) +// } +// Output will be: +// b1 +// b2 +// +// Scenario 2: advanced case: +// xml := `b1b2` +// sp, err := CreateStreamParser(strings.NewReader(xml), "/AAA/BBB", "/AAA/BBB[. != 'b1']") +// if err != nil { +// panic(err) +// } +// for { +// n, err := sp.Read() +// if err != nil { +// break +// } +// fmt.Println(n.OutputXML(true)) +// } +// Output will be: +// b2 +// +// As the argument names indicate, streamElementXPath should be used for providing xpath query pointing +// to the target element node only, no extra filtering on the element itself or its children; while +// streamElementFilter, if needed, can provide additional filtering on the target element and its children. +// +// CreateStreamParser returns error if either streamElementXPath or streamElementFilter, if provided, cannot +// be successfully parsed and compiled into a valid xpath query. +func CreateStreamParser(r io.Reader, streamElementXPath string, streamElementFilter ...string) (*StreamParser, error) { + elemXPath, err := getQuery(streamElementXPath) + if err != nil { + return nil, fmt.Errorf("invalid streamElementXPath '%s', err: %s", streamElementXPath, err.Error()) + } + elemFilter := (*xpath.Expr)(nil) + if len(streamElementFilter) > 0 { + elemFilter, err = getQuery(streamElementFilter[0]) + if err != nil { + return nil, fmt.Errorf("invalid streamElementFilter '%s', err: %s", streamElementFilter[0], err.Error()) + } + } + sp := &StreamParser{ + p: createParser(r), + } + sp.p.streamElementXPath = elemXPath + sp.p.streamElementFilter = elemFilter + return sp, nil +} + +// Read returns a target node that satisifies the XPath specified by caller at StreamParser creation +// time. If there is no more satisifying target node after reading the rest of the XML document, io.EOF +// will be returned. At any time, any XML parsing error encountered, the error will be returned and +// the stream parsing is stopped. Calling Read() after an error is returned (including io.EOF) is not +// allowed the behavior will be undefined. Also note, due to the streaming nature, calling Read() will +// automatically remove any previous target node(s) from the document tree. +func (sp *StreamParser) Read() (*Node, error) { + // Because this is a streaming read, we need to release/remove last + // target node from the node tree to free up memory. + if sp.p.streamNode != nil { + RemoveFromTree(sp.p.streamNode) + sp.p.prev = sp.p.streamNodePrev + sp.p.streamNode = nil + sp.p.streamNodePrev = nil + } + return sp.p.parse() +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/query.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/query.go new file mode 100644 index 000000000..c148e5f33 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/query.go @@ -0,0 +1,299 @@ +/* +Package xmlquery provides extract data from XML documents using XPath expression. +*/ +package xmlquery + +import ( + "fmt" + "strings" + + "github.com/antchfx/xpath" +) + +// SelectElements finds child elements with the specified name. +func (n *Node) SelectElements(name string) []*Node { + return Find(n, name) +} + +// SelectElement finds child elements with the specified name. +func (n *Node) SelectElement(name string) *Node { + return FindOne(n, name) +} + +// SelectAttr returns the attribute value with the specified name. +func (n *Node) SelectAttr(name string) string { + if n.Type == AttributeNode { + if n.Data == name { + return n.InnerText() + } + return "" + } + var local, space string + local = name + if i := strings.Index(name, ":"); i > 0 { + space = name[:i] + local = name[i+1:] + } + for _, attr := range n.Attr { + if attr.Name.Local == local && attr.Name.Space == space { + return attr.Value + } + } + return "" +} + +var _ xpath.NodeNavigator = &NodeNavigator{} + +// CreateXPathNavigator creates a new xpath.NodeNavigator for the specified html.Node. +func CreateXPathNavigator(top *Node) *NodeNavigator { + return &NodeNavigator{curr: top, root: top, attr: -1} +} + +func getCurrentNode(it *xpath.NodeIterator) *Node { + n := it.Current().(*NodeNavigator) + if n.NodeType() == xpath.AttributeNode { + childNode := &Node{ + Type: TextNode, + Data: n.Value(), + } + return &Node{ + Parent: n.curr, + Type: AttributeNode, + Data: n.LocalName(), + FirstChild: childNode, + LastChild: childNode, + } + } + return n.curr +} + +// Find is like QueryAll but it will panics if the `expr` is not a +// valid XPath expression. See `QueryAll()` function. +func Find(top *Node, expr string) []*Node { + nodes, err := QueryAll(top, expr) + if err != nil { + panic(err) + } + return nodes +} + +// FindOne is like Query but it will panics if the `expr` is not a +// valid XPath expression. See `Query()` function. +func FindOne(top *Node, expr string) *Node { + node, err := Query(top, expr) + if err != nil { + panic(err) + } + return node +} + +// QueryAll searches the XML Node that matches by the specified XPath expr. +// Return an error if the expression `expr` cannot be parsed. +func QueryAll(top *Node, expr string) ([]*Node, error) { + exp, err := getQuery(expr) + if err != nil { + return nil, err + } + return QuerySelectorAll(top, exp), nil +} + +// Query searches the XML Node that matches by the specified XPath expr, +// and returns first element of matched. +func Query(top *Node, expr string) (*Node, error) { + exp, err := getQuery(expr) + if err != nil { + return nil, err + } + return QuerySelector(top, exp), nil +} + +// QuerySelectorAll searches all of the XML Node that matches the specified XPath selectors. +func QuerySelectorAll(top *Node, selector *xpath.Expr) []*Node { + t := selector.Select(CreateXPathNavigator(top)) + var elems []*Node + for t.MoveNext() { + elems = append(elems, getCurrentNode(t)) + } + return elems +} + +// QuerySelector returns the first matched XML Node by the specified XPath selector. +func QuerySelector(top *Node, selector *xpath.Expr) *Node { + t := selector.Select(CreateXPathNavigator(top)) + if t.MoveNext() { + return getCurrentNode(t) + } + return nil +} + +// FindEach searches the html.Node and calls functions cb. +// Important: this method has deprecated, recommend use for .. = range Find(){}. +func FindEach(top *Node, expr string, cb func(int, *Node)) { + for i, n := range Find(top, expr) { + cb(i, n) + } +} + +// FindEachWithBreak functions the same as FindEach but allows you +// to break the loop by returning false from your callback function, cb. +// Important: this method has deprecated, recommend use for .. = range Find(){}. +func FindEachWithBreak(top *Node, expr string, cb func(int, *Node) bool) { + for i, n := range Find(top, expr) { + if !cb(i, n) { + break + } + } +} + +type NodeNavigator struct { + root, curr *Node + attr int +} + +func (x *NodeNavigator) Current() *Node { + return x.curr +} + +func (x *NodeNavigator) NodeType() xpath.NodeType { + switch x.curr.Type { + case CommentNode: + return xpath.CommentNode + case TextNode, CharDataNode: + return xpath.TextNode + case DeclarationNode, DocumentNode: + return xpath.RootNode + case ElementNode: + if x.attr != -1 { + return xpath.AttributeNode + } + return xpath.ElementNode + } + panic(fmt.Sprintf("unknown XML node type: %v", x.curr.Type)) +} + +func (x *NodeNavigator) LocalName() string { + if x.attr != -1 { + return x.curr.Attr[x.attr].Name.Local + } + return x.curr.Data + +} + +func (x *NodeNavigator) Prefix() string { + if x.NodeType() == xpath.AttributeNode { + if x.attr != -1 { + return x.curr.Attr[x.attr].Name.Space + } + return "" + } + return x.curr.Prefix +} + +func (x *NodeNavigator) NamespaceURL() string { + return x.curr.NamespaceURI +} + +func (x *NodeNavigator) Value() string { + switch x.curr.Type { + case CommentNode: + return x.curr.Data + case ElementNode: + if x.attr != -1 { + return x.curr.Attr[x.attr].Value + } + return x.curr.InnerText() + case TextNode: + return x.curr.Data + } + return "" +} + +func (x *NodeNavigator) Copy() xpath.NodeNavigator { + n := *x + return &n +} + +func (x *NodeNavigator) MoveToRoot() { + x.curr = x.root +} + +func (x *NodeNavigator) MoveToParent() bool { + if x.attr != -1 { + x.attr = -1 + return true + } else if node := x.curr.Parent; node != nil { + x.curr = node + return true + } + return false +} + +func (x *NodeNavigator) MoveToNextAttribute() bool { + if x.attr >= len(x.curr.Attr)-1 { + return false + } + x.attr++ + return true +} + +func (x *NodeNavigator) MoveToChild() bool { + if x.attr != -1 { + return false + } + if node := x.curr.FirstChild; node != nil { + x.curr = node + return true + } + return false +} + +func (x *NodeNavigator) MoveToFirst() bool { + if x.attr != -1 || x.curr.PrevSibling == nil { + return false + } + for { + node := x.curr.PrevSibling + if node == nil { + break + } + x.curr = node + } + return true +} + +func (x *NodeNavigator) String() string { + return x.Value() +} + +func (x *NodeNavigator) MoveToNext() bool { + if x.attr != -1 { + return false + } + if node := x.curr.NextSibling; node != nil { + x.curr = node + return true + } + return false +} + +func (x *NodeNavigator) MoveToPrevious() bool { + if x.attr != -1 { + return false + } + if node := x.curr.PrevSibling; node != nil { + x.curr = node + return true + } + return false +} + +func (x *NodeNavigator) MoveTo(other xpath.NodeNavigator) bool { + node, ok := other.(*NodeNavigator) + if !ok || node.root != x.root { + return false + } + + x.curr = node.curr + x.attr = node.attr + return true +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/stub.go deleted file mode 100644 index a4c5d8cc8..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xmlquery/stub.go +++ /dev/null @@ -1,67 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/antchfx/xmlquery, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/antchfx/xmlquery (exports: Node; functions: Find,FindOne,FindEach,FindEachWithBreak,QueryAll,Query) - -// Package xmlquery is a stub of github.com/antchfx/xmlquery, generated by depstubber. -package xmlquery - -import ( - xml "encoding/xml" -) - -func Find(_ *Node, _ string) []*Node { - return nil -} - -func FindEach(_ *Node, _ string, _ func(int, *Node)) {} - -func FindEachWithBreak(_ *Node, _ string, _ func(int, *Node) bool) {} - -func FindOne(_ *Node, _ string) *Node { - return nil -} - -type Node struct { - Parent *Node - FirstChild *Node - LastChild *Node - PrevSibling *Node - NextSibling *Node - Type NodeType - Data string - Prefix string - NamespaceURI string - Attr []xml.Attr -} - -func (_ *Node) InnerText() string { - return "" -} - -func (_ *Node) OutputXML(_ bool) string { - return "" -} - -func (_ *Node) SelectAttr(_ string) string { - return "" -} - -func (_ *Node) SelectElement(_ string) *Node { - return nil -} - -func (_ *Node) SelectElements(_ string) []*Node { - return nil -} - -type NodeType uint - -func Query(_ *Node, _ string) (*Node, error) { - return nil, nil -} - -func QueryAll(_ *Node, _ string) ([]*Node, error) { - return nil, nil -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.gitignore b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.gitignore new file mode 100644 index 000000000..4d5d27b1d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.gitignore @@ -0,0 +1,32 @@ +# vscode +.vscode +debug +*.test + +./build + +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.travis.yml b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.travis.yml new file mode 100644 index 000000000..6b63957a8 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/.travis.yml @@ -0,0 +1,12 @@ +language: go + +go: + - 1.6 + - 1.9 + - '1.10' + +install: + - go get github.com/mattn/goveralls + +script: + - $HOME/gopath/bin/goveralls -service=travis-ci \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/README.md b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/README.md new file mode 100644 index 000000000..540285d53 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/README.md @@ -0,0 +1,172 @@ +XPath +==== +[![GoDoc](https://godoc.org/github.com/antchfx/xpath?status.svg)](https://godoc.org/github.com/antchfx/xpath) +[![Coverage Status](https://coveralls.io/repos/github/antchfx/xpath/badge.svg?branch=master)](https://coveralls.io/github/antchfx/xpath?branch=master) +[![Build Status](https://travis-ci.org/antchfx/xpath.svg?branch=master)](https://travis-ci.org/antchfx/xpath) +[![Go Report Card](https://goreportcard.com/badge/github.com/antchfx/xpath)](https://goreportcard.com/report/github.com/antchfx/xpath) + +XPath is Go package provides selecting nodes from XML, HTML or other documents using XPath expression. + +Implementation +=== + +- [htmlquery](https://github.com/antchfx/htmlquery) - an XPath query package for HTML document + +- [xmlquery](https://github.com/antchfx/xmlquery) - an XPath query package for XML document. + +- [jsonquery](https://github.com/antchfx/jsonquery) - an XPath query package for JSON document + +Supported Features +=== + +#### The basic XPath patterns. + +> The basic XPath patterns cover 90% of the cases that most stylesheets will need. + +- `node` : Selects all child elements with nodeName of node. + +- `*` : Selects all child elements. + +- `@attr` : Selects the attribute attr. + +- `@*` : Selects all attributes. + +- `node()` : Matches an org.w3c.dom.Node. + +- `text()` : Matches a org.w3c.dom.Text node. + +- `comment()` : Matches a comment. + +- `.` : Selects the current node. + +- `..` : Selects the parent of current node. + +- `/` : Selects the document node. + +- `a[expr]` : Select only those nodes matching a which also satisfy the expression expr. + +- `a[n]` : Selects the nth matching node matching a When a filter's expression is a number, XPath selects based on position. + +- `a/b` : For each node matching a, add the nodes matching b to the result. + +- `a//b` : For each node matching a, add the descendant nodes matching b to the result. + +- `//b` : Returns elements in the entire document matching b. + +- `a|b` : All nodes matching a or b, union operation(not boolean or). + +- `(a, b, c)` : Evaluates each of its operands and concatenates the resulting sequences, in order, into a single result sequence + + +#### Node Axes + +- `child::*` : The child axis selects children of the current node. + +- `descendant::*` : The descendant axis selects descendants of the current node. It is equivalent to '//'. + +- `descendant-or-self::*` : Selects descendants including the current node. + +- `attribute::*` : Selects attributes of the current element. It is equivalent to @* + +- `following-sibling::*` : Selects nodes after the current node. + +- `preceding-sibling::*` : Selects nodes before the current node. + +- `following::*` : Selects the first matching node following in document order, excluding descendants. + +- `preceding::*` : Selects the first matching node preceding in document order, excluding ancestors. + +- `parent::*` : Selects the parent if it matches. The '..' pattern from the core is equivalent to 'parent::node()'. + +- `ancestor::*` : Selects matching ancestors. + +- `ancestor-or-self::*` : Selects ancestors including the current node. + +- `self::*` : Selects the current node. '.' is equivalent to 'self::node()'. + +#### Expressions + + The gxpath supported three types: number, boolean, string. + +- `path` : Selects nodes based on the path. + +- `a = b` : Standard comparisons. + + * a = b True if a equals b. + * a != b True if a is not equal to b. + * a < b True if a is less than b. + * a <= b True if a is less than or equal to b. + * a > b True if a is greater than b. + * a >= b True if a is greater than or equal to b. + +- `a + b` : Arithmetic expressions. + + * `- a` Unary minus + * a + b Add + * a - b Substract + * a * b Multiply + * a div b Divide + * a mod b Floating point mod, like Java. + +- `a or b` : Boolean `or` operation. + +- `a and b` : Boolean `and` operation. + +- `(expr)` : Parenthesized expressions. + +- `fun(arg1, ..., argn)` : Function calls: + +| Function | Supported | +| --- | --- | +`boolean()`| ✓ | +`ceiling()`| ✓ | +`choose()`| ✗ | +`concat()`| ✓ | +`contains()`| ✓ | +`count()`| ✓ | +`current()`| ✗ | +`document()`| ✗ | +`element-available()`| ✗ | +`ends-with()`| ✓ | +`false()`| ✓ | +`floor()`| ✓ | +`format-number()`| ✗ | +`function-available()`| ✗ | +`generate-id()`| ✗ | +`id()`| ✗ | +`key()`| ✗ | +`lang()`| ✗ | +`last()`| ✓ | +`local-name()`| ✓ | +`name()`| ✓ | +`namespace-uri()`| ✓ | +`normalize-space()`| ✓ | +`not()`| ✓ | +`number()`| ✓ | +`position()`| ✓ | +`replace()`| ✓ | +`reverse()`| ✓ | +`round()`| ✓ | +`starts-with()`| ✓ | +`string()`| ✓ | +`string-length()`| ✓ | +`substring()`| ✓ | +`substring-after()`| ✓ | +`substring-before()`| ✓ | +`sum()`| ✓ | +`system-property()`| ✗ | +`translate()`| ✓ | +`true()`| ✓ | +`unparsed-entity-url()` | ✗ | + +Changelogs +=== + +2019-03-19 +- optimize XPath `|` operation performance. [#33](https://github.com/antchfx/xpath/issues/33). Tips: suggest split into multiple subquery if you have a lot of `|` operations. + +2019-01-29 +- improvement `normalize-space` function. [#32](https://github.com/antchfx/xpath/issues/32) + +2018-12-07 +- supports XPath 2.0 Sequence expressions. [#30](https://github.com/antchfx/xpath/pull/30) by [@minherz](https://github.com/minherz). \ No newline at end of file diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/build.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/build.go new file mode 100644 index 000000000..b7f850f9b --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/build.go @@ -0,0 +1,522 @@ +package xpath + +import ( + "errors" + "fmt" +) + +type flag int + +const ( + noneFlag flag = iota + filterFlag +) + +// builder provides building an XPath expressions. +type builder struct { + depth int + flag flag + firstInput query +} + +// axisPredicate creates a predicate to predicating for this axis node. +func axisPredicate(root *axisNode) func(NodeNavigator) bool { + // get current axix node type. + typ := ElementNode + switch root.AxeType { + case "attribute": + typ = AttributeNode + case "self", "parent": + typ = allNode + default: + switch root.Prop { + case "comment": + typ = CommentNode + case "text": + typ = TextNode + // case "processing-instruction": + // typ = ProcessingInstructionNode + case "node": + typ = allNode + } + } + nametest := root.LocalName != "" || root.Prefix != "" + predicate := func(n NodeNavigator) bool { + if typ == n.NodeType() || typ == allNode || typ == TextNode { + if nametest { + if root.LocalName == n.LocalName() && root.Prefix == n.Prefix() { + return true + } + } else { + return true + } + } + return false + } + + return predicate +} + +// processAxisNode processes a query for the XPath axis node. +func (b *builder) processAxisNode(root *axisNode) (query, error) { + var ( + err error + qyInput query + qyOutput query + predicate = axisPredicate(root) + ) + + if root.Input == nil { + qyInput = &contextQuery{} + } else { + if root.AxeType == "child" && (root.Input.Type() == nodeAxis) { + if input := root.Input.(*axisNode); input.AxeType == "descendant-or-self" { + var qyGrandInput query + if input.Input != nil { + qyGrandInput, _ = b.processNode(input.Input) + } else { + qyGrandInput = &contextQuery{} + } + // fix #20: https://github.com/antchfx/htmlquery/issues/20 + filter := func(n NodeNavigator) bool { + v := predicate(n) + switch root.Prop { + case "text": + v = v && n.NodeType() == TextNode + case "comment": + v = v && n.NodeType() == CommentNode + } + return v + } + qyOutput = &descendantQuery{Input: qyGrandInput, Predicate: filter, Self: true} + return qyOutput, nil + } + } + qyInput, err = b.processNode(root.Input) + if err != nil { + return nil, err + } + } + + switch root.AxeType { + case "ancestor": + qyOutput = &ancestorQuery{Input: qyInput, Predicate: predicate} + case "ancestor-or-self": + qyOutput = &ancestorQuery{Input: qyInput, Predicate: predicate, Self: true} + case "attribute": + qyOutput = &attributeQuery{Input: qyInput, Predicate: predicate} + case "child": + filter := func(n NodeNavigator) bool { + v := predicate(n) + switch root.Prop { + case "text": + v = v && n.NodeType() == TextNode + case "node": + v = v && (n.NodeType() == ElementNode || n.NodeType() == TextNode) + case "comment": + v = v && n.NodeType() == CommentNode + } + return v + } + qyOutput = &childQuery{Input: qyInput, Predicate: filter} + case "descendant": + qyOutput = &descendantQuery{Input: qyInput, Predicate: predicate} + case "descendant-or-self": + qyOutput = &descendantQuery{Input: qyInput, Predicate: predicate, Self: true} + case "following": + qyOutput = &followingQuery{Input: qyInput, Predicate: predicate} + case "following-sibling": + qyOutput = &followingQuery{Input: qyInput, Predicate: predicate, Sibling: true} + case "parent": + qyOutput = &parentQuery{Input: qyInput, Predicate: predicate} + case "preceding": + qyOutput = &precedingQuery{Input: qyInput, Predicate: predicate} + case "preceding-sibling": + qyOutput = &precedingQuery{Input: qyInput, Predicate: predicate, Sibling: true} + case "self": + qyOutput = &selfQuery{Input: qyInput, Predicate: predicate} + case "namespace": + // haha,what will you do someting?? + default: + err = fmt.Errorf("unknown axe type: %s", root.AxeType) + return nil, err + } + return qyOutput, nil +} + +// processFilterNode builds query for the XPath filter predicate. +func (b *builder) processFilterNode(root *filterNode) (query, error) { + b.flag |= filterFlag + + qyInput, err := b.processNode(root.Input) + if err != nil { + return nil, err + } + qyCond, err := b.processNode(root.Condition) + if err != nil { + return nil, err + } + qyOutput := &filterQuery{Input: qyInput, Predicate: qyCond} + return qyOutput, nil +} + +// processFunctionNode processes query for the XPath function node. +func (b *builder) processFunctionNode(root *functionNode) (query, error) { + var qyOutput query + switch root.FuncName { + case "starts-with": + arg1, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + arg2, err := b.processNode(root.Args[1]) + if err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: b.firstInput, Func: startwithFunc(arg1, arg2)} + case "ends-with": + arg1, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + arg2, err := b.processNode(root.Args[1]) + if err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: b.firstInput, Func: endwithFunc(arg1, arg2)} + case "contains": + arg1, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + arg2, err := b.processNode(root.Args[1]) + if err != nil { + return nil, err + } + + qyOutput = &functionQuery{Input: b.firstInput, Func: containsFunc(arg1, arg2)} + case "substring": + //substring( string , start [, length] ) + if len(root.Args) < 2 { + return nil, errors.New("xpath: substring function must have at least two parameter") + } + var ( + arg1, arg2, arg3 query + err error + ) + if arg1, err = b.processNode(root.Args[0]); err != nil { + return nil, err + } + if arg2, err = b.processNode(root.Args[1]); err != nil { + return nil, err + } + if len(root.Args) == 3 { + if arg3, err = b.processNode(root.Args[2]); err != nil { + return nil, err + } + } + qyOutput = &functionQuery{Input: b.firstInput, Func: substringFunc(arg1, arg2, arg3)} + case "substring-before", "substring-after": + //substring-xxxx( haystack, needle ) + if len(root.Args) != 2 { + return nil, errors.New("xpath: substring-before function must have two parameters") + } + var ( + arg1, arg2 query + err error + ) + if arg1, err = b.processNode(root.Args[0]); err != nil { + return nil, err + } + if arg2, err = b.processNode(root.Args[1]); err != nil { + return nil, err + } + qyOutput = &functionQuery{ + Input: b.firstInput, + Func: substringIndFunc(arg1, arg2, root.FuncName == "substring-after"), + } + case "string-length": + // string-length( [string] ) + if len(root.Args) < 1 { + return nil, errors.New("xpath: string-length function must have at least one parameter") + } + arg1, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: b.firstInput, Func: stringLengthFunc(arg1)} + case "normalize-space": + if len(root.Args) == 0 { + return nil, errors.New("xpath: normalize-space function must have at least one parameter") + } + argQuery, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: argQuery, Func: normalizespaceFunc} + case "replace": + //replace( string , string, string ) + if len(root.Args) != 3 { + return nil, errors.New("xpath: replace function must have three parameters") + } + var ( + arg1, arg2, arg3 query + err error + ) + if arg1, err = b.processNode(root.Args[0]); err != nil { + return nil, err + } + if arg2, err = b.processNode(root.Args[1]); err != nil { + return nil, err + } + if arg3, err = b.processNode(root.Args[2]); err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: b.firstInput, Func: replaceFunc(arg1, arg2, arg3)} + case "translate": + //translate( string , string, string ) + if len(root.Args) != 3 { + return nil, errors.New("xpath: translate function must have three parameters") + } + var ( + arg1, arg2, arg3 query + err error + ) + if arg1, err = b.processNode(root.Args[0]); err != nil { + return nil, err + } + if arg2, err = b.processNode(root.Args[1]); err != nil { + return nil, err + } + if arg3, err = b.processNode(root.Args[2]); err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: b.firstInput, Func: translateFunc(arg1, arg2, arg3)} + case "not": + if len(root.Args) == 0 { + return nil, errors.New("xpath: not function must have at least one parameter") + } + argQuery, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: argQuery, Func: notFunc} + case "name", "local-name", "namespace-uri": + if len(root.Args) > 1 { + return nil, fmt.Errorf("xpath: %s function must have at most one parameter", root.FuncName) + } + var ( + arg query + err error + ) + if len(root.Args) == 1 { + arg, err = b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + } + switch root.FuncName { + case "name": + qyOutput = &functionQuery{Input: b.firstInput, Func: nameFunc(arg)} + case "local-name": + qyOutput = &functionQuery{Input: b.firstInput, Func: localNameFunc(arg)} + case "namespace-uri": + qyOutput = &functionQuery{Input: b.firstInput, Func: namespaceFunc(arg)} + } + case "true", "false": + val := root.FuncName == "true" + qyOutput = &functionQuery{ + Input: b.firstInput, + Func: func(_ query, _ iterator) interface{} { + return val + }, + } + case "last": + qyOutput = &functionQuery{Input: b.firstInput, Func: lastFunc} + case "position": + qyOutput = &functionQuery{Input: b.firstInput, Func: positionFunc} + case "boolean", "number", "string": + inp := b.firstInput + if len(root.Args) > 1 { + return nil, fmt.Errorf("xpath: %s function must have at most one parameter", root.FuncName) + } + if len(root.Args) == 1 { + argQuery, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + inp = argQuery + } + f := &functionQuery{Input: inp} + switch root.FuncName { + case "boolean": + f.Func = booleanFunc + case "string": + f.Func = stringFunc + case "number": + f.Func = numberFunc + } + qyOutput = f + case "count": + //if b.firstInput == nil { + // return nil, errors.New("xpath: expression must evaluate to node-set") + //} + if len(root.Args) == 0 { + return nil, fmt.Errorf("xpath: count(node-sets) function must with have parameters node-sets") + } + argQuery, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: argQuery, Func: countFunc} + case "sum": + if len(root.Args) == 0 { + return nil, fmt.Errorf("xpath: sum(node-sets) function must with have parameters node-sets") + } + argQuery, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + qyOutput = &functionQuery{Input: argQuery, Func: sumFunc} + case "ceiling", "floor", "round": + if len(root.Args) == 0 { + return nil, fmt.Errorf("xpath: ceiling(node-sets) function must with have parameters node-sets") + } + argQuery, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + f := &functionQuery{Input: argQuery} + switch root.FuncName { + case "ceiling": + f.Func = ceilingFunc + case "floor": + f.Func = floorFunc + case "round": + f.Func = roundFunc + } + qyOutput = f + case "concat": + if len(root.Args) < 2 { + return nil, fmt.Errorf("xpath: concat() must have at least two arguments") + } + var args []query + for _, v := range root.Args { + q, err := b.processNode(v) + if err != nil { + return nil, err + } + args = append(args, q) + } + qyOutput = &functionQuery{Input: b.firstInput, Func: concatFunc(args...)} + case "reverse": + if len(root.Args) == 0 { + return nil, fmt.Errorf("xpath: reverse(node-sets) function must with have parameters node-sets") + } + argQuery, err := b.processNode(root.Args[0]) + if err != nil { + return nil, err + } + qyOutput = &transformFunctionQuery{Input: argQuery, Func: reverseFunc} + default: + return nil, fmt.Errorf("not yet support this function %s()", root.FuncName) + } + return qyOutput, nil +} + +func (b *builder) processOperatorNode(root *operatorNode) (query, error) { + left, err := b.processNode(root.Left) + if err != nil { + return nil, err + } + right, err := b.processNode(root.Right) + if err != nil { + return nil, err + } + var qyOutput query + switch root.Op { + case "+", "-", "div", "mod": // Numeric operator + var exprFunc func(interface{}, interface{}) interface{} + switch root.Op { + case "+": + exprFunc = plusFunc + case "-": + exprFunc = minusFunc + case "div": + exprFunc = divFunc + case "mod": + exprFunc = modFunc + } + qyOutput = &numericQuery{Left: left, Right: right, Do: exprFunc} + case "=", ">", ">=", "<", "<=", "!=": + var exprFunc func(iterator, interface{}, interface{}) interface{} + switch root.Op { + case "=": + exprFunc = eqFunc + case ">": + exprFunc = gtFunc + case ">=": + exprFunc = geFunc + case "<": + exprFunc = ltFunc + case "<=": + exprFunc = leFunc + case "!=": + exprFunc = neFunc + } + qyOutput = &logicalQuery{Left: left, Right: right, Do: exprFunc} + case "or", "and": + isOr := false + if root.Op == "or" { + isOr = true + } + qyOutput = &booleanQuery{Left: left, Right: right, IsOr: isOr} + case "|": + qyOutput = &unionQuery{Left: left, Right: right} + } + return qyOutput, nil +} + +func (b *builder) processNode(root node) (q query, err error) { + if b.depth = b.depth + 1; b.depth > 1024 { + err = errors.New("the xpath expressions is too complex") + return + } + + switch root.Type() { + case nodeConstantOperand: + n := root.(*operandNode) + q = &constantQuery{Val: n.Val} + case nodeRoot: + q = &contextQuery{Root: true} + case nodeAxis: + q, err = b.processAxisNode(root.(*axisNode)) + b.firstInput = q + case nodeFilter: + q, err = b.processFilterNode(root.(*filterNode)) + case nodeFunction: + q, err = b.processFunctionNode(root.(*functionNode)) + case nodeOperator: + q, err = b.processOperatorNode(root.(*operatorNode)) + } + return +} + +// build builds a specified XPath expressions expr. +func build(expr string) (q query, err error) { + defer func() { + if e := recover(); e != nil { + switch x := e.(type) { + case string: + err = errors.New(x) + case error: + err = x + default: + err = errors.New("unknown panic") + } + } + }() + root := parse(expr) + b := &builder{} + return b.processNode(root) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func.go new file mode 100644 index 000000000..bcfee55b2 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func.go @@ -0,0 +1,585 @@ +package xpath + +import ( + "errors" + "fmt" + "math" + "strconv" + "strings" + "sync" + "unicode" +) + +// Defined an interface of stringBuilder that compatible with +// strings.Builder(go 1.10) and bytes.Buffer(< go 1.10) +type stringBuilder interface { + WriteRune(r rune) (n int, err error) + WriteString(s string) (int, error) + Reset() + Grow(n int) + String() string +} + +var builderPool = sync.Pool{New: func() interface{} { + return newStringBuilder() +}} + +// The XPath function list. + +func predicate(q query) func(NodeNavigator) bool { + type Predicater interface { + Test(NodeNavigator) bool + } + if p, ok := q.(Predicater); ok { + return p.Test + } + return func(NodeNavigator) bool { return true } +} + +// positionFunc is a XPath Node Set functions position(). +func positionFunc(q query, t iterator) interface{} { + var ( + count = 1 + node = t.Current().Copy() + ) + test := predicate(q) + for node.MoveToPrevious() { + if test(node) { + count++ + } + } + return float64(count) +} + +// lastFunc is a XPath Node Set functions last(). +func lastFunc(q query, t iterator) interface{} { + var ( + count = 0 + node = t.Current().Copy() + ) + node.MoveToFirst() + test := predicate(q) + for { + if test(node) { + count++ + } + if !node.MoveToNext() { + break + } + } + return float64(count) +} + +// countFunc is a XPath Node Set functions count(node-set). +func countFunc(q query, t iterator) interface{} { + var count = 0 + q = functionArgs(q) + test := predicate(q) + switch typ := q.Evaluate(t).(type) { + case query: + for node := typ.Select(t); node != nil; node = typ.Select(t) { + if test(node) { + count++ + } + } + } + return float64(count) +} + +// sumFunc is a XPath Node Set functions sum(node-set). +func sumFunc(q query, t iterator) interface{} { + var sum float64 + switch typ := functionArgs(q).Evaluate(t).(type) { + case query: + for node := typ.Select(t); node != nil; node = typ.Select(t) { + if v, err := strconv.ParseFloat(node.Value(), 64); err == nil { + sum += v + } + } + case float64: + sum = typ + case string: + v, err := strconv.ParseFloat(typ, 64) + if err != nil { + panic(errors.New("sum() function argument type must be a node-set or number")) + } + sum = v + } + return sum +} + +func asNumber(t iterator, o interface{}) float64 { + switch typ := o.(type) { + case query: + node := typ.Select(t) + if node == nil { + return float64(0) + } + if v, err := strconv.ParseFloat(node.Value(), 64); err == nil { + return v + } + case float64: + return typ + case string: + v, err := strconv.ParseFloat(typ, 64) + if err != nil { + panic(errors.New("ceiling() function argument type must be a node-set or number")) + } + return v + } + return 0 +} + +// ceilingFunc is a XPath Node Set functions ceiling(node-set). +func ceilingFunc(q query, t iterator) interface{} { + val := asNumber(t, functionArgs(q).Evaluate(t)) + return math.Ceil(val) +} + +// floorFunc is a XPath Node Set functions floor(node-set). +func floorFunc(q query, t iterator) interface{} { + val := asNumber(t, functionArgs(q).Evaluate(t)) + return math.Floor(val) +} + +// roundFunc is a XPath Node Set functions round(node-set). +func roundFunc(q query, t iterator) interface{} { + val := asNumber(t, functionArgs(q).Evaluate(t)) + //return math.Round(val) + return round(val) +} + +// nameFunc is a XPath functions name([node-set]). +func nameFunc(arg query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var v NodeNavigator + if arg == nil { + v = t.Current() + } else { + v = arg.Select(t) + if v == nil { + return "" + } + } + ns := v.Prefix() + if ns == "" { + return v.LocalName() + } + return ns + ":" + v.LocalName() + } +} + +// localNameFunc is a XPath functions local-name([node-set]). +func localNameFunc(arg query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var v NodeNavigator + if arg == nil { + v = t.Current() + } else { + v = arg.Select(t) + if v == nil { + return "" + } + } + return v.LocalName() + } +} + +// namespaceFunc is a XPath functions namespace-uri([node-set]). +func namespaceFunc(arg query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var v NodeNavigator + if arg == nil { + v = t.Current() + } else { + // Get the first node in the node-set if specified. + v = arg.Select(t) + if v == nil { + return "" + } + } + // fix about namespace-uri() bug: https://github.com/antchfx/xmlquery/issues/22 + // TODO: In the next version, add NamespaceURL() to the NodeNavigator interface. + type namespaceURL interface { + NamespaceURL() string + } + if f, ok := v.(namespaceURL); ok { + return f.NamespaceURL() + } + return v.Prefix() + } +} + +func asBool(t iterator, v interface{}) bool { + switch v := v.(type) { + case nil: + return false + case *NodeIterator: + return v.MoveNext() + case bool: + return v + case float64: + return v != 0 + case string: + return v != "" + case query: + return v.Select(t) != nil + default: + panic(fmt.Errorf("unexpected type: %T", v)) + } +} + +func asString(t iterator, v interface{}) string { + switch v := v.(type) { + case nil: + return "" + case bool: + if v { + return "true" + } + return "false" + case float64: + return strconv.FormatFloat(v, 'g', -1, 64) + case string: + return v + case query: + node := v.Select(t) + if node == nil { + return "" + } + return node.Value() + default: + panic(fmt.Errorf("unexpected type: %T", v)) + } +} + +// booleanFunc is a XPath functions boolean([node-set]). +func booleanFunc(q query, t iterator) interface{} { + v := functionArgs(q).Evaluate(t) + return asBool(t, v) +} + +// numberFunc is a XPath functions number([node-set]). +func numberFunc(q query, t iterator) interface{} { + v := functionArgs(q).Evaluate(t) + return asNumber(t, v) +} + +// stringFunc is a XPath functions string([node-set]). +func stringFunc(q query, t iterator) interface{} { + v := functionArgs(q).Evaluate(t) + return asString(t, v) +} + +// startwithFunc is a XPath functions starts-with(string, string). +func startwithFunc(arg1, arg2 query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var ( + m, n string + ok bool + ) + switch typ := functionArgs(arg1).Evaluate(t).(type) { + case string: + m = typ + case query: + node := typ.Select(t) + if node == nil { + return false + } + m = node.Value() + default: + panic(errors.New("starts-with() function argument type must be string")) + } + n, ok = functionArgs(arg2).Evaluate(t).(string) + if !ok { + panic(errors.New("starts-with() function argument type must be string")) + } + return strings.HasPrefix(m, n) + } +} + +// endwithFunc is a XPath functions ends-with(string, string). +func endwithFunc(arg1, arg2 query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var ( + m, n string + ok bool + ) + switch typ := functionArgs(arg1).Evaluate(t).(type) { + case string: + m = typ + case query: + node := typ.Select(t) + if node == nil { + return false + } + m = node.Value() + default: + panic(errors.New("ends-with() function argument type must be string")) + } + n, ok = functionArgs(arg2).Evaluate(t).(string) + if !ok { + panic(errors.New("ends-with() function argument type must be string")) + } + return strings.HasSuffix(m, n) + } +} + +// containsFunc is a XPath functions contains(string or @attr, string). +func containsFunc(arg1, arg2 query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var ( + m, n string + ok bool + ) + switch typ := functionArgs(arg1).Evaluate(t).(type) { + case string: + m = typ + case query: + node := typ.Select(t) + if node == nil { + return false + } + m = node.Value() + default: + panic(errors.New("contains() function argument type must be string")) + } + + n, ok = functionArgs(arg2).Evaluate(t).(string) + if !ok { + panic(errors.New("contains() function argument type must be string")) + } + + return strings.Contains(m, n) + } +} + +// normalizespaceFunc is XPath functions normalize-space(string?) +func normalizespaceFunc(q query, t iterator) interface{} { + var m string + switch typ := functionArgs(q).Evaluate(t).(type) { + case string: + m = typ + case query: + node := typ.Select(t) + if node == nil { + return "" + } + m = node.Value() + } + var b = builderPool.Get().(stringBuilder) + b.Grow(len(m)) + + runeStr := []rune(strings.TrimSpace(m)) + l := len(runeStr) + for i := range runeStr { + r := runeStr[i] + isSpace := unicode.IsSpace(r) + if !(isSpace && (i+1 < l && unicode.IsSpace(runeStr[i+1]))) { + if isSpace { + r = ' ' + } + b.WriteRune(r) + } + } + result := b.String() + b.Reset() + builderPool.Put(b) + + return result +} + +// substringFunc is XPath functions substring function returns a part of a given string. +func substringFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var m string + switch typ := functionArgs(arg1).Evaluate(t).(type) { + case string: + m = typ + case query: + node := typ.Select(t) + if node == nil { + return "" + } + m = node.Value() + } + + var start, length float64 + var ok bool + + if start, ok = functionArgs(arg2).Evaluate(t).(float64); !ok { + panic(errors.New("substring() function first argument type must be int")) + } else if start < 1 { + panic(errors.New("substring() function first argument type must be >= 1")) + } + start-- + if arg3 != nil { + if length, ok = functionArgs(arg3).Evaluate(t).(float64); !ok { + panic(errors.New("substring() function second argument type must be int")) + } + } + if (len(m) - int(start)) < int(length) { + panic(errors.New("substring() function start and length argument out of range")) + } + if length > 0 { + return m[int(start):int(length+start)] + } + return m[int(start):] + } +} + +// substringIndFunc is XPath functions substring-before/substring-after function returns a part of a given string. +func substringIndFunc(arg1, arg2 query, after bool) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + var str string + switch v := functionArgs(arg1).Evaluate(t).(type) { + case string: + str = v + case query: + node := v.Select(t) + if node == nil { + return "" + } + str = node.Value() + } + var word string + switch v := functionArgs(arg2).Evaluate(t).(type) { + case string: + word = v + case query: + node := v.Select(t) + if node == nil { + return "" + } + word = node.Value() + } + if word == "" { + return "" + } + + i := strings.Index(str, word) + if i < 0 { + return "" + } + if after { + return str[i+len(word):] + } + return str[:i] + } +} + +// stringLengthFunc is XPATH string-length( [string] ) function that returns a number +// equal to the number of characters in a given string. +func stringLengthFunc(arg1 query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + switch v := functionArgs(arg1).Evaluate(t).(type) { + case string: + return float64(len(v)) + case query: + node := v.Select(t) + if node == nil { + break + } + return float64(len(node.Value())) + } + return float64(0) + } +} + +// translateFunc is XPath functions translate() function returns a replaced string. +func translateFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + str := asString(t, functionArgs(arg1).Evaluate(t)) + src := asString(t, functionArgs(arg2).Evaluate(t)) + dst := asString(t, functionArgs(arg3).Evaluate(t)) + + replace := make([]string, 0, len(src)) + for i, s := range src { + d := "" + if i < len(dst) { + d = string(dst[i]) + } + replace = append(replace, string(s), d) + } + return strings.NewReplacer(replace...).Replace(str) + } +} + +// replaceFunc is XPath functions replace() function returns a replaced string. +func replaceFunc(arg1, arg2, arg3 query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + str := asString(t, functionArgs(arg1).Evaluate(t)) + src := asString(t, functionArgs(arg2).Evaluate(t)) + dst := asString(t, functionArgs(arg3).Evaluate(t)) + + return strings.Replace(str, src, dst, -1) + } +} + +// notFunc is XPATH functions not(expression) function operation. +func notFunc(q query, t iterator) interface{} { + switch v := functionArgs(q).Evaluate(t).(type) { + case bool: + return !v + case query: + node := v.Select(t) + return node == nil + default: + return false + } +} + +// concatFunc is the concat function concatenates two or more +// strings and returns the resulting string. +// concat( string1 , string2 [, stringn]* ) +func concatFunc(args ...query) func(query, iterator) interface{} { + return func(q query, t iterator) interface{} { + b := builderPool.Get().(stringBuilder) + for _, v := range args { + v = functionArgs(v) + + switch v := v.Evaluate(t).(type) { + case string: + b.WriteString(v) + case query: + node := v.Select(t) + if node != nil { + b.WriteString(node.Value()) + } + } + } + result := b.String() + b.Reset() + builderPool.Put(b) + + return result + } +} + +// https://github.com/antchfx/xpath/issues/43 +func functionArgs(q query) query { + if _, ok := q.(*functionQuery); ok { + return q + } + return q.Clone() +} + +func reverseFunc(q query, t iterator) func() NodeNavigator { + var list []NodeNavigator + for { + node := q.Select(t) + if node == nil { + break + } + list = append(list, node.Copy()) + } + i := len(list) + return func() NodeNavigator { + if i <= 0 { + return nil + } + i-- + node := list[i] + return node + } +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_go110.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_go110.go new file mode 100644 index 000000000..6df30d3d7 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_go110.go @@ -0,0 +1,16 @@ +// +build go1.10 + +package xpath + +import ( + "math" + "strings" +) + +func round(f float64) int { + return int(math.Round(f)) +} + +func newStringBuilder() stringBuilder{ + return &strings.Builder{} +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_pre_go110.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_pre_go110.go new file mode 100644 index 000000000..335141f79 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/func_pre_go110.go @@ -0,0 +1,22 @@ +// +build !go1.10 + +package xpath + +import ( + "bytes" + "math" +) + +// math.Round() is supported by Go 1.10+, +// This method just compatible for version <1.10. +// https://github.com/golang/go/issues/20100 +func round(f float64) int { + if math.Abs(f) < 0.5 { + return 0 + } + return int(f + math.Copysign(0.5, f)) +} + +func newStringBuilder() stringBuilder { + return &bytes.Buffer{} +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/operator.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/operator.go new file mode 100644 index 000000000..8c2f31f86 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/operator.go @@ -0,0 +1,305 @@ +package xpath + +import ( + "fmt" + "reflect" + "strconv" +) + +// The XPath number operator function list. + +// valueType is a return value type. +type valueType int + +const ( + booleanType valueType = iota + numberType + stringType + nodeSetType +) + +func getValueType(i interface{}) valueType { + v := reflect.ValueOf(i) + switch v.Kind() { + case reflect.Float64: + return numberType + case reflect.String: + return stringType + case reflect.Bool: + return booleanType + default: + if _, ok := i.(query); ok { + return nodeSetType + } + } + panic(fmt.Errorf("xpath unknown value type: %v", v.Kind())) +} + +type logical func(iterator, string, interface{}, interface{}) bool + +var logicalFuncs = [][]logical{ + {cmpBooleanBoolean, nil, nil, nil}, + {nil, cmpNumericNumeric, cmpNumericString, cmpNumericNodeSet}, + {nil, cmpStringNumeric, cmpStringString, cmpStringNodeSet}, + {nil, cmpNodeSetNumeric, cmpNodeSetString, cmpNodeSetNodeSet}, +} + +// number vs number +func cmpNumberNumberF(op string, a, b float64) bool { + switch op { + case "=": + return a == b + case ">": + return a > b + case "<": + return a < b + case ">=": + return a >= b + case "<=": + return a <= b + case "!=": + return a != b + } + return false +} + +// string vs string +func cmpStringStringF(op string, a, b string) bool { + switch op { + case "=": + return a == b + case ">": + return a > b + case "<": + return a < b + case ">=": + return a >= b + case "<=": + return a <= b + case "!=": + return a != b + } + return false +} + +func cmpBooleanBooleanF(op string, a, b bool) bool { + switch op { + case "or": + return a || b + case "and": + return a && b + } + return false +} + +func cmpNumericNumeric(t iterator, op string, m, n interface{}) bool { + a := m.(float64) + b := n.(float64) + return cmpNumberNumberF(op, a, b) +} + +func cmpNumericString(t iterator, op string, m, n interface{}) bool { + a := m.(float64) + b := n.(string) + num, err := strconv.ParseFloat(b, 64) + if err != nil { + panic(err) + } + return cmpNumberNumberF(op, a, num) +} + +func cmpNumericNodeSet(t iterator, op string, m, n interface{}) bool { + a := m.(float64) + b := n.(query) + + for { + node := b.Select(t) + if node == nil { + break + } + num, err := strconv.ParseFloat(node.Value(), 64) + if err != nil { + panic(err) + } + if cmpNumberNumberF(op, a, num) { + return true + } + } + return false +} + +func cmpNodeSetNumeric(t iterator, op string, m, n interface{}) bool { + a := m.(query) + b := n.(float64) + for { + node := a.Select(t) + if node == nil { + break + } + num, err := strconv.ParseFloat(node.Value(), 64) + if err != nil { + panic(err) + } + if cmpNumberNumberF(op, num, b) { + return true + } + } + return false +} + +func cmpNodeSetString(t iterator, op string, m, n interface{}) bool { + a := m.(query) + b := n.(string) + for { + node := a.Select(t) + if node == nil { + break + } + if cmpStringStringF(op, b, node.Value()) { + return true + } + } + return false +} + +func cmpNodeSetNodeSet(t iterator, op string, m, n interface{}) bool { + a := m.(query) + b := n.(query) + x := a.Select(t) + if x == nil { + return false + } + y := b.Select(t) + if y == nil { + return false + } + return cmpStringStringF(op, x.Value(), y.Value()) +} + +func cmpStringNumeric(t iterator, op string, m, n interface{}) bool { + a := m.(string) + b := n.(float64) + num, err := strconv.ParseFloat(a, 64) + if err != nil { + panic(err) + } + return cmpNumberNumberF(op, b, num) +} + +func cmpStringString(t iterator, op string, m, n interface{}) bool { + a := m.(string) + b := n.(string) + return cmpStringStringF(op, a, b) +} + +func cmpStringNodeSet(t iterator, op string, m, n interface{}) bool { + a := m.(string) + b := n.(query) + for { + node := b.Select(t) + if node == nil { + break + } + if cmpStringStringF(op, a, node.Value()) { + return true + } + } + return false +} + +func cmpBooleanBoolean(t iterator, op string, m, n interface{}) bool { + a := m.(bool) + b := n.(bool) + return cmpBooleanBooleanF(op, a, b) +} + +// eqFunc is an `=` operator. +func eqFunc(t iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "=", m, n) +} + +// gtFunc is an `>` operator. +func gtFunc(t iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, ">", m, n) +} + +// geFunc is an `>=` operator. +func geFunc(t iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, ">=", m, n) +} + +// ltFunc is an `<` operator. +func ltFunc(t iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "<", m, n) +} + +// leFunc is an `<=` operator. +func leFunc(t iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "<=", m, n) +} + +// neFunc is an `!=` operator. +func neFunc(t iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "!=", m, n) +} + +// orFunc is an `or` operator. +var orFunc = func(t iterator, m, n interface{}) interface{} { + t1 := getValueType(m) + t2 := getValueType(n) + return logicalFuncs[t1][t2](t, "or", m, n) +} + +func numericExpr(m, n interface{}, cb func(float64, float64) float64) float64 { + typ := reflect.TypeOf(float64(0)) + a := reflect.ValueOf(m).Convert(typ) + b := reflect.ValueOf(n).Convert(typ) + return cb(a.Float(), b.Float()) +} + +// plusFunc is an `+` operator. +var plusFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return a + b + }) +} + +// minusFunc is an `-` operator. +var minusFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return a - b + }) +} + +// mulFunc is an `*` operator. +var mulFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return a * b + }) +} + +// divFunc is an `DIV` operator. +var divFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return a / b + }) +} + +// modFunc is an 'MOD' operator. +var modFunc = func(m, n interface{}) interface{} { + return numericExpr(m, n, func(a, b float64) float64 { + return float64(int(a) % int(b)) + }) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/parse.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/parse.go new file mode 100644 index 000000000..fb9abe312 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/parse.go @@ -0,0 +1,1186 @@ +package xpath + +import ( + "bytes" + "errors" + "fmt" + "strconv" + "unicode" +) + +// A XPath expression token type. +type itemType int + +const ( + itemComma itemType = iota // ',' + itemSlash // '/' + itemAt // '@' + itemDot // '.' + itemLParens // '(' + itemRParens // ')' + itemLBracket // '[' + itemRBracket // ']' + itemStar // '*' + itemPlus // '+' + itemMinus // '-' + itemEq // '=' + itemLt // '<' + itemGt // '>' + itemBang // '!' + itemDollar // '$' + itemApos // '\'' + itemQuote // '"' + itemUnion // '|' + itemNe // '!=' + itemLe // '<=' + itemGe // '>=' + itemAnd // '&&' + itemOr // '||' + itemDotDot // '..' + itemSlashSlash // '//' + itemName // XML Name + itemString // Quoted string constant + itemNumber // Number constant + itemAxe // Axe (like child::) + itemEOF // END +) + +// A node is an XPath node in the parse tree. +type node interface { + Type() nodeType +} + +// nodeType identifies the type of a parse tree node. +type nodeType int + +func (t nodeType) Type() nodeType { + return t +} + +const ( + nodeRoot nodeType = iota + nodeAxis + nodeFilter + nodeFunction + nodeOperator + nodeVariable + nodeConstantOperand +) + +type parser struct { + r *scanner + d int +} + +// newOperatorNode returns new operator node OperatorNode. +func newOperatorNode(op string, left, right node) node { + return &operatorNode{nodeType: nodeOperator, Op: op, Left: left, Right: right} +} + +// newOperand returns new constant operand node OperandNode. +func newOperandNode(v interface{}) node { + return &operandNode{nodeType: nodeConstantOperand, Val: v} +} + +// newAxisNode returns new axis node AxisNode. +func newAxisNode(axeTyp, localName, prefix, prop string, n node) node { + return &axisNode{ + nodeType: nodeAxis, + LocalName: localName, + Prefix: prefix, + AxeType: axeTyp, + Prop: prop, + Input: n, + } +} + +// newVariableNode returns new variable node VariableNode. +func newVariableNode(prefix, name string) node { + return &variableNode{nodeType: nodeVariable, Name: name, Prefix: prefix} +} + +// newFilterNode returns a new filter node FilterNode. +func newFilterNode(n, m node) node { + return &filterNode{nodeType: nodeFilter, Input: n, Condition: m} +} + +// newRootNode returns a root node. +func newRootNode(s string) node { + return &rootNode{nodeType: nodeRoot, slash: s} +} + +// newFunctionNode returns function call node. +func newFunctionNode(name, prefix string, args []node) node { + return &functionNode{nodeType: nodeFunction, Prefix: prefix, FuncName: name, Args: args} +} + +// testOp reports whether current item name is an operand op. +func testOp(r *scanner, op string) bool { + return r.typ == itemName && r.prefix == "" && r.name == op +} + +func isPrimaryExpr(r *scanner) bool { + switch r.typ { + case itemString, itemNumber, itemDollar, itemLParens: + return true + case itemName: + return r.canBeFunc && !isNodeType(r) + } + return false +} + +func isNodeType(r *scanner) bool { + switch r.name { + case "node", "text", "processing-instruction", "comment": + return r.prefix == "" + } + return false +} + +func isStep(item itemType) bool { + switch item { + case itemDot, itemDotDot, itemAt, itemAxe, itemStar, itemName: + return true + } + return false +} + +func checkItem(r *scanner, typ itemType) { + if r.typ != typ { + panic(fmt.Sprintf("%s has an invalid token", r.text)) + } +} + +// parseExpression parsing the expression with input node n. +func (p *parser) parseExpression(n node) node { + if p.d = p.d + 1; p.d > 200 { + panic("the xpath query is too complex(depth > 200)") + } + n = p.parseOrExpr(n) + p.d-- + return n +} + +// next scanning next item on forward. +func (p *parser) next() bool { + return p.r.nextItem() +} + +func (p *parser) skipItem(typ itemType) { + checkItem(p.r, typ) + p.next() +} + +// OrExpr ::= AndExpr | OrExpr 'or' AndExpr +func (p *parser) parseOrExpr(n node) node { + opnd := p.parseAndExpr(n) + for { + if !testOp(p.r, "or") { + break + } + p.next() + opnd = newOperatorNode("or", opnd, p.parseAndExpr(n)) + } + return opnd +} + +// AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr +func (p *parser) parseAndExpr(n node) node { + opnd := p.parseEqualityExpr(n) + for { + if !testOp(p.r, "and") { + break + } + p.next() + opnd = newOperatorNode("and", opnd, p.parseEqualityExpr(n)) + } + return opnd +} + +// EqualityExpr ::= RelationalExpr | EqualityExpr '=' RelationalExpr | EqualityExpr '!=' RelationalExpr +func (p *parser) parseEqualityExpr(n node) node { + opnd := p.parseRelationalExpr(n) +Loop: + for { + var op string + switch p.r.typ { + case itemEq: + op = "=" + case itemNe: + op = "!=" + default: + break Loop + } + p.next() + opnd = newOperatorNode(op, opnd, p.parseRelationalExpr(n)) + } + return opnd +} + +// RelationalExpr ::= AdditiveExpr | RelationalExpr '<' AdditiveExpr | RelationalExpr '>' AdditiveExpr +// | RelationalExpr '<=' AdditiveExpr +// | RelationalExpr '>=' AdditiveExpr +func (p *parser) parseRelationalExpr(n node) node { + opnd := p.parseAdditiveExpr(n) +Loop: + for { + var op string + switch p.r.typ { + case itemLt: + op = "<" + case itemGt: + op = ">" + case itemLe: + op = "<=" + case itemGe: + op = ">=" + default: + break Loop + } + p.next() + opnd = newOperatorNode(op, opnd, p.parseAdditiveExpr(n)) + } + return opnd +} + +// AdditiveExpr ::= MultiplicativeExpr | AdditiveExpr '+' MultiplicativeExpr | AdditiveExpr '-' MultiplicativeExpr +func (p *parser) parseAdditiveExpr(n node) node { + opnd := p.parseMultiplicativeExpr(n) +Loop: + for { + var op string + switch p.r.typ { + case itemPlus: + op = "+" + case itemMinus: + op = "-" + default: + break Loop + } + p.next() + opnd = newOperatorNode(op, opnd, p.parseMultiplicativeExpr(n)) + } + return opnd +} + +// MultiplicativeExpr ::= UnaryExpr | MultiplicativeExpr MultiplyOperator(*) UnaryExpr +// | MultiplicativeExpr 'div' UnaryExpr | MultiplicativeExpr 'mod' UnaryExpr +func (p *parser) parseMultiplicativeExpr(n node) node { + opnd := p.parseUnaryExpr(n) +Loop: + for { + var op string + if p.r.typ == itemStar { + op = "*" + } else if testOp(p.r, "div") || testOp(p.r, "mod") { + op = p.r.name + } else { + break Loop + } + p.next() + opnd = newOperatorNode(op, opnd, p.parseUnaryExpr(n)) + } + return opnd +} + +// UnaryExpr ::= UnionExpr | '-' UnaryExpr +func (p *parser) parseUnaryExpr(n node) node { + minus := false + // ignore '-' sequence + for p.r.typ == itemMinus { + p.next() + minus = !minus + } + opnd := p.parseUnionExpr(n) + if minus { + opnd = newOperatorNode("*", opnd, newOperandNode(float64(-1))) + } + return opnd +} + +// UnionExpr ::= PathExpr | UnionExpr '|' PathExpr +func (p *parser) parseUnionExpr(n node) node { + opnd := p.parsePathExpr(n) +Loop: + for { + if p.r.typ != itemUnion { + break Loop + } + p.next() + opnd2 := p.parsePathExpr(n) + // Checking the node type that must be is node set type? + opnd = newOperatorNode("|", opnd, opnd2) + } + return opnd +} + +// PathExpr ::= LocationPath | FilterExpr | FilterExpr '/' RelativeLocationPath | FilterExpr '//' RelativeLocationPath +func (p *parser) parsePathExpr(n node) node { + var opnd node + if isPrimaryExpr(p.r) { + opnd = p.parseFilterExpr(n) + switch p.r.typ { + case itemSlash: + p.next() + opnd = p.parseRelativeLocationPath(opnd) + case itemSlashSlash: + p.next() + opnd = p.parseRelativeLocationPath(newAxisNode("descendant-or-self", "", "", "", opnd)) + } + } else { + opnd = p.parseLocationPath(nil) + } + return opnd +} + +// FilterExpr ::= PrimaryExpr | FilterExpr Predicate +func (p *parser) parseFilterExpr(n node) node { + opnd := p.parsePrimaryExpr(n) + if p.r.typ == itemLBracket { + opnd = newFilterNode(opnd, p.parsePredicate(opnd)) + } + return opnd +} + +// Predicate ::= '[' PredicateExpr ']' +func (p *parser) parsePredicate(n node) node { + p.skipItem(itemLBracket) + opnd := p.parseExpression(n) + p.skipItem(itemRBracket) + return opnd +} + +// LocationPath ::= RelativeLocationPath | AbsoluteLocationPath +func (p *parser) parseLocationPath(n node) (opnd node) { + switch p.r.typ { + case itemSlash: + p.next() + opnd = newRootNode("/") + if isStep(p.r.typ) { + opnd = p.parseRelativeLocationPath(opnd) // ?? child:: or self ?? + } + case itemSlashSlash: + p.next() + opnd = newRootNode("//") + opnd = p.parseRelativeLocationPath(newAxisNode("descendant-or-self", "", "", "", opnd)) + default: + opnd = p.parseRelativeLocationPath(n) + } + return opnd +} + +// RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | AbbreviatedRelativeLocationPath +func (p *parser) parseRelativeLocationPath(n node) node { + opnd := n +Loop: + for { + opnd = p.parseStep(opnd) + switch p.r.typ { + case itemSlashSlash: + p.next() + opnd = newAxisNode("descendant-or-self", "", "", "", opnd) + case itemSlash: + p.next() + default: + break Loop + } + } + return opnd +} + +// Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep +func (p *parser) parseStep(n node) (opnd node) { + axeTyp := "child" // default axes value. + if p.r.typ == itemDot || p.r.typ == itemDotDot { + if p.r.typ == itemDot { + axeTyp = "self" + } else { + axeTyp = "parent" + } + p.next() + opnd = newAxisNode(axeTyp, "", "", "", n) + if p.r.typ != itemLBracket { + return opnd + } + } else { + switch p.r.typ { + case itemAt: + p.next() + axeTyp = "attribute" + case itemAxe: + axeTyp = p.r.name + p.next() + case itemLParens: + return p.parseSequence(n) + } + opnd = p.parseNodeTest(n, axeTyp) + } + for p.r.typ == itemLBracket { + opnd = newFilterNode(opnd, p.parsePredicate(opnd)) + } + return opnd +} + +// Expr ::= '(' Step ("," Step)* ')' +func (p *parser) parseSequence(n node) (opnd node) { + p.skipItem(itemLParens) + opnd = p.parseStep(n) + for { + if p.r.typ != itemComma { + break + } + p.next() + opnd2 := p.parseStep(n) + opnd = newOperatorNode("|", opnd, opnd2) + } + p.skipItem(itemRParens) + return opnd +} + +// NodeTest ::= NameTest | nodeType '(' ')' | 'processing-instruction' '(' Literal ')' +func (p *parser) parseNodeTest(n node, axeTyp string) (opnd node) { + switch p.r.typ { + case itemName: + if p.r.canBeFunc && isNodeType(p.r) { + var prop string + switch p.r.name { + case "comment", "text", "processing-instruction", "node": + prop = p.r.name + } + var name string + p.next() + p.skipItem(itemLParens) + if prop == "processing-instruction" && p.r.typ != itemRParens { + checkItem(p.r, itemString) + name = p.r.strval + p.next() + } + p.skipItem(itemRParens) + opnd = newAxisNode(axeTyp, name, "", prop, n) + } else { + prefix := p.r.prefix + name := p.r.name + p.next() + if p.r.name == "*" { + name = "" + } + opnd = newAxisNode(axeTyp, name, prefix, "", n) + } + case itemStar: + opnd = newAxisNode(axeTyp, "", "", "", n) + p.next() + default: + panic("expression must evaluate to a node-set") + } + return opnd +} + +// PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall +func (p *parser) parsePrimaryExpr(n node) (opnd node) { + switch p.r.typ { + case itemString: + opnd = newOperandNode(p.r.strval) + p.next() + case itemNumber: + opnd = newOperandNode(p.r.numval) + p.next() + case itemDollar: + p.next() + checkItem(p.r, itemName) + opnd = newVariableNode(p.r.prefix, p.r.name) + p.next() + case itemLParens: + p.next() + opnd = p.parseExpression(n) + p.skipItem(itemRParens) + case itemName: + if p.r.canBeFunc && !isNodeType(p.r) { + opnd = p.parseMethod(nil) + } + } + return opnd +} + +// FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument )* )? ')' +func (p *parser) parseMethod(n node) node { + var args []node + name := p.r.name + prefix := p.r.prefix + + p.skipItem(itemName) + p.skipItem(itemLParens) + if p.r.typ != itemRParens { + for { + args = append(args, p.parseExpression(n)) + if p.r.typ == itemRParens { + break + } + p.skipItem(itemComma) + } + } + p.skipItem(itemRParens) + return newFunctionNode(name, prefix, args) +} + +// Parse parsing the XPath express string expr and returns a tree node. +func parse(expr string) node { + r := &scanner{text: expr} + r.nextChar() + r.nextItem() + p := &parser{r: r} + return p.parseExpression(nil) +} + +// rootNode holds a top-level node of tree. +type rootNode struct { + nodeType + slash string +} + +func (r *rootNode) String() string { + return r.slash +} + +// operatorNode holds two Nodes operator. +type operatorNode struct { + nodeType + Op string + Left, Right node +} + +func (o *operatorNode) String() string { + return fmt.Sprintf("%v%s%v", o.Left, o.Op, o.Right) +} + +// axisNode holds a location step. +type axisNode struct { + nodeType + Input node + Prop string // node-test name.[comment|text|processing-instruction|node] + AxeType string // name of the axes.[attribute|ancestor|child|....] + LocalName string // local part name of node. + Prefix string // prefix name of node. +} + +func (a *axisNode) String() string { + var b bytes.Buffer + if a.AxeType != "" { + b.Write([]byte(a.AxeType + "::")) + } + if a.Prefix != "" { + b.Write([]byte(a.Prefix + ":")) + } + b.Write([]byte(a.LocalName)) + if a.Prop != "" { + b.Write([]byte("/" + a.Prop + "()")) + } + return b.String() +} + +// operandNode holds a constant operand. +type operandNode struct { + nodeType + Val interface{} +} + +func (o *operandNode) String() string { + return fmt.Sprintf("%v", o.Val) +} + +// filterNode holds a condition filter. +type filterNode struct { + nodeType + Input, Condition node +} + +func (f *filterNode) String() string { + return fmt.Sprintf("%s[%s]", f.Input, f.Condition) +} + +// variableNode holds a variable. +type variableNode struct { + nodeType + Name, Prefix string +} + +func (v *variableNode) String() string { + if v.Prefix == "" { + return v.Name + } + return fmt.Sprintf("%s:%s", v.Prefix, v.Name) +} + +// functionNode holds a function call. +type functionNode struct { + nodeType + Args []node + Prefix string + FuncName string // function name +} + +func (f *functionNode) String() string { + var b bytes.Buffer + // fun(arg1, ..., argn) + b.Write([]byte(f.FuncName)) + b.Write([]byte("(")) + for i, arg := range f.Args { + if i > 0 { + b.Write([]byte(",")) + } + b.Write([]byte(fmt.Sprintf("%s", arg))) + } + b.Write([]byte(")")) + return b.String() +} + +type scanner struct { + text, name, prefix string + + pos int + curr rune + typ itemType + strval string // text value at current pos + numval float64 // number value at current pos + canBeFunc bool +} + +func (s *scanner) nextChar() bool { + if s.pos >= len(s.text) { + s.curr = rune(0) + return false + } + s.curr = rune(s.text[s.pos]) + s.pos++ + return true +} + +func (s *scanner) nextItem() bool { + s.skipSpace() + switch s.curr { + case 0: + s.typ = itemEOF + return false + case ',', '@', '(', ')', '|', '*', '[', ']', '+', '-', '=', '#', '$': + s.typ = asItemType(s.curr) + s.nextChar() + case '<': + s.typ = itemLt + s.nextChar() + if s.curr == '=' { + s.typ = itemLe + s.nextChar() + } + case '>': + s.typ = itemGt + s.nextChar() + if s.curr == '=' { + s.typ = itemGe + s.nextChar() + } + case '!': + s.typ = itemBang + s.nextChar() + if s.curr == '=' { + s.typ = itemNe + s.nextChar() + } + case '.': + s.typ = itemDot + s.nextChar() + if s.curr == '.' { + s.typ = itemDotDot + s.nextChar() + } else if isDigit(s.curr) { + s.typ = itemNumber + s.numval = s.scanFraction() + } + case '/': + s.typ = itemSlash + s.nextChar() + if s.curr == '/' { + s.typ = itemSlashSlash + s.nextChar() + } + case '"', '\'': + s.typ = itemString + s.strval = s.scanString() + default: + if isDigit(s.curr) { + s.typ = itemNumber + s.numval = s.scanNumber() + } else if isName(s.curr) { + s.typ = itemName + s.name = s.scanName() + s.prefix = "" + // "foo:bar" is one itemem not three because it doesn't allow spaces in between + // We should distinct it from "foo::" and need process "foo ::" as well + if s.curr == ':' { + s.nextChar() + // can be "foo:bar" or "foo::" + if s.curr == ':' { + // "foo::" + s.nextChar() + s.typ = itemAxe + } else { // "foo:*", "foo:bar" or "foo: " + s.prefix = s.name + if s.curr == '*' { + s.nextChar() + s.name = "*" + } else if isName(s.curr) { + s.name = s.scanName() + } else { + panic(fmt.Sprintf("%s has an invalid qualified name.", s.text)) + } + } + } else { + s.skipSpace() + if s.curr == ':' { + s.nextChar() + // it can be "foo ::" or just "foo :" + if s.curr == ':' { + s.nextChar() + s.typ = itemAxe + } else { + panic(fmt.Sprintf("%s has an invalid qualified name.", s.text)) + } + } + } + s.skipSpace() + s.canBeFunc = s.curr == '(' + } else { + panic(fmt.Sprintf("%s has an invalid token.", s.text)) + } + } + return true +} + +func (s *scanner) skipSpace() { +Loop: + for { + if !unicode.IsSpace(s.curr) || !s.nextChar() { + break Loop + } + } +} + +func (s *scanner) scanFraction() float64 { + var ( + i = s.pos - 2 + c = 1 // '.' + ) + for isDigit(s.curr) { + s.nextChar() + c++ + } + v, err := strconv.ParseFloat(s.text[i:i+c], 64) + if err != nil { + panic(fmt.Errorf("xpath: scanFraction parse float got error: %v", err)) + } + return v +} + +func (s *scanner) scanNumber() float64 { + var ( + c int + i = s.pos - 1 + ) + for isDigit(s.curr) { + s.nextChar() + c++ + } + if s.curr == '.' { + s.nextChar() + c++ + for isDigit(s.curr) { + s.nextChar() + c++ + } + } + v, err := strconv.ParseFloat(s.text[i:i+c], 64) + if err != nil { + panic(fmt.Errorf("xpath: scanNumber parse float got error: %v", err)) + } + return v +} + +func (s *scanner) scanString() string { + var ( + c = 0 + end = s.curr + ) + s.nextChar() + i := s.pos - 1 + for s.curr != end { + if !s.nextChar() { + panic(errors.New("xpath: scanString got unclosed string")) + } + c++ + } + s.nextChar() + return s.text[i : i+c] +} + +func (s *scanner) scanName() string { + var ( + c int + i = s.pos - 1 + ) + for isName(s.curr) { + c++ + if !s.nextChar() { + break + } + } + return s.text[i : i+c] +} + +func isName(r rune) bool { + return string(r) != ":" && string(r) != "/" && + (unicode.Is(first, r) || unicode.Is(second, r) || string(r) == "*") +} + +func isDigit(r rune) bool { + return unicode.IsDigit(r) +} + +func asItemType(r rune) itemType { + switch r { + case ',': + return itemComma + case '@': + return itemAt + case '(': + return itemLParens + case ')': + return itemRParens + case '|': + return itemUnion + case '*': + return itemStar + case '[': + return itemLBracket + case ']': + return itemRBracket + case '+': + return itemPlus + case '-': + return itemMinus + case '=': + return itemEq + case '$': + return itemDollar + } + panic(fmt.Errorf("unknown item: %v", r)) +} + +var first = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x003A, 0x003A, 1}, + {0x0041, 0x005A, 1}, + {0x005F, 0x005F, 1}, + {0x0061, 0x007A, 1}, + {0x00C0, 0x00D6, 1}, + {0x00D8, 0x00F6, 1}, + {0x00F8, 0x00FF, 1}, + {0x0100, 0x0131, 1}, + {0x0134, 0x013E, 1}, + {0x0141, 0x0148, 1}, + {0x014A, 0x017E, 1}, + {0x0180, 0x01C3, 1}, + {0x01CD, 0x01F0, 1}, + {0x01F4, 0x01F5, 1}, + {0x01FA, 0x0217, 1}, + {0x0250, 0x02A8, 1}, + {0x02BB, 0x02C1, 1}, + {0x0386, 0x0386, 1}, + {0x0388, 0x038A, 1}, + {0x038C, 0x038C, 1}, + {0x038E, 0x03A1, 1}, + {0x03A3, 0x03CE, 1}, + {0x03D0, 0x03D6, 1}, + {0x03DA, 0x03E0, 2}, + {0x03E2, 0x03F3, 1}, + {0x0401, 0x040C, 1}, + {0x040E, 0x044F, 1}, + {0x0451, 0x045C, 1}, + {0x045E, 0x0481, 1}, + {0x0490, 0x04C4, 1}, + {0x04C7, 0x04C8, 1}, + {0x04CB, 0x04CC, 1}, + {0x04D0, 0x04EB, 1}, + {0x04EE, 0x04F5, 1}, + {0x04F8, 0x04F9, 1}, + {0x0531, 0x0556, 1}, + {0x0559, 0x0559, 1}, + {0x0561, 0x0586, 1}, + {0x05D0, 0x05EA, 1}, + {0x05F0, 0x05F2, 1}, + {0x0621, 0x063A, 1}, + {0x0641, 0x064A, 1}, + {0x0671, 0x06B7, 1}, + {0x06BA, 0x06BE, 1}, + {0x06C0, 0x06CE, 1}, + {0x06D0, 0x06D3, 1}, + {0x06D5, 0x06D5, 1}, + {0x06E5, 0x06E6, 1}, + {0x0905, 0x0939, 1}, + {0x093D, 0x093D, 1}, + {0x0958, 0x0961, 1}, + {0x0985, 0x098C, 1}, + {0x098F, 0x0990, 1}, + {0x0993, 0x09A8, 1}, + {0x09AA, 0x09B0, 1}, + {0x09B2, 0x09B2, 1}, + {0x09B6, 0x09B9, 1}, + {0x09DC, 0x09DD, 1}, + {0x09DF, 0x09E1, 1}, + {0x09F0, 0x09F1, 1}, + {0x0A05, 0x0A0A, 1}, + {0x0A0F, 0x0A10, 1}, + {0x0A13, 0x0A28, 1}, + {0x0A2A, 0x0A30, 1}, + {0x0A32, 0x0A33, 1}, + {0x0A35, 0x0A36, 1}, + {0x0A38, 0x0A39, 1}, + {0x0A59, 0x0A5C, 1}, + {0x0A5E, 0x0A5E, 1}, + {0x0A72, 0x0A74, 1}, + {0x0A85, 0x0A8B, 1}, + {0x0A8D, 0x0A8D, 1}, + {0x0A8F, 0x0A91, 1}, + {0x0A93, 0x0AA8, 1}, + {0x0AAA, 0x0AB0, 1}, + {0x0AB2, 0x0AB3, 1}, + {0x0AB5, 0x0AB9, 1}, + {0x0ABD, 0x0AE0, 0x23}, + {0x0B05, 0x0B0C, 1}, + {0x0B0F, 0x0B10, 1}, + {0x0B13, 0x0B28, 1}, + {0x0B2A, 0x0B30, 1}, + {0x0B32, 0x0B33, 1}, + {0x0B36, 0x0B39, 1}, + {0x0B3D, 0x0B3D, 1}, + {0x0B5C, 0x0B5D, 1}, + {0x0B5F, 0x0B61, 1}, + {0x0B85, 0x0B8A, 1}, + {0x0B8E, 0x0B90, 1}, + {0x0B92, 0x0B95, 1}, + {0x0B99, 0x0B9A, 1}, + {0x0B9C, 0x0B9C, 1}, + {0x0B9E, 0x0B9F, 1}, + {0x0BA3, 0x0BA4, 1}, + {0x0BA8, 0x0BAA, 1}, + {0x0BAE, 0x0BB5, 1}, + {0x0BB7, 0x0BB9, 1}, + {0x0C05, 0x0C0C, 1}, + {0x0C0E, 0x0C10, 1}, + {0x0C12, 0x0C28, 1}, + {0x0C2A, 0x0C33, 1}, + {0x0C35, 0x0C39, 1}, + {0x0C60, 0x0C61, 1}, + {0x0C85, 0x0C8C, 1}, + {0x0C8E, 0x0C90, 1}, + {0x0C92, 0x0CA8, 1}, + {0x0CAA, 0x0CB3, 1}, + {0x0CB5, 0x0CB9, 1}, + {0x0CDE, 0x0CDE, 1}, + {0x0CE0, 0x0CE1, 1}, + {0x0D05, 0x0D0C, 1}, + {0x0D0E, 0x0D10, 1}, + {0x0D12, 0x0D28, 1}, + {0x0D2A, 0x0D39, 1}, + {0x0D60, 0x0D61, 1}, + {0x0E01, 0x0E2E, 1}, + {0x0E30, 0x0E30, 1}, + {0x0E32, 0x0E33, 1}, + {0x0E40, 0x0E45, 1}, + {0x0E81, 0x0E82, 1}, + {0x0E84, 0x0E84, 1}, + {0x0E87, 0x0E88, 1}, + {0x0E8A, 0x0E8D, 3}, + {0x0E94, 0x0E97, 1}, + {0x0E99, 0x0E9F, 1}, + {0x0EA1, 0x0EA3, 1}, + {0x0EA5, 0x0EA7, 2}, + {0x0EAA, 0x0EAB, 1}, + {0x0EAD, 0x0EAE, 1}, + {0x0EB0, 0x0EB0, 1}, + {0x0EB2, 0x0EB3, 1}, + {0x0EBD, 0x0EBD, 1}, + {0x0EC0, 0x0EC4, 1}, + {0x0F40, 0x0F47, 1}, + {0x0F49, 0x0F69, 1}, + {0x10A0, 0x10C5, 1}, + {0x10D0, 0x10F6, 1}, + {0x1100, 0x1100, 1}, + {0x1102, 0x1103, 1}, + {0x1105, 0x1107, 1}, + {0x1109, 0x1109, 1}, + {0x110B, 0x110C, 1}, + {0x110E, 0x1112, 1}, + {0x113C, 0x1140, 2}, + {0x114C, 0x1150, 2}, + {0x1154, 0x1155, 1}, + {0x1159, 0x1159, 1}, + {0x115F, 0x1161, 1}, + {0x1163, 0x1169, 2}, + {0x116D, 0x116E, 1}, + {0x1172, 0x1173, 1}, + {0x1175, 0x119E, 0x119E - 0x1175}, + {0x11A8, 0x11AB, 0x11AB - 0x11A8}, + {0x11AE, 0x11AF, 1}, + {0x11B7, 0x11B8, 1}, + {0x11BA, 0x11BA, 1}, + {0x11BC, 0x11C2, 1}, + {0x11EB, 0x11F0, 0x11F0 - 0x11EB}, + {0x11F9, 0x11F9, 1}, + {0x1E00, 0x1E9B, 1}, + {0x1EA0, 0x1EF9, 1}, + {0x1F00, 0x1F15, 1}, + {0x1F18, 0x1F1D, 1}, + {0x1F20, 0x1F45, 1}, + {0x1F48, 0x1F4D, 1}, + {0x1F50, 0x1F57, 1}, + {0x1F59, 0x1F5B, 0x1F5B - 0x1F59}, + {0x1F5D, 0x1F5D, 1}, + {0x1F5F, 0x1F7D, 1}, + {0x1F80, 0x1FB4, 1}, + {0x1FB6, 0x1FBC, 1}, + {0x1FBE, 0x1FBE, 1}, + {0x1FC2, 0x1FC4, 1}, + {0x1FC6, 0x1FCC, 1}, + {0x1FD0, 0x1FD3, 1}, + {0x1FD6, 0x1FDB, 1}, + {0x1FE0, 0x1FEC, 1}, + {0x1FF2, 0x1FF4, 1}, + {0x1FF6, 0x1FFC, 1}, + {0x2126, 0x2126, 1}, + {0x212A, 0x212B, 1}, + {0x212E, 0x212E, 1}, + {0x2180, 0x2182, 1}, + {0x3007, 0x3007, 1}, + {0x3021, 0x3029, 1}, + {0x3041, 0x3094, 1}, + {0x30A1, 0x30FA, 1}, + {0x3105, 0x312C, 1}, + {0x4E00, 0x9FA5, 1}, + {0xAC00, 0xD7A3, 1}, + }, +} + +var second = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x002D, 0x002E, 1}, + {0x0030, 0x0039, 1}, + {0x00B7, 0x00B7, 1}, + {0x02D0, 0x02D1, 1}, + {0x0300, 0x0345, 1}, + {0x0360, 0x0361, 1}, + {0x0387, 0x0387, 1}, + {0x0483, 0x0486, 1}, + {0x0591, 0x05A1, 1}, + {0x05A3, 0x05B9, 1}, + {0x05BB, 0x05BD, 1}, + {0x05BF, 0x05BF, 1}, + {0x05C1, 0x05C2, 1}, + {0x05C4, 0x0640, 0x0640 - 0x05C4}, + {0x064B, 0x0652, 1}, + {0x0660, 0x0669, 1}, + {0x0670, 0x0670, 1}, + {0x06D6, 0x06DC, 1}, + {0x06DD, 0x06DF, 1}, + {0x06E0, 0x06E4, 1}, + {0x06E7, 0x06E8, 1}, + {0x06EA, 0x06ED, 1}, + {0x06F0, 0x06F9, 1}, + {0x0901, 0x0903, 1}, + {0x093C, 0x093C, 1}, + {0x093E, 0x094C, 1}, + {0x094D, 0x094D, 1}, + {0x0951, 0x0954, 1}, + {0x0962, 0x0963, 1}, + {0x0966, 0x096F, 1}, + {0x0981, 0x0983, 1}, + {0x09BC, 0x09BC, 1}, + {0x09BE, 0x09BF, 1}, + {0x09C0, 0x09C4, 1}, + {0x09C7, 0x09C8, 1}, + {0x09CB, 0x09CD, 1}, + {0x09D7, 0x09D7, 1}, + {0x09E2, 0x09E3, 1}, + {0x09E6, 0x09EF, 1}, + {0x0A02, 0x0A3C, 0x3A}, + {0x0A3E, 0x0A3F, 1}, + {0x0A40, 0x0A42, 1}, + {0x0A47, 0x0A48, 1}, + {0x0A4B, 0x0A4D, 1}, + {0x0A66, 0x0A6F, 1}, + {0x0A70, 0x0A71, 1}, + {0x0A81, 0x0A83, 1}, + {0x0ABC, 0x0ABC, 1}, + {0x0ABE, 0x0AC5, 1}, + {0x0AC7, 0x0AC9, 1}, + {0x0ACB, 0x0ACD, 1}, + {0x0AE6, 0x0AEF, 1}, + {0x0B01, 0x0B03, 1}, + {0x0B3C, 0x0B3C, 1}, + {0x0B3E, 0x0B43, 1}, + {0x0B47, 0x0B48, 1}, + {0x0B4B, 0x0B4D, 1}, + {0x0B56, 0x0B57, 1}, + {0x0B66, 0x0B6F, 1}, + {0x0B82, 0x0B83, 1}, + {0x0BBE, 0x0BC2, 1}, + {0x0BC6, 0x0BC8, 1}, + {0x0BCA, 0x0BCD, 1}, + {0x0BD7, 0x0BD7, 1}, + {0x0BE7, 0x0BEF, 1}, + {0x0C01, 0x0C03, 1}, + {0x0C3E, 0x0C44, 1}, + {0x0C46, 0x0C48, 1}, + {0x0C4A, 0x0C4D, 1}, + {0x0C55, 0x0C56, 1}, + {0x0C66, 0x0C6F, 1}, + {0x0C82, 0x0C83, 1}, + {0x0CBE, 0x0CC4, 1}, + {0x0CC6, 0x0CC8, 1}, + {0x0CCA, 0x0CCD, 1}, + {0x0CD5, 0x0CD6, 1}, + {0x0CE6, 0x0CEF, 1}, + {0x0D02, 0x0D03, 1}, + {0x0D3E, 0x0D43, 1}, + {0x0D46, 0x0D48, 1}, + {0x0D4A, 0x0D4D, 1}, + {0x0D57, 0x0D57, 1}, + {0x0D66, 0x0D6F, 1}, + {0x0E31, 0x0E31, 1}, + {0x0E34, 0x0E3A, 1}, + {0x0E46, 0x0E46, 1}, + {0x0E47, 0x0E4E, 1}, + {0x0E50, 0x0E59, 1}, + {0x0EB1, 0x0EB1, 1}, + {0x0EB4, 0x0EB9, 1}, + {0x0EBB, 0x0EBC, 1}, + {0x0EC6, 0x0EC6, 1}, + {0x0EC8, 0x0ECD, 1}, + {0x0ED0, 0x0ED9, 1}, + {0x0F18, 0x0F19, 1}, + {0x0F20, 0x0F29, 1}, + {0x0F35, 0x0F39, 2}, + {0x0F3E, 0x0F3F, 1}, + {0x0F71, 0x0F84, 1}, + {0x0F86, 0x0F8B, 1}, + {0x0F90, 0x0F95, 1}, + {0x0F97, 0x0F97, 1}, + {0x0F99, 0x0FAD, 1}, + {0x0FB1, 0x0FB7, 1}, + {0x0FB9, 0x0FB9, 1}, + {0x20D0, 0x20DC, 1}, + {0x20E1, 0x3005, 0x3005 - 0x20E1}, + {0x302A, 0x302F, 1}, + {0x3031, 0x3035, 1}, + {0x3099, 0x309A, 1}, + {0x309D, 0x309E, 1}, + {0x30FC, 0x30FE, 1}, + }, +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/query.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/query.go new file mode 100644 index 000000000..47f8076e7 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/query.go @@ -0,0 +1,923 @@ +package xpath + +import ( + "bytes" + "fmt" + "hash/fnv" + "reflect" +) + +type iterator interface { + Current() NodeNavigator +} + +// An XPath query interface. +type query interface { + // Select traversing iterator returns a query matched node NodeNavigator. + Select(iterator) NodeNavigator + + // Evaluate evaluates query and returns values of the current query. + Evaluate(iterator) interface{} + + Clone() query +} + +// nopQuery is an empty query that always return nil for any query. +type nopQuery struct { + query +} + +func (nopQuery) Select(iterator) NodeNavigator { return nil } + +func (nopQuery) Evaluate(iterator) interface{} { return nil } + +func (nopQuery) Clone() query { return nopQuery{} } + +// contextQuery is returns current node on the iterator object query. +type contextQuery struct { + count int + Root bool // Moving to root-level node in the current context iterator. +} + +func (c *contextQuery) Select(t iterator) (n NodeNavigator) { + if c.count == 0 { + c.count++ + n = t.Current().Copy() + if c.Root { + n.MoveToRoot() + } + } + return n +} + +func (c *contextQuery) Evaluate(iterator) interface{} { + c.count = 0 + return c +} + +func (c *contextQuery) Clone() query { + return &contextQuery{count: 0, Root: c.Root} +} + +// ancestorQuery is an XPath ancestor node query.(ancestor::*|ancestor-self::*) +type ancestorQuery struct { + iterator func() NodeNavigator + + Self bool + Input query + Predicate func(NodeNavigator) bool +} + +func (a *ancestorQuery) Select(t iterator) NodeNavigator { + for { + if a.iterator == nil { + node := a.Input.Select(t) + if node == nil { + return nil + } + first := true + node = node.Copy() + a.iterator = func() NodeNavigator { + if first && a.Self { + first = false + if a.Predicate(node) { + return node + } + } + for node.MoveToParent() { + if !a.Predicate(node) { + continue + } + return node + } + return nil + } + } + + if node := a.iterator(); node != nil { + return node + } + a.iterator = nil + } +} + +func (a *ancestorQuery) Evaluate(t iterator) interface{} { + a.Input.Evaluate(t) + a.iterator = nil + return a +} + +func (a *ancestorQuery) Test(n NodeNavigator) bool { + return a.Predicate(n) +} + +func (a *ancestorQuery) Clone() query { + return &ancestorQuery{Self: a.Self, Input: a.Input.Clone(), Predicate: a.Predicate} +} + +// attributeQuery is an XPath attribute node query.(@*) +type attributeQuery struct { + iterator func() NodeNavigator + + Input query + Predicate func(NodeNavigator) bool +} + +func (a *attributeQuery) Select(t iterator) NodeNavigator { + for { + if a.iterator == nil { + node := a.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + a.iterator = func() NodeNavigator { + for { + onAttr := node.MoveToNextAttribute() + if !onAttr { + return nil + } + if a.Predicate(node) { + return node + } + } + } + } + + if node := a.iterator(); node != nil { + return node + } + a.iterator = nil + } +} + +func (a *attributeQuery) Evaluate(t iterator) interface{} { + a.Input.Evaluate(t) + a.iterator = nil + return a +} + +func (a *attributeQuery) Test(n NodeNavigator) bool { + return a.Predicate(n) +} + +func (a *attributeQuery) Clone() query { + return &attributeQuery{Input: a.Input.Clone(), Predicate: a.Predicate} +} + +// childQuery is an XPath child node query.(child::*) +type childQuery struct { + posit int + iterator func() NodeNavigator + + Input query + Predicate func(NodeNavigator) bool +} + +func (c *childQuery) Select(t iterator) NodeNavigator { + for { + if c.iterator == nil { + c.posit = 0 + node := c.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + first := true + c.iterator = func() NodeNavigator { + for { + if (first && !node.MoveToChild()) || (!first && !node.MoveToNext()) { + return nil + } + first = false + if c.Predicate(node) { + return node + } + } + } + } + + if node := c.iterator(); node != nil { + c.posit++ + return node + } + c.iterator = nil + } +} + +func (c *childQuery) Evaluate(t iterator) interface{} { + c.Input.Evaluate(t) + c.iterator = nil + return c +} + +func (c *childQuery) Test(n NodeNavigator) bool { + return c.Predicate(n) +} + +func (c *childQuery) Clone() query { + return &childQuery{Input: c.Input.Clone(), Predicate: c.Predicate} +} + +// position returns a position of current NodeNavigator. +func (c *childQuery) position() int { + return c.posit +} + +// descendantQuery is an XPath descendant node query.(descendant::* | descendant-or-self::*) +type descendantQuery struct { + iterator func() NodeNavigator + posit int + level int + + Self bool + Input query + Predicate func(NodeNavigator) bool +} + +func (d *descendantQuery) Select(t iterator) NodeNavigator { + for { + if d.iterator == nil { + d.posit = 0 + node := d.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + d.level = 0 + positmap := make(map[int]int) + first := true + d.iterator = func() NodeNavigator { + if first && d.Self { + first = false + if d.Predicate(node) { + d.posit = 1 + positmap[d.level] = 1 + return node + } + } + + for { + if node.MoveToChild() { + d.level = d.level + 1 + positmap[d.level] = 0 + } else { + for { + if d.level == 0 { + return nil + } + if node.MoveToNext() { + break + } + node.MoveToParent() + d.level = d.level - 1 + } + } + if d.Predicate(node) { + positmap[d.level]++ + d.posit = positmap[d.level] + return node + } + } + } + } + + if node := d.iterator(); node != nil { + return node + } + d.iterator = nil + } +} + +func (d *descendantQuery) Evaluate(t iterator) interface{} { + d.Input.Evaluate(t) + d.iterator = nil + return d +} + +func (d *descendantQuery) Test(n NodeNavigator) bool { + return d.Predicate(n) +} + +// position returns a position of current NodeNavigator. +func (d *descendantQuery) position() int { + return d.posit +} + +func (d *descendantQuery) depth() int { + return d.level +} + +func (d *descendantQuery) Clone() query { + return &descendantQuery{Self: d.Self, Input: d.Input.Clone(), Predicate: d.Predicate} +} + +// followingQuery is an XPath following node query.(following::*|following-sibling::*) +type followingQuery struct { + posit int + iterator func() NodeNavigator + + Input query + Sibling bool // The matching sibling node of current node. + Predicate func(NodeNavigator) bool +} + +func (f *followingQuery) Select(t iterator) NodeNavigator { + for { + if f.iterator == nil { + f.posit = 0 + node := f.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + if f.Sibling { + f.iterator = func() NodeNavigator { + for { + if !node.MoveToNext() { + return nil + } + if f.Predicate(node) { + f.posit++ + return node + } + } + } + } else { + var q *descendantQuery // descendant query + f.iterator = func() NodeNavigator { + for { + if q == nil { + for !node.MoveToNext() { + if !node.MoveToParent() { + return nil + } + } + q = &descendantQuery{ + Self: true, + Input: &contextQuery{}, + Predicate: f.Predicate, + } + t.Current().MoveTo(node) + } + if node := q.Select(t); node != nil { + f.posit = q.posit + return node + } + q = nil + } + } + } + } + + if node := f.iterator(); node != nil { + return node + } + f.iterator = nil + } +} + +func (f *followingQuery) Evaluate(t iterator) interface{} { + f.Input.Evaluate(t) + return f +} + +func (f *followingQuery) Test(n NodeNavigator) bool { + return f.Predicate(n) +} + +func (f *followingQuery) Clone() query { + return &followingQuery{Input: f.Input.Clone(), Sibling: f.Sibling, Predicate: f.Predicate} +} + +func (f *followingQuery) position() int { + return f.posit +} + +// precedingQuery is an XPath preceding node query.(preceding::*) +type precedingQuery struct { + iterator func() NodeNavigator + posit int + Input query + Sibling bool // The matching sibling node of current node. + Predicate func(NodeNavigator) bool +} + +func (p *precedingQuery) Select(t iterator) NodeNavigator { + for { + if p.iterator == nil { + p.posit = 0 + node := p.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + if p.Sibling { + p.iterator = func() NodeNavigator { + for { + for !node.MoveToPrevious() { + return nil + } + if p.Predicate(node) { + p.posit++ + return node + } + } + } + } else { + var q query + p.iterator = func() NodeNavigator { + for { + if q == nil { + for !node.MoveToPrevious() { + if !node.MoveToParent() { + return nil + } + p.posit = 0 + } + q = &descendantQuery{ + Self: true, + Input: &contextQuery{}, + Predicate: p.Predicate, + } + t.Current().MoveTo(node) + } + if node := q.Select(t); node != nil { + p.posit++ + return node + } + q = nil + } + } + } + } + if node := p.iterator(); node != nil { + return node + } + p.iterator = nil + } +} + +func (p *precedingQuery) Evaluate(t iterator) interface{} { + p.Input.Evaluate(t) + return p +} + +func (p *precedingQuery) Test(n NodeNavigator) bool { + return p.Predicate(n) +} + +func (p *precedingQuery) Clone() query { + return &precedingQuery{Input: p.Input.Clone(), Sibling: p.Sibling, Predicate: p.Predicate} +} + +func (p *precedingQuery) position() int { + return p.posit +} + +// parentQuery is an XPath parent node query.(parent::*) +type parentQuery struct { + Input query + Predicate func(NodeNavigator) bool +} + +func (p *parentQuery) Select(t iterator) NodeNavigator { + for { + node := p.Input.Select(t) + if node == nil { + return nil + } + node = node.Copy() + if node.MoveToParent() && p.Predicate(node) { + return node + } + } +} + +func (p *parentQuery) Evaluate(t iterator) interface{} { + p.Input.Evaluate(t) + return p +} + +func (p *parentQuery) Clone() query { + return &parentQuery{Input: p.Input.Clone(), Predicate: p.Predicate} +} + +func (p *parentQuery) Test(n NodeNavigator) bool { + return p.Predicate(n) +} + +// selfQuery is an Self node query.(self::*) +type selfQuery struct { + Input query + Predicate func(NodeNavigator) bool +} + +func (s *selfQuery) Select(t iterator) NodeNavigator { + for { + node := s.Input.Select(t) + if node == nil { + return nil + } + + if s.Predicate(node) { + return node + } + } +} + +func (s *selfQuery) Evaluate(t iterator) interface{} { + s.Input.Evaluate(t) + return s +} + +func (s *selfQuery) Test(n NodeNavigator) bool { + return s.Predicate(n) +} + +func (s *selfQuery) Clone() query { + return &selfQuery{Input: s.Input.Clone(), Predicate: s.Predicate} +} + +// filterQuery is an XPath query for predicate filter. +type filterQuery struct { + Input query + Predicate query + posit int + positmap map[int]int +} + +func (f *filterQuery) do(t iterator) bool { + val := reflect.ValueOf(f.Predicate.Evaluate(t)) + switch val.Kind() { + case reflect.Bool: + return val.Bool() + case reflect.String: + return len(val.String()) > 0 + case reflect.Float64: + pt := getNodePosition(f.Input) + return int(val.Float()) == pt + default: + if q, ok := f.Predicate.(query); ok { + return q.Select(t) != nil + } + } + return false +} + +func (f *filterQuery) position() int { + return f.posit +} + +func (f *filterQuery) Select(t iterator) NodeNavigator { + if f.positmap == nil { + f.positmap = make(map[int]int) + } + for { + + node := f.Input.Select(t) + if node == nil { + return node + } + node = node.Copy() + + t.Current().MoveTo(node) + if f.do(t) { + // fix https://github.com/antchfx/htmlquery/issues/26 + // Calculate and keep the each of matching node's position in the same depth. + level := getNodeDepth(f.Input) + f.positmap[level]++ + f.posit = f.positmap[level] + return node + } + } +} + +func (f *filterQuery) Evaluate(t iterator) interface{} { + f.Input.Evaluate(t) + return f +} + +func (f *filterQuery) Clone() query { + return &filterQuery{Input: f.Input.Clone(), Predicate: f.Predicate.Clone()} +} + +// functionQuery is an XPath function that returns a computed value for +// the Evaluate call of the current NodeNavigator node. Select call isn't +// applicable for functionQuery. +type functionQuery struct { + Input query // Node Set + Func func(query, iterator) interface{} // The xpath function. +} + +func (f *functionQuery) Select(t iterator) NodeNavigator { + return nil +} + +// Evaluate call a specified function that will returns the +// following value type: number,string,boolean. +func (f *functionQuery) Evaluate(t iterator) interface{} { + return f.Func(f.Input, t) +} + +func (f *functionQuery) Clone() query { + return &functionQuery{Input: f.Input.Clone(), Func: f.Func} +} + +// transformFunctionQuery diffs from functionQuery where the latter computes a scalar +// value (number,string,boolean) for the current NodeNavigator node while the former +// (transformFunctionQuery) performs a mapping or transform of the current NodeNavigator +// and returns a new NodeNavigator. It is used for non-scalar XPath functions such as +// reverse(), remove(), subsequence(), unordered(), etc. +type transformFunctionQuery struct { + Input query + Func func(query, iterator) func() NodeNavigator + iterator func() NodeNavigator +} + +func (f *transformFunctionQuery) Select(t iterator) NodeNavigator { + if f.iterator == nil { + f.iterator = f.Func(f.Input, t) + } + return f.iterator() +} + +func (f *transformFunctionQuery) Evaluate(t iterator) interface{} { + f.Input.Evaluate(t) + f.iterator = nil + return f +} + +func (f *transformFunctionQuery) Clone() query { + return &transformFunctionQuery{Input: f.Input.Clone(), Func: f.Func} +} + +// constantQuery is an XPath constant operand. +type constantQuery struct { + Val interface{} +} + +func (c *constantQuery) Select(t iterator) NodeNavigator { + return nil +} + +func (c *constantQuery) Evaluate(t iterator) interface{} { + return c.Val +} + +func (c *constantQuery) Clone() query { + return c +} + +// logicalQuery is an XPath logical expression. +type logicalQuery struct { + Left, Right query + + Do func(iterator, interface{}, interface{}) interface{} +} + +func (l *logicalQuery) Select(t iterator) NodeNavigator { + // When a XPath expr is logical expression. + node := t.Current().Copy() + val := l.Evaluate(t) + switch val.(type) { + case bool: + if val.(bool) == true { + return node + } + } + return nil +} + +func (l *logicalQuery) Evaluate(t iterator) interface{} { + m := l.Left.Evaluate(t) + n := l.Right.Evaluate(t) + return l.Do(t, m, n) +} + +func (l *logicalQuery) Clone() query { + return &logicalQuery{Left: l.Left.Clone(), Right: l.Right.Clone(), Do: l.Do} +} + +// numericQuery is an XPath numeric operator expression. +type numericQuery struct { + Left, Right query + + Do func(interface{}, interface{}) interface{} +} + +func (n *numericQuery) Select(t iterator) NodeNavigator { + return nil +} + +func (n *numericQuery) Evaluate(t iterator) interface{} { + m := n.Left.Evaluate(t) + k := n.Right.Evaluate(t) + return n.Do(m, k) +} + +func (n *numericQuery) Clone() query { + return &numericQuery{Left: n.Left.Clone(), Right: n.Right.Clone(), Do: n.Do} +} + +type booleanQuery struct { + IsOr bool + Left, Right query + iterator func() NodeNavigator +} + +func (b *booleanQuery) Select(t iterator) NodeNavigator { + if b.iterator == nil { + var list []NodeNavigator + i := 0 + root := t.Current().Copy() + if b.IsOr { + for { + node := b.Left.Select(t) + if node == nil { + break + } + node = node.Copy() + list = append(list, node) + } + t.Current().MoveTo(root) + for { + node := b.Right.Select(t) + if node == nil { + break + } + node = node.Copy() + list = append(list, node) + } + } else { + var m []NodeNavigator + var n []NodeNavigator + for { + node := b.Left.Select(t) + if node == nil { + break + } + node = node.Copy() + list = append(m, node) + } + t.Current().MoveTo(root) + for { + node := b.Right.Select(t) + if node == nil { + break + } + node = node.Copy() + list = append(n, node) + } + for _, k := range m { + for _, j := range n { + if k == j { + list = append(list, k) + } + } + } + } + + b.iterator = func() NodeNavigator { + if i >= len(list) { + return nil + } + node := list[i] + i++ + return node + } + } + return b.iterator() +} + +func (b *booleanQuery) Evaluate(t iterator) interface{} { + m := b.Left.Evaluate(t) + left := asBool(t, m) + if b.IsOr && left { + return true + } else if !b.IsOr && !left { + return false + } + m = b.Right.Evaluate(t) + return asBool(t, m) +} + +func (b *booleanQuery) Clone() query { + return &booleanQuery{IsOr: b.IsOr, Left: b.Left.Clone(), Right: b.Right.Clone()} +} + +type unionQuery struct { + Left, Right query + iterator func() NodeNavigator +} + +func (u *unionQuery) Select(t iterator) NodeNavigator { + if u.iterator == nil { + var list []NodeNavigator + var m = make(map[uint64]bool) + root := t.Current().Copy() + for { + node := u.Left.Select(t) + if node == nil { + break + } + code := getHashCode(node.Copy()) + if _, ok := m[code]; !ok { + m[code] = true + list = append(list, node.Copy()) + } + } + t.Current().MoveTo(root) + for { + node := u.Right.Select(t) + if node == nil { + break + } + code := getHashCode(node.Copy()) + if _, ok := m[code]; !ok { + m[code] = true + list = append(list, node.Copy()) + } + } + var i int + u.iterator = func() NodeNavigator { + if i >= len(list) { + return nil + } + node := list[i] + i++ + return node + } + } + return u.iterator() +} + +func (u *unionQuery) Evaluate(t iterator) interface{} { + u.iterator = nil + u.Left.Evaluate(t) + u.Right.Evaluate(t) + return u +} + +func (u *unionQuery) Clone() query { + return &unionQuery{Left: u.Left.Clone(), Right: u.Right.Clone()} +} + +func getHashCode(n NodeNavigator) uint64 { + var sb bytes.Buffer + switch n.NodeType() { + case AttributeNode, TextNode, CommentNode: + sb.WriteString(fmt.Sprintf("%s=%s", n.LocalName(), n.Value())) + // https://github.com/antchfx/htmlquery/issues/25 + d := 1 + for n.MoveToPrevious() { + d++ + } + sb.WriteString(fmt.Sprintf("-%d", d)) + for n.MoveToParent() { + d = 1 + for n.MoveToPrevious() { + d++ + } + sb.WriteString(fmt.Sprintf("-%d", d)) + } + case ElementNode: + sb.WriteString(n.Prefix() + n.LocalName()) + d := 1 + for n.MoveToPrevious() { + d++ + } + sb.WriteString(fmt.Sprintf("-%d", d)) + + for n.MoveToParent() { + d = 1 + for n.MoveToPrevious() { + d++ + } + sb.WriteString(fmt.Sprintf("-%d", d)) + } + } + h := fnv.New64a() + h.Write([]byte(sb.String())) + return h.Sum64() +} + +func getNodePosition(q query) int { + type Position interface { + position() int + } + if count, ok := q.(Position); ok { + return count.position() + } + return 1 +} + +func getNodeDepth(q query) int { + type Depth interface { + depth() int + } + if count, ok := q.(Depth); ok { + return count.depth() + } + return 0 +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/stub.go deleted file mode 100644 index d470abbed..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/stub.go +++ /dev/null @@ -1,64 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/antchfx/xpath, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/antchfx/xpath (exports: ; functions: Compile,MustCompile,Select) - -// Package xpath is a stub of github.com/antchfx/xpath, generated by depstubber. -package xpath - -import () - -func Compile(_ string) (*Expr, error) { - return nil, nil -} - -type Expr struct{} - -func (_ *Expr) Evaluate(_ NodeNavigator) interface{} { - return nil -} - -func (_ *Expr) Select(_ NodeNavigator) *NodeIterator { - return nil -} - -func (_ *Expr) String() string { - return "" -} - -func MustCompile(_ string) *Expr { - return nil -} - -type NodeIterator struct{} - -func (_ *NodeIterator) Current() NodeNavigator { - return nil -} - -func (_ *NodeIterator) MoveNext() bool { - return false -} - -type NodeNavigator interface { - Copy() NodeNavigator - LocalName() string - MoveTo(_ NodeNavigator) bool - MoveToChild() bool - MoveToFirst() bool - MoveToNext() bool - MoveToNextAttribute() bool - MoveToParent() bool - MoveToPrevious() bool - MoveToRoot() - NodeType() NodeType - Prefix() string - Value() string -} - -type NodeType int - -func Select(_ NodeNavigator, _ string) *NodeIterator { - return nil -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/xpath.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/xpath.go new file mode 100644 index 000000000..5f6aa89a1 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/antchfx/xpath/xpath.go @@ -0,0 +1,161 @@ +package xpath + +import ( + "errors" + "fmt" +) + +// NodeType represents a type of XPath node. +type NodeType int + +const ( + // RootNode is a root node of the XML document or node tree. + RootNode NodeType = iota + + // ElementNode is an element, such as . + ElementNode + + // AttributeNode is an attribute, such as id='123'. + AttributeNode + + // TextNode is the text content of a node. + TextNode + + // CommentNode is a comment node, such as + CommentNode + + // allNode is any types of node, used by xpath package only to predicate match. + allNode +) + +// NodeNavigator provides cursor model for navigating XML data. +type NodeNavigator interface { + // NodeType returns the XPathNodeType of the current node. + NodeType() NodeType + + // LocalName gets the Name of the current node. + LocalName() string + + // Prefix returns namespace prefix associated with the current node. + Prefix() string + + // Value gets the value of current node. + Value() string + + // Copy does a deep copy of the NodeNavigator and all its components. + Copy() NodeNavigator + + // MoveToRoot moves the NodeNavigator to the root node of the current node. + MoveToRoot() + + // MoveToParent moves the NodeNavigator to the parent node of the current node. + MoveToParent() bool + + // MoveToNextAttribute moves the NodeNavigator to the next attribute on current node. + MoveToNextAttribute() bool + + // MoveToChild moves the NodeNavigator to the first child node of the current node. + MoveToChild() bool + + // MoveToFirst moves the NodeNavigator to the first sibling node of the current node. + MoveToFirst() bool + + // MoveToNext moves the NodeNavigator to the next sibling node of the current node. + MoveToNext() bool + + // MoveToPrevious moves the NodeNavigator to the previous sibling node of the current node. + MoveToPrevious() bool + + // MoveTo moves the NodeNavigator to the same position as the specified NodeNavigator. + MoveTo(NodeNavigator) bool +} + +// NodeIterator holds all matched Node object. +type NodeIterator struct { + node NodeNavigator + query query +} + +// Current returns current node which matched. +func (t *NodeIterator) Current() NodeNavigator { + return t.node +} + +// MoveNext moves Navigator to the next match node. +func (t *NodeIterator) MoveNext() bool { + n := t.query.Select(t) + if n != nil { + if !t.node.MoveTo(n) { + t.node = n.Copy() + } + return true + } + return false +} + +// Select selects a node set using the specified XPath expression. +// This method is deprecated, recommend using Expr.Select() method instead. +func Select(root NodeNavigator, expr string) *NodeIterator { + exp, err := Compile(expr) + if err != nil { + panic(err) + } + return exp.Select(root) +} + +// Expr is an XPath expression for query. +type Expr struct { + s string + q query +} + +type iteratorFunc func() NodeNavigator + +func (f iteratorFunc) Current() NodeNavigator { + return f() +} + +// 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: + return &NodeIterator{query: expr.q.Clone(), node: root} + } + return val +} + +// Select selects a node set using the specified XPath expression. +func (expr *Expr) Select(root NodeNavigator) *NodeIterator { + return &NodeIterator{query: expr.q.Clone(), node: root} +} + +// String returns XPath expression string. +func (expr *Expr) String() string { + return expr.s +} + +// Compile compiles an XPath expression string. +func Compile(expr string) (*Expr, error) { + if expr == "" { + return nil, errors.New("expr expression is nil") + } + qy, err := build(expr) + if err != nil { + return nil, err + } + if qy == nil { + return nil, fmt.Errorf(fmt.Sprintf("undeclared variable in XPath expression: %s", expr)) + } + return &Expr{s: expr, q: qy}, nil +} + +// 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{}} + } + return exp +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/README.md b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/README.md new file mode 100644 index 000000000..4d10f697b --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/README.md @@ -0,0 +1,4 @@ +Installation and usage +---------------------- + +See [gopkg.in/xmlpath.v2](https://gopkg.in/xmlpath.v2) for documentation and usage details. diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/doc.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/doc.go new file mode 100644 index 000000000..e81d7370a --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/doc.go @@ -0,0 +1,75 @@ +// Package xmlpath implements a strict subset of the XPath specification for the Go language. +// +// The XPath specification is available at: +// +// http://www.w3.org/TR/xpath +// +// Path expressions supported by this package are in the following format, +// with all components being optional: +// +// /axis-name::node-test[predicate]/axis-name::node-test[predicate] +// +// At the moment, xmlpath is compatible with the XPath specification +// to the following extent: +// +// - All axes are supported ("child", "following-sibling", etc) +// - All abbreviated forms are supported (".", "//", etc) +// - All node types except for namespace are supported +// - Predicates may be [N], [path], [not(path)], [path=literal] or [contains(path, literal)] +// - Predicates may be joined with "or", "and", and parenthesis +// - Richer expressions and namespaces are not supported +// +// For example, assuming the following document: +// +// +// +// +// 0836217462 +// Being a Dog Is a Full-Time Job +// I'd dog paddle the deepest ocean. +// +// +// Charles M Schulz +// 1922-11-26 +// 2000-02-12 +// +// +// Peppermint Patty +// 1966-08-22 +// bold, brash and tomboyish +// +// +// Snoopy +// 1950-10-04 +// extroverted beagle +// +// +// +// +// The following examples are valid path expressions, and the first +// match has the indicated value: +// +// /library/book/isbn => "0836217462" +// library/*/isbn => "0836217462" +// /library/book/../book/./isbn => "0836217462" +// /library/book/character[2]/name => "Snoopy" +// /library/book/character[born='1950-10-04']/name => "Snoopy" +// /library/book//node()[@id='PP']/name => "Peppermint Patty" +// //book[author/@id='CMS']/title => "Being a Dog Is a Full-Time Job", +// /library/book/preceding::comment() => " Great book. " +// //*[contains(born,'1922')]/name => "Charles M Schulz" +// //*[@id='PP' or @id='Snoopy']/born => {"1966-08-22", "1950-10-04"} +// +// To run an expression, compile it, and then apply the compiled path to any +// number of context nodes, from one or more parsed xml documents: +// +// path := xmlpath.MustCompile("/library/book/isbn") +// root, err := xmlpath.Parse(file) +// if err != nil { +// log.Fatal(err) +// } +// if value, ok := path.String(root); ok { +// fmt.Println("Found:", value) +// } +// +package xmlpath diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/parser.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/parser.go new file mode 100644 index 000000000..64267aa49 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/parser.go @@ -0,0 +1,396 @@ +package xmlpath + +import ( + "golang.org/x/net/html" + "encoding/xml" + "io" + "strings" +) + +// Node is an item in an xml tree that was compiled to +// be processed via xml paths. A node may represent: +// +// - An element in the xml document () +// - An attribute of an element in the xml document (href="...") +// - A comment in the xml document () +// - A processing instruction in the xml document () +// - Some text within the xml document +// +type Node struct { + kind nodeKind + name xml.Name + attr string + text []byte + + nodes []Node + pos int + end int + + up *Node + down []*Node +} + +type nodeKind int + +const ( + anyNode nodeKind = iota + startNode + endNode + attrNode + textNode + commentNode + procInstNode +) + +// String returns the string value of node. +// +// The string value of a node is: +// +// - For element nodes, the concatenation of all text nodes within the element. +// - For text nodes, the text itself. +// - For attribute nodes, the attribute value. +// - For comment nodes, the text within the comment delimiters. +// - For processing instruction nodes, the content of the instruction. +// +func (node *Node) String() string { + if node.kind == attrNode { + return node.attr + } + return string(node.Bytes()) +} + +// Bytes returns the string value of node as a byte slice. +// See Node.String for a description of what the string value of a node is. +func (node *Node) Bytes() []byte { + if node.kind == attrNode { + return []byte(node.attr) + } + if node.kind != startNode { + return node.text + } + size := 0 + for i := node.pos; i < node.end; i++ { + if node.nodes[i].kind == textNode { + size += len(node.nodes[i].text) + } + } + text := make([]byte, 0, size) + for i := node.pos; i < node.end; i++ { + if node.nodes[i].kind == textNode { + text = append(text, node.nodes[i].text...) + } + } + return text +} + +// equals returns whether the string value of node is equal to s, +// without allocating memory. +func (node *Node) equals(s string) bool { + if node.kind == attrNode { + return s == node.attr + } + if node.kind != startNode { + if len(s) != len(node.text) { + return false + } + for i := range s { + if s[i] != node.text[i] { + return false + } + } + return true + } + si := 0 + for i := node.pos; i < node.end; i++ { + if node.nodes[i].kind == textNode { + for _, c := range node.nodes[i].text { + if si > len(s) { + return false + } + if s[si] != c { + return false + } + si++ + } + } + } + return si == len(s) +} + +// contains returns whether the string value of node contains s, +// without allocating memory. +func (node *Node) contains(s string) (ok bool) { + if len(s) == 0 { + return true + } + if node.kind == attrNode { + return strings.Contains(node.attr, s) + } + s0 := s[0] + for i := node.pos; i < node.end; i++ { + if node.nodes[i].kind == textNode { + text := node.nodes[i].text + NextTry: + for ci, c := range text { + if c != s0 { + continue + } + si := 1 + for ci++; ci < len(text) && si < len(s); ci++ { + if s[si] != text[ci] { + continue NextTry + } + si++ + } + if si == len(s) { + return true + } + for j := i + 1; j < node.end; j++ { + if node.nodes[j].kind == textNode { + for _, c := range node.nodes[j].text { + if s[si] != c { + continue NextTry + } + si++ + if si == len(s) { + return true + } + } + } + } + } + } + } + return false +} + +// Parse reads an xml document from r, parses it, and returns its root node. +func Parse(r io.Reader) (*Node, error) { + return ParseDecoder(xml.NewDecoder(r)) +} + +// ParseDecoder parses the xml document being decoded by d and returns +// its root node. +func ParseDecoder(d *xml.Decoder) (*Node, error) { + var nodes []Node + var text []byte + + // The root node. + nodes = append(nodes, Node{kind: startNode}) + + for { + t, err := d.Token() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + switch t := t.(type) { + case xml.EndElement: + nodes = append(nodes, Node{ + kind: endNode, + }) + case xml.StartElement: + nodes = append(nodes, Node{ + kind: startNode, + name: t.Name, + }) + for _, attr := range t.Attr { + nodes = append(nodes, Node{ + kind: attrNode, + name: attr.Name, + attr: attr.Value, + }) + } + case xml.CharData: + texti := len(text) + text = append(text, t...) + nodes = append(nodes, Node{ + kind: textNode, + text: text[texti : texti+len(t)], + }) + case xml.Comment: + texti := len(text) + text = append(text, t...) + nodes = append(nodes, Node{ + kind: commentNode, + text: text[texti : texti+len(t)], + }) + case xml.ProcInst: + texti := len(text) + text = append(text, t.Inst...) + nodes = append(nodes, Node{ + kind: procInstNode, + name: xml.Name{Local: t.Target}, + text: text[texti : texti+len(t.Inst)], + }) + } + } + + // Close the root node. + nodes = append(nodes, Node{kind: endNode}) + + stack := make([]*Node, 0, len(nodes)) + downs := make([]*Node, len(nodes)) + downCount := 0 + + for pos := range nodes { + + switch nodes[pos].kind { + + case startNode, attrNode, textNode, commentNode, procInstNode: + node := &nodes[pos] + node.nodes = nodes + node.pos = pos + if len(stack) > 0 { + node.up = stack[len(stack)-1] + } + if node.kind == startNode { + stack = append(stack, node) + } else { + node.end = pos + 1 + } + + case endNode: + node := stack[len(stack)-1] + node.end = pos + stack = stack[:len(stack)-1] + + // Compute downs. Doing that here is what enables the + // use of a slice of a contiguous pre-allocated block. + node.down = downs[downCount:downCount] + for i := node.pos + 1; i < node.end; i++ { + if nodes[i].up == node { + switch nodes[i].kind { + case startNode, textNode, commentNode, procInstNode: + node.down = append(node.down, &nodes[i]) + downCount++ + } + } + } + if len(stack) == 0 { + return node, nil + } + } + } + return nil, io.EOF +} + +// ParseHTML reads an HTML document from r, parses it using a proper HTML +// parser, and returns its root node. +// +// The document will be processed as a properly structured HTML document, +// emulating the behavior of a browser when processing it. This includes +// putting the content inside proper and tags, if the +// provided text misses them. +func ParseHTML(r io.Reader) (*Node, error) { + ns, err := html.ParseFragment(r, nil) + if err != nil { + return nil, err + } + + var nodes []Node + var text []byte + + n := ns[0] + + // The root node. + nodes = append(nodes, Node{kind: startNode}) + + for n != nil { + switch n.Type { + case html.DocumentNode: + case html.ElementNode: + nodes = append(nodes, Node{ + kind: startNode, + name: xml.Name{Local: n.Data, Space: n.Namespace}, + }) + for _, attr := range n.Attr { + nodes = append(nodes, Node{ + kind: attrNode, + name: xml.Name{Local: attr.Key, Space: attr.Namespace}, + attr: attr.Val, + }) + } + case html.TextNode: + texti := len(text) + text = append(text, n.Data...) + nodes = append(nodes, Node{ + kind: textNode, + text: text[texti : texti+len(n.Data)], + }) + case html.CommentNode: + texti := len(text) + text = append(text, n.Data...) + nodes = append(nodes, Node{ + kind: commentNode, + text: text[texti : texti+len(n.Data)], + }) + } + + if n.FirstChild != nil { + n = n.FirstChild + continue + } + + for n != nil { + if n.Type == html.ElementNode { + nodes = append(nodes, Node{kind: endNode}) + } + if n.NextSibling != nil { + n = n.NextSibling + break + } + n = n.Parent + } + } + + // Close the root node. + nodes = append(nodes, Node{kind: endNode}) + + stack := make([]*Node, 0, len(nodes)) + downs := make([]*Node, len(nodes)) + downCount := 0 + + for pos := range nodes { + + switch nodes[pos].kind { + + case startNode, attrNode, textNode, commentNode, procInstNode: + node := &nodes[pos] + node.nodes = nodes + node.pos = pos + if len(stack) > 0 { + node.up = stack[len(stack)-1] + } + if node.kind == startNode { + stack = append(stack, node) + } else { + node.end = pos + 1 + } + + case endNode: + node := stack[len(stack)-1] + node.end = pos + stack = stack[:len(stack)-1] + + // Compute downs. Doing that here is what enables the + // use of a slice of a contiguous pre-allocated block. + node.down = downs[downCount:downCount] + for i := node.pos + 1; i < node.end; i++ { + if nodes[i].up == node { + switch nodes[i].kind { + case startNode, textNode, commentNode, procInstNode: + node.down = append(node.down, &nodes[i]) + downCount++ + } + } + } + if len(stack) == 0 { + return node, nil + } + } + } + return nil, io.EOF +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/path.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/path.go new file mode 100644 index 000000000..db38ed573 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/path.go @@ -0,0 +1,790 @@ +package xmlpath + +import ( + "fmt" + "strconv" + "unicode/utf8" +) + +// Path is a compiled path that can be applied to a context +// node to obtain a matching node set. +// A single Path can be applied concurrently to any number +// of context nodes. +type Path struct { + path string + steps []pathStep +} + +// Iter returns an iterator that goes over the list of nodes +// that p matches on the given context. +func (p *Path) Iter(context *Node) *Iter { + iter := Iter{ + make([]pathStepState, len(p.steps)), + make([]bool, len(context.nodes)), + } + for i := range p.steps { + iter.state[i].step = &p.steps[i] + } + iter.state[0].init(context) + return &iter +} + +// Exists returns whether any nodes match p on the given context. +func (p *Path) Exists(context *Node) bool { + return p.Iter(context).Next() +} + +// String returns the string value of the first node matched +// by p on the given context. +// +// See the documentation of Node.String. +func (p *Path) String(context *Node) (s string, ok bool) { + iter := p.Iter(context) + if iter.Next() { + return iter.Node().String(), true + } + return "", false +} + +// Bytes returns as a byte slice the string value of the first +// node matched by p on the given context. +// +// See the documentation of Node.String. +func (p *Path) Bytes(node *Node) (b []byte, ok bool) { + iter := p.Iter(node) + if iter.Next() { + return iter.Node().Bytes(), true + } + return nil, false +} + +// Iter iterates over node sets. +type Iter struct { + state []pathStepState + seen []bool +} + +// Node returns the current node. +// Must only be called after Iter.Next returns true. +func (iter *Iter) Node() *Node { + state := iter.state[len(iter.state)-1] + if state.pos == 0 { + panic("Iter.Node called before Iter.Next") + } + if state.node == nil { + panic("Iter.Node called after Iter.Next false") + } + return state.node +} + +// Next iterates to the next node in the set, if any, and +// returns whether there is a node available. +func (iter *Iter) Next() bool { + tip := len(iter.state) - 1 +outer: + for { + for !iter.state[tip].next() { + tip-- + if tip == -1 { + return false + } + } + for tip < len(iter.state)-1 { + tip++ + iter.state[tip].init(iter.state[tip-1].node) + if !iter.state[tip].next() { + tip-- + continue outer + } + } + if iter.seen[iter.state[tip].node.pos] { + continue + } + iter.seen[iter.state[tip].node.pos] = true + return true + } + panic("unreachable") +} + +type pathStepState struct { + step *pathStep + node *Node + pos int + idx int + aux int +} + +func (s *pathStepState) init(node *Node) { + s.node = node + s.pos = 0 + s.idx = 0 + s.aux = 0 +} + +func (s *pathStepState) next() bool { + for s._next() { + s.pos++ + if s.step.pred == nil || s.test(s.step.pred) { + return true + } + } + return false +} + +func (s *pathStepState) test(pred predicate) bool { + switch pred := pred.(type) { + case positionPredicate: + if pred.pos == s.pos { + return true + } + case existsPredicate: + if pred.path.Exists(s.node) { + return true + } + case equalsPredicate: + iter := pred.path.Iter(s.node) + for iter.Next() { + if iter.Node().equals(pred.value) { + return true + } + } + case containsPredicate: + iter := pred.path.Iter(s.node) + for iter.Next() { + if iter.Node().contains(pred.value) { + return true + } + } + case notPredicate: + iter := pred.path.Iter(s.node) + if !iter.Next() { + return true + } + case andPredicate: + for _, sub := range pred.sub { + if !s.test(sub) { + return false + } + } + return true + case orPredicate: + for _, sub := range pred.sub { + if s.test(sub) { + return true + } + } + default: + panic(fmt.Sprintf("internal error: unknown predicate type: %#v", s.step.pred)) + } + return false +} + +func (s *pathStepState) _next() bool { + if s.node == nil { + return false + } + if s.step.root && s.idx == 0 { + for s.node.up != nil { + s.node = s.node.up + } + } + + switch s.step.axis { + + case "self": + if s.idx == 0 && s.step.match(s.node) { + s.idx++ + return true + } + + case "parent": + if s.idx == 0 && s.node.up != nil && s.step.match(s.node.up) { + s.idx++ + s.node = s.node.up + return true + } + + case "ancestor", "ancestor-or-self": + if s.idx == 0 && s.step.axis == "ancestor-or-self" { + s.idx++ + if s.step.match(s.node) { + return true + } + } + for s.node.up != nil { + s.node = s.node.up + s.idx++ + if s.step.match(s.node) { + return true + } + } + + case "child": + var down []*Node + if s.idx == 0 { + down = s.node.down + } else { + down = s.node.up.down + } + for s.idx < len(down) { + node := down[s.idx] + s.idx++ + if s.step.match(node) { + s.node = node + return true + } + } + + case "descendant", "descendant-or-self": + if s.idx == 0 { + s.idx = s.node.pos + s.aux = s.node.end + if s.step.axis == "descendant" { + s.idx++ + } + } + for s.idx < s.aux { + node := &s.node.nodes[s.idx] + s.idx++ + if node.kind == attrNode { + continue + } + if s.step.match(node) { + s.node = node + return true + } + } + + case "following": + if s.idx == 0 { + s.idx = s.node.end + } + for s.idx < len(s.node.nodes) { + node := &s.node.nodes[s.idx] + s.idx++ + if node.kind == attrNode { + continue + } + if s.step.match(node) { + s.node = node + return true + } + } + + case "following-sibling": + var down []*Node + if s.node.up != nil { + down = s.node.up.down + if s.idx == 0 { + for s.idx < len(down) { + node := down[s.idx] + s.idx++ + if node == s.node { + break + } + } + } + } + for s.idx < len(down) { + node := down[s.idx] + s.idx++ + if s.step.match(node) { + s.node = node + return true + } + } + + case "preceding": + if s.idx == 0 { + s.aux = s.node.pos // Detect ancestors. + s.idx = s.node.pos - 1 + } + for s.idx >= 0 { + node := &s.node.nodes[s.idx] + s.idx-- + if node.kind == attrNode { + continue + } + if node == s.node.nodes[s.aux].up { + s.aux = s.node.nodes[s.aux].up.pos + continue + } + if s.step.match(node) { + s.node = node + return true + } + } + + case "preceding-sibling": + var down []*Node + if s.node.up != nil { + down = s.node.up.down + if s.aux == 0 { + s.aux = 1 + for s.idx < len(down) { + node := down[s.idx] + s.idx++ + if node == s.node { + s.idx-- + break + } + } + } + } + for s.idx >= 0 { + node := down[s.idx] + s.idx-- + if s.step.match(node) { + s.node = node + return true + } + } + + case "attribute": + if s.idx == 0 { + s.idx = s.node.pos + 1 + s.aux = s.node.end + } + for s.idx < s.aux { + node := &s.node.nodes[s.idx] + s.idx++ + if node.kind != attrNode { + break + } + if s.step.match(node) { + s.node = node + return true + } + } + + } + + s.node = nil + return false +} + +type positionPredicate struct { + pos int +} + +type existsPredicate struct { + path *Path +} + +type equalsPredicate struct { + path *Path + value string +} + +type containsPredicate struct { + path *Path + value string +} + +type notPredicate struct { + path *Path +} + +type andPredicate struct { + sub []predicate +} + +type orPredicate struct { + sub []predicate +} + +// predicate is a marker interface for predicate types. +type predicate interface { + predicate() +} + +func (positionPredicate) predicate() {} +func (existsPredicate) predicate() {} +func (equalsPredicate) predicate() {} +func (containsPredicate) predicate() {} +func (notPredicate) predicate() {} +func (andPredicate) predicate() {} +func (orPredicate) predicate() {} + +type pathStep struct { + root bool + axis string + name string + kind nodeKind + pred predicate +} + +func (step *pathStep) match(node *Node) bool { + return node.kind != endNode && + (step.kind == anyNode || step.kind == node.kind) && + (step.name == "*" || node.name.Local == step.name) +} + +// MustCompile returns the compiled path, and panics if +// there are any errors. +func MustCompile(path string) *Path { + e, err := Compile(path) + if err != nil { + panic(err) + } + return e +} + +// Compile returns the compiled path. +func Compile(path string) (*Path, error) { + c := pathCompiler{path, 0} + if path == "" { + return nil, c.errorf("empty path") + } + p, err := c.parsePath() + if err != nil { + return nil, err + } + return p, nil +} + +type pathCompiler struct { + path string + i int +} + +func (c *pathCompiler) errorf(format string, args ...interface{}) error { + return fmt.Errorf("compiling xml path %q:%d: %s", c.path, c.i, fmt.Sprintf(format, args...)) +} + +func (c *pathCompiler) parsePath() (path *Path, err error) { + var steps []pathStep + var start = c.i + for { + step := pathStep{axis: "child"} + + c.skipSpaces() + if c.i == 0 && c.skipByte('/') { + c.skipSpaces() + step.root = true + if len(c.path) == 1 { + step.name = "*" + } + } + if c.peekByte('/') { + step.axis = "descendant-or-self" + step.name = "*" + } else if c.skipByte('@') { + mark := c.i + if !c.skipName() { + return nil, c.errorf("missing name after @") + } + step.axis = "attribute" + step.name = c.path[mark:c.i] + step.kind = attrNode + } else { + mark := c.i + if c.skipName() { + step.name = c.path[mark:c.i] + c.skipSpaces() + } + if step.name == "" { + return nil, c.errorf("missing name") + } else if step.name == "*" { + step.kind = startNode + } else if step.name == "." { + step.axis = "self" + step.name = "*" + } else if step.name == ".." { + step.axis = "parent" + step.name = "*" + } else { + if c.skipByte(':') { + if !c.skipByte(':') { + return nil, c.errorf("missing ':'") + } + c.skipSpaces() + switch step.name { + case "attribute": + step.kind = attrNode + case "self", "child", "parent": + case "descendant", "descendant-or-self": + case "ancestor", "ancestor-or-self": + case "following", "following-sibling": + case "preceding", "preceding-sibling": + default: + return nil, c.errorf("unsupported axis: %q", step.name) + } + step.axis = step.name + + mark = c.i + if !c.skipName() { + return nil, c.errorf("missing name") + } + step.name = c.path[mark:c.i] + + c.skipSpaces() + } + if c.skipByte('(') { + c.skipSpaces() + conflict := step.kind != anyNode + switch step.name { + case "node": + // must be anyNode + case "text": + step.kind = textNode + case "comment": + step.kind = commentNode + case "processing-instruction": + step.kind = procInstNode + default: + return nil, c.errorf("unsupported expression: %s()", step.name) + } + if conflict { + return nil, c.errorf("%s() cannot succeed on axis %q", step.name, step.axis) + } + + name := step.name + literal, err := c.parseLiteral() + if err == errNoLiteral { + step.name = "*" + } else if err != nil { + return nil, c.errorf("%v", err) + } else if step.kind == procInstNode { + c.skipSpaces() + step.name = literal + } else { + return nil, c.errorf("%s() has no arguments", name) + } + if !c.skipByte(')') { + return nil, c.errorf("%s() missing ')'", name) + } + c.skipSpaces() + } else if step.name == "*" && step.kind == anyNode { + step.kind = startNode + } + } + } + if c.skipByte('[') { + c.skipSpaces() + type state struct { + sub []predicate + and bool + } + var stack []state + var sub []predicate + var and bool + NextPred: + if c.skipByte('(') { + stack = append(stack, state{sub, and}) + sub = nil + and = false + } + var next predicate + if pos, ok := c.parseInt(); ok { + if pos == 0 { + return nil, c.errorf("positions start at 1") + } + next = positionPredicate{pos} + } else if c.skipString("contains(") { + path, err := c.parsePath() + if err != nil { + return nil, err + } + c.skipSpaces() + if !c.skipByte(',') { + return nil, c.errorf("contains() expected ',' followed by a literal string") + } + c.skipSpaces() + value, err := c.parseLiteral() + if err != nil { + return nil, err + } + c.skipSpaces() + if !c.skipByte(')') { + return nil, c.errorf("contains() missing ')'") + } + next = containsPredicate{path, value} + } else if c.skipString("not(") { + // TODO Generalize to handle any predicate expression. + path, err := c.parsePath() + if err != nil { + return nil, err + } + c.skipSpaces() + if !c.skipByte(')') { + return nil, c.errorf("not() missing ')'") + } + next = notPredicate{path} + } else { + path, err := c.parsePath() + if err != nil { + return nil, err + } + if path.path[0] == '-' { + if _, err = strconv.Atoi(path.path); err == nil { + return nil, c.errorf("positions must be positive") + } + } + c.skipSpaces() + if c.skipByte('=') { + c.skipSpaces() + value, err := c.parseLiteral() + if err != nil { + return nil, c.errorf("%v", err) + } + next = equalsPredicate{path, value} + } else { + next = existsPredicate{path} + } + } + HandleNext: + if and { + p := sub[len(sub)-1].(andPredicate) + p.sub = append(p.sub, next) + sub[len(sub)-1] = p + } else { + sub = append(sub, next) + } + if c.skipSpaces() { + mark := c.i + if c.skipString("and") && c.skipSpaces() { + if !and { + and = true + sub[len(sub)-1] = andPredicate{[]predicate{sub[len(sub)-1]}} + } + goto NextPred + } else if c.skipString("or") && c.skipSpaces() { + and = false + goto NextPred + } else { + c.i = mark + } + } + if c.skipByte(')') { + if len(stack) == 0 { + return nil, c.errorf("unexpected ')'") + } + if len(sub) == 1 { + next = sub[0] + } else { + next = orPredicate{sub} + } + s := stack[len(stack)-1] + stack = stack[:len(stack)-1] + sub = s.sub + and = s.and + goto HandleNext + } + if len(stack) > 0 { + return nil, c.errorf("expected ')'") + } + if len(sub) == 1 { + step.pred = sub[0] + } else { + step.pred = orPredicate{sub} + } + if !c.skipByte(']') { + return nil, c.errorf("expected ']'") + } + c.skipSpaces() + } + steps = append(steps, step) + //fmt.Printf("step: %#v\n", step) + if !c.skipByte('/') { + if (start == 0 || start == c.i) && c.i < len(c.path) { + return nil, c.errorf("unexpected %q", c.path[c.i]) + } + return &Path{steps: steps, path: c.path[start:c.i]}, nil + } + } + panic("unreachable") +} + +var errNoLiteral = fmt.Errorf("expected a literal string") + +func (c *pathCompiler) parseLiteral() (string, error) { + if c.skipByte('"') { + mark := c.i + if !c.skipByteFind('"') { + return "", fmt.Errorf(`missing '"'`) + } + return c.path[mark : c.i-1], nil + } + if c.skipByte('\'') { + mark := c.i + if !c.skipByteFind('\'') { + return "", fmt.Errorf(`missing "'"`) + } + return c.path[mark : c.i-1], nil + } + return "", errNoLiteral +} + +func (c *pathCompiler) parseInt() (v int, ok bool) { + mark := c.i + for c.i < len(c.path) && c.path[c.i] >= '0' && c.path[c.i] <= '9' { + v *= 10 + v += int(c.path[c.i]) - '0' + c.i++ + } + if c.i == mark { + return 0, false + } + return v, true +} + +func (c *pathCompiler) skipByte(b byte) bool { + if c.i < len(c.path) && c.path[c.i] == b { + c.i++ + return true + } + return false +} + +func (c *pathCompiler) skipByteFind(b byte) bool { + for i := c.i; i < len(c.path); i++ { + if c.path[i] == b { + c.i = i + 1 + return true + } + } + return false +} + +func (c *pathCompiler) peekByte(b byte) bool { + return c.i < len(c.path) && c.path[c.i] == b +} + +func (c *pathCompiler) skipSpaces() bool { + mark := c.i + for c.i < len(c.path) { + if c.path[c.i] != ' ' { + break + } + c.i++ + } + return c.i != mark +} + +func (c *pathCompiler) skipString(s string) bool { + if c.i+len(s) <= len(c.path) && c.path[c.i:c.i+len(s)] == s { + c.i += len(s) + return true + } + return false +} + +func (c *pathCompiler) skipName() bool { + if c.i >= len(c.path) { + return false + } + if c.path[c.i] == '*' { + c.i++ + return true + } + start := c.i + for c.i < len(c.path) && (c.path[c.i] >= utf8.RuneSelf || isNameByte(c.path[c.i])) { + c.i++ + } + return c.i > start +} + +func isNameByte(c byte) bool { + return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c == '.' || c == '-' +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/stub.go deleted file mode 100644 index 2ec18b739..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/go-xmlpath/xmlpath/stub.go +++ /dev/null @@ -1,56 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/go-xmlpath/xmlpath, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/go-xmlpath/xmlpath (exports: ; functions: Compile,MustCompile) - -// Package xmlpath is a stub of github.com/go-xmlpath/xmlpath, generated by depstubber. -package xmlpath - -import () - -func Compile(_ string) (*Path, error) { - return nil, nil -} - -type Iter struct{} - -func (_ *Iter) Next() bool { - return false -} - -func (_ *Iter) Node() *Node { - return nil -} - -func MustCompile(_ string) *Path { - return nil -} - -type Node struct{} - -func (_ *Node) Bytes() []byte { - return nil -} - -func (_ *Node) String() string { - return "" -} - -type Path struct{} - -func (_ *Path) Bytes(_ *Node) ([]byte, bool) { - return nil, false -} - -func (_ *Path) Exists(_ *Node) bool { - return false -} - -func (_ *Path) Iter(_ *Node) *Iter { - return nil -} - -func (_ *Path) String(_ *Node) (string, bool) { - return "", false -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/LICENSE b/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/LICENSE new file mode 100644 index 000000000..37ec93a14 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/lru/lru.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/lru/lru.go new file mode 100644 index 000000000..eac1c7664 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/golang/groupcache/lru/lru.go @@ -0,0 +1,133 @@ +/* +Copyright 2013 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package lru implements an LRU cache. +package lru + +import "container/list" + +// Cache is an LRU cache. It is not safe for concurrent access. +type Cache struct { + // MaxEntries is the maximum number of cache entries before + // an item is evicted. Zero means no limit. + MaxEntries int + + // OnEvicted optionally specifies a callback function to be + // executed when an entry is purged from the cache. + OnEvicted func(key Key, value interface{}) + + ll *list.List + cache map[interface{}]*list.Element +} + +// A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators +type Key interface{} + +type entry struct { + key Key + value interface{} +} + +// New creates a new Cache. +// If maxEntries is zero, the cache has no limit and it's assumed +// that eviction is done by the caller. +func New(maxEntries int) *Cache { + return &Cache{ + MaxEntries: maxEntries, + ll: list.New(), + cache: make(map[interface{}]*list.Element), + } +} + +// Add adds a value to the cache. +func (c *Cache) Add(key Key, value interface{}) { + if c.cache == nil { + c.cache = make(map[interface{}]*list.Element) + c.ll = list.New() + } + if ee, ok := c.cache[key]; ok { + c.ll.MoveToFront(ee) + ee.Value.(*entry).value = value + return + } + ele := c.ll.PushFront(&entry{key, value}) + c.cache[key] = ele + if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries { + c.RemoveOldest() + } +} + +// Get looks up a key's value from the cache. +func (c *Cache) Get(key Key) (value interface{}, ok bool) { + if c.cache == nil { + return + } + if ele, hit := c.cache[key]; hit { + c.ll.MoveToFront(ele) + return ele.Value.(*entry).value, true + } + return +} + +// Remove removes the provided key from the cache. +func (c *Cache) Remove(key Key) { + if c.cache == nil { + return + } + if ele, hit := c.cache[key]; hit { + c.removeElement(ele) + } +} + +// RemoveOldest removes the oldest item from the cache. +func (c *Cache) RemoveOldest() { + if c.cache == nil { + return + } + ele := c.ll.Back() + if ele != nil { + c.removeElement(ele) + } +} + +func (c *Cache) removeElement(e *list.Element) { + c.ll.Remove(e) + kv := e.Value.(*entry) + delete(c.cache, kv.key) + if c.OnEvicted != nil { + c.OnEvicted(kv.key, kv.value) + } +} + +// Len returns the number of items in the cache. +func (c *Cache) Len() int { + if c.cache == nil { + return 0 + } + return c.ll.Len() +} + +// Clear purges all stored items from the cache. +func (c *Cache) Clear() { + if c.OnEvicted != nil { + for _, e := range c.cache { + kv := e.Value.(*entry) + c.OnEvicted(kv.key, kv.value) + } + } + c.ll = nil + c.cache = nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/help/help.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/help/help.go new file mode 100644 index 000000000..3b6e9db4d --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/help/help.go @@ -0,0 +1,74 @@ +package help + +/* +#cgo pkg-config: libxml-2.0 + +#include +#include +#include +#include +#include + +void printMemoryLeak() { xmlMemDisplay(stdout); } +*/ +import "C" + +import ( + "sync" + "sync/atomic" +) + +/** +* With regards to Thread Safety +* +* xmlInitParser and xmlCleanupParser need to be called *once* each during the +* lifetime of the program, regardless of how many documents you parse. +* +* xmlInitParser should be called at the very beginning before doing anything +* parser related. Luckly, using the call below, we can guarantee that by +* making sure it gets called exactly once if anyone uses any gokogiri +* related functions. +* +* xmlCleanupParser is trickier because it also can only be called once, but it +* should strictly be called at the very end of program execution, after we're +* sure that no more documents will be parsed. If it's ever called, and a new +* document is parsed, there is a potential for a segfault. +* +* For more information: +* +* http://www.xmlsoft.org/threads.html +* http://www.xmlsoft.org/FAQ.html#Developer (In particular, question #7) +**/ + +var once sync.Once +var cleaned = new(int32) + +func LibxmlInitParser() { + if called_clean := atomic.LoadInt32(cleaned); called_clean != 0 { + panic("LibxmlCleanUpParser has been called. Please make sure you only " + + "call it if no more document parsing will take place.") + } + once.Do(func() { C.xmlInitParser() }) +} + +func LibxmlCleanUpParser() { + // Because of our test structure, this method is called several + // times during a test run (but it should only be called once + // during the lifetime of the program). + once.Do(func() { + atomic.AddInt32(cleaned, 1) + C.xmlCleanupParser() + }) +} + +func LibxmlGetMemoryAllocation() int { + return (int)(C.xmlMemBlocks()) +} + +func LibxmlCheckMemoryLeak() bool { + return (C.xmlMemBlocks() == 0) +} + +func LibxmlReportMemoryLeak() { + C.printMemoryLeak() +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/util/util.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/util/util.go new file mode 100644 index 000000000..c3d364f09 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/util/util.go @@ -0,0 +1,20 @@ +package util + +var EmptyStringBytes = []byte{0} + +func AppendCStringTerminator(b []byte) []byte { + if num := len(b); num > 0 { + if b[num-1] != 0 { + return append(b, 0) + } + } + return b +} + +func GetCString(b []byte) []byte { + b = AppendCStringTerminator(b) + if len(b) == 0 { + return EmptyStringBytes + } + return b +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/attribute.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/attribute.go new file mode 100644 index 000000000..ca5ac0153 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/attribute.go @@ -0,0 +1,37 @@ +package xml + +/* +AttributeNode represents an attribute, which has a name and a value. + +AttributeNodes are created by calling SetAttr or SetNsAttr on an element node, +and retrieved by the Attribute and Attributes functions on an element node. + +Note that while mamespace declarations resemble attributes, they are a distinct node type +and cannot be used or retrieved as an AttributeNode. +*/ +type AttributeNode struct { + *XmlNode +} + +// String returns the value of the attribute. +func (attrNode *AttributeNode) String() string { + return attrNode.Content() +} + +// Value returns the value of the attribute. +func (attrNode *AttributeNode) Value() string { + return attrNode.Content() +} + +//SetValue sets the value of the attribute. Note that the argument will +// be converted to a string, and automatically XML-escaped when the +// document is serialized. +func (attrNode *AttributeNode) SetValue(val interface{}) { + attrNode.SetContent(val) +} + +/* +alias :value :content +alias :to_s :content +alias :content= :value= +*/ diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/cdata.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/cdata.go new file mode 100644 index 000000000..d7cc458d1 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/cdata.go @@ -0,0 +1,12 @@ +package xml + +/* CDataNode represents a CDATA section. This XML node type allows the embedding of unescaped, verbatim text within an XML document. + +It is otherwise identical to a TextNode. It is most often used to wrap content that is whitespace-sensitive or likely to contain +large numbers of less-than or greater-than signs (such as code snippets or example documents). + +If you use the XML_PARSE_NOCDATA parsing option, the parser will always present the CDATA sections as TextNodes. +*/ +type CDataNode struct { + *XmlNode +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/comment.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/comment.go new file mode 100644 index 000000000..177cf5450 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/comment.go @@ -0,0 +1,5 @@ +package xml + +type CommentNode struct { + *XmlNode +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/document.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/document.go new file mode 100644 index 000000000..6a7ec89c6 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/document.go @@ -0,0 +1,455 @@ +package xml + +/* +#cgo pkg-config: libxml-2.0 + +#include "helper.h" +*/ +import "C" + +import ( + "errors" + "github.com/jbowtie/gokogiri/help" + . "github.com/jbowtie/gokogiri/util" + "github.com/jbowtie/gokogiri/xpath" + "os" + "unsafe" +) + +type Document interface { + /* Nokogiri APIs */ + CreateElementNode(string) *ElementNode + CreateCDataNode(string) *CDataNode + CreateTextNode(string) *TextNode + CreateCommentNode(string) *CommentNode + CreatePINode(string, string) *ProcessingInstructionNode + ParseFragment([]byte, []byte, ParseOption) (*DocumentFragment, error) + + DocPtr() unsafe.Pointer + DocType() NodeType + DocRef() Document + InputEncoding() []byte + OutputEncoding() []byte + DocXPathCtx() *xpath.XPath + AddUnlinkedNode(unsafe.Pointer) + RemoveUnlinkedNode(unsafe.Pointer) bool + Free() + String() string + Root() *ElementNode + NodeById(string) *ElementNode + BookkeepFragment(*DocumentFragment) + + RecursivelyRemoveNamespaces() error + UnparsedEntityURI(string) string + Uri() string +} + +// ParseOption values allow you to tune the behaviour of the parsing engine. +type ParseOption int + +const ( + XML_PARSE_RECOVER ParseOption = 1 << iota // recover on errors + XML_PARSE_NOENT // substitute entities + XML_PARSE_DTDLOAD // load the external subset + XML_PARSE_DTDATTR // default DTD attributes + XML_PARSE_DTDVALID // validate with the DTD + XML_PARSE_NOERROR // suppress error reports + XML_PARSE_NOWARNING // suppress warning reports + XML_PARSE_PEDANTIC // pedantic error reporting + XML_PARSE_NOBLANKS // remove blank nodes + XML_PARSE_SAX1 // use the SAX1 interface internally + XML_PARSE_XINCLUDE // Implement XInclude substitition + XML_PARSE_NONET // Forbid network access + XML_PARSE_NODICT // Do not reuse the context dictionnary + XML_PARSE_NSCLEAN // remove redundant namespaces declarations + XML_PARSE_NOCDATA // merge CDATA as text nodes + XML_PARSE_NOXINCNODE // do not generate XINCLUDE START/END nodes + XML_PARSE_COMPACT // compact small text nodes; makes tree read-only + XML_PARSE_OLD10 // parse using XML-1.0 before update 5 + XML_PARSE_NOBASEFIX // do not fixup XINCLUDE xml//base uris + XML_PARSE_HUGE // relax any hardcoded limit from the parser + XML_PARSE_OLDSAX // parse using SAX2 interface before 2.7.0 + XML_PARSE_IGNORE_ENC // ignore internal document encoding hint + XML_PARSE_BIG_LINES // Store big lines numbers in text PSVI field +) + +//DefaultParseOption provides liberal parsing highly tolerant of invalid documents. Errors and warnings +// are suppressed and the DTD is not processed. +const DefaultParseOption ParseOption = XML_PARSE_RECOVER | + XML_PARSE_NONET | + XML_PARSE_NOERROR | + XML_PARSE_NOWARNING + +//StrictParseOption provides standard-compliant parsing. The DTD is processed, entity +// substitions are made, and errors and warnings are reported back. +const StrictParseOption ParseOption = XML_PARSE_NOENT | + XML_PARSE_DTDLOAD | + XML_PARSE_DTDATTR | + XML_PARSE_NOCDATA + +//DefaultEncoding is UTF-8, which is also the default for both libxml2 and Go strings. +const DefaultEncoding = "utf-8" + +var ERR_FAILED_TO_PARSE_XML = errors.New("failed to parse xml input") + +/* +XmlDocument is the primary interface for working with XML documents. +*/ +type XmlDocument struct { + Ptr *C.xmlDoc + Me Document + Node + InEncoding []byte + OutEncoding []byte + UnlinkedNodes map[*C.xmlNode]bool + XPathCtx *xpath.XPath + Type NodeType + InputLen int + + fragments []*DocumentFragment //save the pointers to free them when the doc is freed +} + +//DefaultEncodingBytes allows us to conveniently pass the DefaultEncoding to various functions that +// expect the encoding as a byte array. +var DefaultEncodingBytes = []byte(DefaultEncoding) + +const initialFragments = 2 + +//NewDocument wraps the pointer to the C struct. +// +// TODO: this should probably not be exported. +func NewDocument(p unsafe.Pointer, contentLen int, inEncoding, outEncoding []byte) (doc *XmlDocument) { + inEncoding = AppendCStringTerminator(inEncoding) + outEncoding = AppendCStringTerminator(outEncoding) + + xmlNode := &XmlNode{Ptr: (*C.xmlNode)(p)} + docPtr := (*C.xmlDoc)(p) + doc = &XmlDocument{Ptr: docPtr, Node: xmlNode, InEncoding: inEncoding, OutEncoding: outEncoding, InputLen: contentLen} + doc.UnlinkedNodes = make(map[*C.xmlNode]bool) + doc.XPathCtx = xpath.NewXPath(p) + doc.Type = xmlNode.NodeType() + doc.fragments = make([]*DocumentFragment, 0, initialFragments) + doc.Me = doc + xmlNode.Document = doc + //runtime.SetFinalizer(doc, (*XmlDocument).Free) + return +} + +// Parse creates an XmlDocument from some pre-existing content where the input encoding is known. Byte arrays created from +// a Go string are utf-8 encoded (you can pass DefaultEncodingBytes in this scenario). +// +// If you want to build up a document programmatically, calling CreateEmptyDocument and building it up using the xml.Node +// interface is a better approach than building a string and calling Parse. +// +// If you have an XML file, then ReadFile will automatically determine the encoding according to the XML specification. +func Parse(content, inEncoding, url []byte, options ParseOption, outEncoding []byte) (doc *XmlDocument, err error) { + inEncoding = AppendCStringTerminator(inEncoding) + outEncoding = AppendCStringTerminator(outEncoding) + + var docPtr *C.xmlDoc + contentLen := len(content) + + if contentLen > 0 { + var contentPtr, urlPtr, encodingPtr unsafe.Pointer + contentPtr = unsafe.Pointer(&content[0]) + + if len(url) > 0 { + url = AppendCStringTerminator(url) + urlPtr = unsafe.Pointer(&url[0]) + } + if len(inEncoding) > 0 { + encodingPtr = unsafe.Pointer(&inEncoding[0]) + } + + docPtr = C.xmlParse(contentPtr, C.int(contentLen), urlPtr, encodingPtr, C.int(options), nil, 0) + + if docPtr == nil { + err = ERR_FAILED_TO_PARSE_XML + } else { + doc = NewDocument(unsafe.Pointer(docPtr), contentLen, inEncoding, outEncoding) + } + + } else { + doc = CreateEmptyDocument(inEncoding, outEncoding) + } + return +} + +// ReadFile loads an XmlDocument from a filename. The encoding declared in the document will be +// used as the input encoding. If no encoding is declared, the library will use the alogrithm +// in the XML standard to determine if the document is encoded with UTF-8 or UTF-16. +func ReadFile(filename string, options ParseOption) (doc *XmlDocument, err error) { + // verify the file exists and can be read before we invoke C API + _, err = os.Stat(filename) + if err != nil { + return + } + + dataBytes := GetCString([]byte(filename)) + dataPtr := unsafe.Pointer(&dataBytes[0]) + var docPtr *C.xmlDoc + docPtr = C.xmlReadFile((*C.char)(dataPtr), nil, C.int(options)) + if docPtr == nil { + err = ERR_FAILED_TO_PARSE_XML + } else { + var encoding []byte + // capture the detected input encoding + p := docPtr.encoding + if p != nil { + encoding = []byte(C.GoString((*C.char)(unsafe.Pointer(p)))) + } + doc = NewDocument(unsafe.Pointer(docPtr), 0, encoding, DefaultEncodingBytes) + } + return +} + +// Create an empty XML document and return an XmlDocument. The root element, along with +// any top-level comments or processing instructions, can be added by calling +// AddChild() on the document itself. +func CreateEmptyDocument(inEncoding, outEncoding []byte) (doc *XmlDocument) { + help.LibxmlInitParser() + docPtr := C.newEmptyXmlDoc() + doc = NewDocument(unsafe.Pointer(docPtr), 0, inEncoding, outEncoding) + return +} + +// DocPtr provides access to the libxml2 structure underlying the document. +func (document *XmlDocument) DocPtr() (ptr unsafe.Pointer) { + ptr = unsafe.Pointer(document.Ptr) + return +} + +// DocType returns one of the node type constants, usually XML_DOCUMENT_NODE. This +// may be of use if you are working with the C API. +func (document *XmlDocument) DocType() (t NodeType) { + t = document.Type + return +} + +// DocRef returns the embedded Document interface. +func (document *XmlDocument) DocRef() (d Document) { + d = document.Me + return +} + +// InputEncoding is the original encoding of the document. +func (document *XmlDocument) InputEncoding() (encoding []byte) { + encoding = document.InEncoding + return +} + +// OutputEncoding is the encoding that will be used when the document is written out. +// This can be overridden by explicitly specifying an encoding as an argument to any of the +// output functions. +func (document *XmlDocument) OutputEncoding() (encoding []byte) { + encoding = document.OutEncoding + return +} + +// Returns an XPath context that can be used to compile and evaluate XPath +// expressions. +// +// In most cases, you should call the Search or EvalXPath functions instead of +// handling the context directly. +func (document *XmlDocument) DocXPathCtx() (ctx *xpath.XPath) { + ctx = document.XPathCtx + return +} + +func (document *XmlDocument) AddUnlinkedNode(nodePtr unsafe.Pointer) { + p := (*C.xmlNode)(nodePtr) + document.UnlinkedNodes[p] = true +} + +func (document *XmlDocument) RemoveUnlinkedNode(nodePtr unsafe.Pointer) bool { + p := (*C.xmlNode)(nodePtr) + if document.UnlinkedNodes[p] { + delete(document.UnlinkedNodes, p) + return true + } + return false +} + +func (document *XmlDocument) BookkeepFragment(fragment *DocumentFragment) { + document.fragments = append(document.fragments, fragment) +} + +// Root returns the root node of the document. Newly created documents do not +// have a root node until an element node is added a child of the document. +// +// Documents that have multiple root nodes are invalid and the behaviour is +// not well defined. +func (document *XmlDocument) Root() (element *ElementNode) { + nodePtr := C.xmlDocGetRootElement(document.Ptr) + if nodePtr != nil { + element = NewNode(unsafe.Pointer(nodePtr), document).(*ElementNode) + } + return +} + +// Get an element node by the value of its ID attribute. By convention this attribute +// is named id, but the actual name of the attribute is set by the document's DTD or schema. +// +// The value for an ID attribute is guaranteed to be unique within a valid document. +func (document *XmlDocument) NodeById(id string) (element *ElementNode) { + dataBytes := GetCString([]byte(id)) + dataPtr := unsafe.Pointer(&dataBytes[0]) + nodePtr := C.xmlGetID(document.Ptr, (*C.xmlChar)(dataPtr)) + if nodePtr != nil { + idattr := NewNode(unsafe.Pointer(nodePtr), document).(*AttributeNode) + element = idattr.Parent().(*ElementNode) + } + return +} + +/* +CreateElementNode creates an element node with the specified tag name. It can be +added as a child of any other element, or as a child of the document itself. + +Use SetNamespace if the element node needs to be in a namespace. + +Note that valid documents have only one child element, referred to as the root node. +*/ +func (document *XmlDocument) CreateElementNode(tag string) (element *ElementNode) { + tagBytes := GetCString([]byte(tag)) + tagPtr := unsafe.Pointer(&tagBytes[0]) + newNodePtr := C.xmlNewNode(nil, (*C.xmlChar)(tagPtr)) + newNode := NewNode(unsafe.Pointer(newNodePtr), document) + element = newNode.(*ElementNode) + return +} + +//CreateTextNode creates a text node. It can be added as a child of an element. +// +// The data argument is XML-escaped and used as the content of the node. +func (document *XmlDocument) CreateTextNode(data string) (text *TextNode) { + dataBytes := GetCString([]byte(data)) + dataPtr := unsafe.Pointer(&dataBytes[0]) + nodePtr := C.xmlNewText((*C.xmlChar)(dataPtr)) + if nodePtr != nil { + nodePtr.doc = (*C.xmlDoc)(document.DocPtr()) + text = NewNode(unsafe.Pointer(nodePtr), document).(*TextNode) + } + return +} + +//CreateCDataNode creates a CDATA node. CDATA nodes can +// only be children of an element. +// +// The data argument will become the content of the newly created node. +func (document *XmlDocument) CreateCDataNode(data string) (cdata *CDataNode) { + dataLen := len(data) + dataBytes := GetCString([]byte(data)) + dataPtr := unsafe.Pointer(&dataBytes[0]) + nodePtr := C.xmlNewCDataBlock(document.Ptr, (*C.xmlChar)(dataPtr), C.int(dataLen)) + if nodePtr != nil { + cdata = NewNode(unsafe.Pointer(nodePtr), document).(*CDataNode) + } + return +} + +//CreateCommentNode creates a comment node. Comment nodes can +// be children of an element or of the document itself. +// +// The data argument will become the content of the comment. +func (document *XmlDocument) CreateCommentNode(data string) (comment *CommentNode) { + dataBytes := GetCString([]byte(data)) + dataPtr := unsafe.Pointer(&dataBytes[0]) + nodePtr := C.xmlNewComment((*C.xmlChar)(dataPtr)) + if nodePtr != nil { + comment = NewNode(unsafe.Pointer(nodePtr), document).(*CommentNode) + } + return +} + +//CreatePINode creates a processing instruction node with the specified name and data. +// Processing instruction nodes can be children of an element or of the document itself. +// +// While it's common to use an attribute-like syntax for processing instructions, the data +// is actually an arbitrary string that you will need to generate or parse yourself. +func (document *XmlDocument) CreatePINode(name, data string) (pi *ProcessingInstructionNode) { + nameBytes := GetCString([]byte(name)) + namePtr := unsafe.Pointer(&nameBytes[0]) + dataBytes := GetCString([]byte(data)) + dataPtr := unsafe.Pointer(&dataBytes[0]) + nodePtr := C.xmlNewDocPI(document.Ptr, (*C.xmlChar)(namePtr), (*C.xmlChar)(dataPtr)) + if nodePtr != nil { + pi = NewNode(unsafe.Pointer(nodePtr), document).(*ProcessingInstructionNode) + } + return +} + +func (document *XmlDocument) ParseFragment(input, url []byte, options ParseOption) (fragment *DocumentFragment, err error) { + root := document.Root() + if root == nil { + fragment, err = parsefragment(document, nil, input, url, options) + } else { + fragment, err = parsefragment(document, root.XmlNode, input, url, options) + } + return +} + +// Return the value of an NDATA entity declared in the DTD. If there is no such entity or +// the value cannot be encoded as a valid URI, an empty string is returned. +// +// Note that this library assumes you already know the name of entity and does not +// expose any way of getting the list of entities. +func (document *XmlDocument) UnparsedEntityURI(name string) (val string) { + if name == "" { + return + } + + nameBytes := GetCString([]byte(name)) + namePtr := unsafe.Pointer(&nameBytes[0]) + entity := C.xmlGetDocEntity(document.Ptr, (*C.xmlChar)(namePtr)) + if entity == nil { + return + } + + // unlike entity.content (which returns the raw, unprocessed string value of the entity), + // it looks like entity.URI includes any escaping needed to treat the value as a URI. + valPtr := unsafe.Pointer(entity.URI) + if valPtr == nil { + return + } + + val = C.GoString((*C.char)(valPtr)) + return +} + +// Free the C structures associated with this document. +func (document *XmlDocument) Free() { + //must free the xpath context before freeing the fragments or unlinked nodes + //otherwise, it causes memory leaks and crashes when dealing with very large documents (a few MB) + if document.XPathCtx != nil { + document.XPathCtx.Free() + document.XPathCtx = nil + } + //must clear the fragments first + //because the nodes are put in the unlinked list + if document.fragments != nil { + for _, fragment := range document.fragments { + fragment.Remove() + } + } + document.fragments = nil + var p *C.xmlNode + if document.UnlinkedNodes != nil { + for p = range document.UnlinkedNodes { + C.xmlFreeNode(p) + } + } + document.UnlinkedNodes = nil + if document.Ptr != nil { + C.xmlFreeDoc(document.Ptr) + document.Ptr = nil + } +} + +/* Uri returns the URI of the document - typically this is the filename if ReadFile was used to parse +the document. +*/ +func (document *XmlDocument) Uri() (val string) { + val = C.GoString((*C.char)(unsafe.Pointer(document.Ptr.URL))) + return +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/element.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/element.go new file mode 100644 index 000000000..da6a92dcc --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/element.go @@ -0,0 +1,5 @@ +package xml + +type ElementNode struct { + *XmlNode +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/fragment.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/fragment.go new file mode 100644 index 000000000..7fc43f321 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/fragment.go @@ -0,0 +1,115 @@ +package xml + +//#include "helper.h" +import "C" +import ( + "errors" + . "github.com/jbowtie/gokogiri/util" + "unsafe" +) + +type DocumentFragment struct { + Node + InEncoding []byte + OutEncoding []byte +} + +var ( + fragmentWrapperStart = []byte("") + fragmentWrapperEnd = []byte("") +) + +var ErrFailParseFragment = errors.New("failed to parse xml fragment") +var ErrEmptyFragment = errors.New("empty xml fragment") + +const initChildrenNumber = 4 + +func parsefragment(document Document, node *XmlNode, content, url []byte, options ParseOption) (fragment *DocumentFragment, err error) { + //wrap the content before parsing + content = append(fragmentWrapperStart, content...) + content = append(content, fragmentWrapperEnd...) + + //set up pointers before calling the C function + var contentPtr, urlPtr unsafe.Pointer + contentPtr = unsafe.Pointer(&content[0]) + contentLen := len(content) + if len(url) > 0 { + url = AppendCStringTerminator(url) + urlPtr = unsafe.Pointer(&url[0]) + } + + var rootElementPtr *C.xmlNode + + if node == nil { + inEncoding := document.InputEncoding() + var encodingPtr unsafe.Pointer + if len(inEncoding) > 0 { + encodingPtr = unsafe.Pointer(&inEncoding[0]) + } + rootElementPtr = C.xmlParseFragmentAsDoc(document.DocPtr(), contentPtr, C.int(contentLen), urlPtr, encodingPtr, C.int(options), nil, 0) + + } else { + rootElementPtr = C.xmlParseFragment(node.NodePtr(), contentPtr, C.int(contentLen), urlPtr, C.int(options), nil, 0) + } + + //Note we've parsed the fragment within the given document + //the root is not the root of the document; rather it's the root of the subtree from the fragment + root := NewNode(unsafe.Pointer(rootElementPtr), document) + + //the fragment was in invalid + if root == nil { + err = ErrFailParseFragment + return + } + + fragment = &DocumentFragment{} + fragment.Node = root + fragment.InEncoding = document.InputEncoding() + fragment.OutEncoding = document.OutputEncoding() + + document.BookkeepFragment(fragment) + return +} + +func ParseFragment(content, inEncoding, url []byte, options ParseOption, outEncoding []byte) (fragment *DocumentFragment, err error) { + inEncoding = AppendCStringTerminator(inEncoding) + outEncoding = AppendCStringTerminator(outEncoding) + document := CreateEmptyDocument(inEncoding, outEncoding) + fragment, err = parsefragment(document, nil, content, url, options) + return +} + +func (fragment *DocumentFragment) Remove() { + fragment.Node.Remove() +} + +func (fragment *DocumentFragment) Children() []Node { + nodes := make([]Node, 0, initChildrenNumber) + child := fragment.FirstChild() + for ; child != nil; child = child.NextSibling() { + nodes = append(nodes, child) + } + return nodes +} + +func (fragment *DocumentFragment) ToBuffer(outputBuffer []byte) []byte { + var b []byte + var size int + for _, node := range fragment.Children() { + if docType := node.MyDocument().DocType(); docType == XML_HTML_DOCUMENT_NODE { + b, size = node.ToHtml(fragment.OutEncoding, nil) + } else { + b, size = node.ToXml(fragment.OutEncoding, nil) + } + outputBuffer = append(outputBuffer, b[:size]...) + } + return outputBuffer +} + +func (fragment *DocumentFragment) String() string { + b := fragment.ToBuffer(nil) + if b == nil { + return "" + } + return string(b) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.c b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.c new file mode 100644 index 000000000..e5cfa4ddb --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.c @@ -0,0 +1,195 @@ +#include +#include "helper.h" + +//internal callback functions +int xml_write_callback(void *ctx, char *buffer, int len) { + if (len > 0) { + xmlNodeWriteCallback(buffer, len); + } + return len; +} + +int close_callback(void * ctx) { + return 0; +} + +xmlDoc* newEmptyXmlDoc() { + return xmlNewDoc(BAD_CAST XML_DEFAULT_VERSION); +} + +xmlElementType getNodeType(xmlNode *node) { return node->type; } + +void xmlFreeChars(char *buffer) { + if (buffer) { + xmlFree((xmlChar*)buffer); + } +} + +char *xmlDocDumpToString(xmlDoc *doc, void *encoding, int format) { + xmlChar *buff; + int buffersize; + xmlDocDumpFormatMemoryEnc(doc, &buff, &buffersize, (char*)encoding, format); + return (char*)buff; +} + +char *htmlDocDumpToString(htmlDocPtr doc, int format) { + xmlChar *buff; + int buffersize; + htmlDocDumpMemoryFormat(doc, &buff, &buffersize, format); + return (char*)buff; +} + +xmlDoc* xmlParse(void *buffer, int buffer_len, void *url, void *encoding, int options, void *error_buffer, int error_buffer_len) { + const char *c_buffer = (char*)buffer; + const char *c_url = (char*)url; + const char *c_encoding = (char*)encoding; + xmlDoc *doc = NULL; + + xmlResetLastError(); + doc = xmlReadMemory(c_buffer, buffer_len, c_url, c_encoding, options); + + if(doc == NULL) { + xmlErrorPtr error; + xmlFreeDoc(doc); + error = xmlGetLastError(); + if(error != NULL && error_buffer != NULL && error->level >= XML_ERR_ERROR) { + char *c_error_buffer = (char*)error_buffer; + if (error->message != NULL) { + strncpy(c_error_buffer, error->message, error_buffer_len-1); + c_error_buffer[error_buffer_len-1] = '\0'; + } + else { + //snprintf(c_error_buffer, error_buffer_len, "xml parsing error:%d", error->code); + } + } + } + return doc; +} + +xmlNode* xmlParseFragment(void *doc, void *buffer, int buffer_len, void *url, int options, void *error_buffer, int error_buffer_len) { + xmlNodePtr root_element = NULL; + xmlParserErrors errCode; + errCode = xmlParseInNodeContext((xmlNodePtr)doc, buffer, buffer_len, options, &root_element); + if (errCode != XML_ERR_OK) { + if (error_buffer != NULL && error_buffer_len > 0) { + //char *c_error_buffer = (char*)error_buffer; + //snprintf(c_error_buffer, error_buffer_len, "xml fragemnt parsing error (xmlParserErrors):%d", errCode); + } + printf("errorcode %d\n", errCode); + return NULL; + } + return root_element; +} + +xmlNode* xmlParseFragmentAsDoc(void *doc, void *buffer, int buffer_len, void *url, void *encoding, int options, void *error_buffer, int error_buffer_len) { + xmlDoc* tmpDoc = NULL; + xmlNode* tmpRoot = NULL; + tmpDoc = xmlReadMemory((char*)buffer, buffer_len, (char*)url, (char*)encoding, options); + if (tmpDoc == NULL) { + return NULL; + } + tmpRoot = xmlDocGetRootElement(tmpDoc); + if (tmpRoot == NULL) { + return NULL; + } + tmpRoot = xmlDocCopyNode(tmpRoot, doc, 1); + xmlFreeDoc(tmpDoc); + return tmpRoot; +} + +void xmlSetContent(void *n, char *content) { + xmlNode *node = (xmlNode*)n; + xmlNode *child = node->children; + xmlNode *next = NULL; + unsigned char *encoded = xmlEncodeSpecialChars(node->doc, (xmlChar*)content); + if (encoded) { + while (child) { + next = child->next ; + xmlUnlinkNode(child); + //xmlFreeNode(child); + xmlUnlinkNodeCallback(child); + child = next ; + } + xmlNodeSetContent(node, (xmlChar*)encoded); + xmlFree(encoded); + } +} + +int xmlUnlinkNodeWithCheck(xmlNode *node) { + if (xmlNodePtrCheck(node->parent)) { + xmlUnlinkNode(node); + return 1; + } + return 0; +} + +int xmlNodePtrCheck(void *node) { + if (node == (void*)(-1)) + return 0; + return 1; +} + +int xmlSaveNode(void *node, void *encoding, int options) { + xmlSaveCtxtPtr savectx; + const char *c_encoding = (char*)encoding; + + savectx = xmlSaveToIO( + (xmlOutputWriteCallback)xml_write_callback, + (xmlOutputCloseCallback)close_callback, + NULL, + encoding, + options + ); + xmlSaveTree(savectx, (xmlNode*)node); + return xmlSaveClose(savectx); +} + +void removeNamespace(xmlNs **source, xmlNs *target) { + xmlNs *ns, *prevns = NULL; + + for (ns = *source; ns; ns = ns->next) { + if (ns == target) { + if (!prevns) { + // we are the first element + *source = ns->next; + } else { + prevns->next = ns->next; + } + + break; + } + + prevns = ns; + } +} + +void removeDefaultNamespace(xmlNs *ns, xmlNode *node) { + removeNamespace(&node->nsDef, ns); + + xmlAttr *attr; + + for (attr = node->properties; attr; attr = attr->next) { + if (!attr->ns) + continue; + + removeNamespace(&attr->ns, ns); + } + + if (node->ns == ns) + node->ns = NULL; + + xmlNode *child; + + for (child = xmlFirstElementChild(node); child; child = xmlNextElementSibling(child)) { + removeDefaultNamespace(ns, child); + } +} + +void xmlRemoveDefaultNamespace(xmlNode *node) { + if (node->ns && node->ns->prefix) { + // not a default namespace + return; + } + + removeDefaultNamespace(node->ns, node); +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.h b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.h new file mode 100644 index 000000000..16d3a5b97 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/helper.h @@ -0,0 +1,37 @@ +#ifndef __CHELPER_H__ +#define __CHELPER_H__ + +#include +#include +#include +#include +#include +#include +#include + +xmlDoc* xmlParse(void *buffer, int buffer_len, void *url, void *encoding, int options, void *error_buffer, int errror_buffer_len); +xmlNode* xmlParseFragment(void* doc, void *buffer, int buffer_len, void *url, int options, void *error_buffer, int error_buffer_len); +xmlNode* xmlParseFragmentAsDoc(void *doc, void *buffer, int buffer_len, void *url, void *encoding, int options, void *error_buffer, int error_buffer_len); +int xmlSaveNode(void *node, void *encoding, int options); +void xmlRemoveDefaultNamespace(xmlNode *node); + +void xmlSetContent(void *node, char *content); + +xmlDoc* newEmptyXmlDoc(); +xmlElementType getNodeType(xmlNode *node); +char *xmlDocDumpToString(xmlDoc *doc, void *encoding, int format); +char *htmlDocDumpToString(xmlDoc *doc, int format); +void xmlFreeChars(char *buffer); +int xmlUnlinkNodeWithCheck(xmlNode *node); +int xmlNodePtrCheck(void *node); +void xmlNodeWriteCallback(void *data, int data_len); +void xmlUnlinkNodeCallback(void *nodePtr); + +typedef struct XmlBufferContext { + void *obj; + char *buffer; + int buffer_len; + int data_size; +} XmlBufferContext; + +#endif //__CHELPER_H__ diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/node.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/node.go new file mode 100644 index 000000000..d94b02820 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/node.go @@ -0,0 +1,1186 @@ +package xml + +//#include "helper.h" +//#include +import "C" + +import ( + "errors" + "strconv" + "sync" + "unsafe" + + . "github.com/jbowtie/gokogiri/util" + "github.com/jbowtie/gokogiri/xpath" +) + +var ( + ERR_UNDEFINED_COERCE_PARAM = errors.New("unexpected parameter type in coerce") + ERR_UNDEFINED_SET_CONTENT_PARAM = errors.New("unexpected parameter type in SetContent") + ERR_UNDEFINED_SEARCH_PARAM = errors.New("unexpected parameter type in Search") + ERR_CANNOT_MAKE_DUCMENT_AS_CHILD = errors.New("cannot add a document node as a child") + ERR_CANNOT_COPY_TEXT_NODE_WHEN_ADD_CHILD = errors.New("cannot copy a text node when adding it") +) + +// NodeType is an enumeration that indicates the type of XmlNode. +type NodeType int + +const ( + XML_ELEMENT_NODE NodeType = iota + 1 + XML_ATTRIBUTE_NODE + XML_TEXT_NODE + XML_CDATA_SECTION_NODE + XML_ENTITY_REF_NODE + XML_ENTITY_NODE + XML_PI_NODE + XML_COMMENT_NODE + XML_DOCUMENT_NODE + XML_DOCUMENT_TYPE_NODE + XML_DOCUMENT_FRAG_NODE + XML_NOTATION_NODE + XML_HTML_DOCUMENT_NODE + XML_DTD_NODE + XML_ELEMENT_DECL + XML_ATTRIBUTE_DECL + XML_ENTITY_DECL + XML_NAMESPACE_DECL + XML_XINCLUDE_START + XML_XINCLUDE_END + XML_DOCB_DOCUMENT_NODE +) + +// SerializationOption is a set of flags used to control how a node is written out. +type SerializationOption int + +const ( + XML_SAVE_FORMAT SerializationOption = 1 << iota // format save output + XML_SAVE_NO_DECL //drop the xml declaration + XML_SAVE_NO_EMPTY //no empty tags + XML_SAVE_NO_XHTML //disable XHTML1 specific rules + XML_SAVE_XHTML //force XHTML1 specific rules + XML_SAVE_AS_XML //force XML serialization on HTML doc + XML_SAVE_AS_HTML //force HTML serialization on XML doc + XML_SAVE_WSNONSIG //format with non-significant whitespace +) + +// NamespaceDeclaration represents a namespace declaration, providing both the prefix and the URI of the namespace. +// It is returned by the DeclaredNamespaces function. +type NamespaceDeclaration struct { + Prefix string + Uri string +} + +type Node interface { + NodePtr() unsafe.Pointer + ResetNodePtr() + MyDocument() Document + + IsValid() bool + + ParseFragment([]byte, []byte, ParseOption) (*DocumentFragment, error) + LineNumber() int + + // + NodeType() NodeType + NextSibling() Node + PreviousSibling() Node + + Parent() Node + FirstChild() Node + LastChild() Node + CountChildren() int + Attributes() map[string]*AttributeNode + AttributeList() []*AttributeNode + + Coerce(interface{}) ([]Node, error) + + AddChild(interface{}) error + AddPreviousSibling(interface{}) error + AddNextSibling(interface{}) error + InsertBefore(interface{}) error + InsertAfter(interface{}) error + InsertBegin(interface{}) error + InsertEnd(interface{}) error + SetInnerHtml(interface{}) error + SetChildren(interface{}) error + Replace(interface{}) error + Wrap(string) error + + SetContent(interface{}) error + + Name() string + SetName(string) + + Attr(string) string + SetAttr(string, string) string + SetNsAttr(string, string, string) string + Attribute(string) *AttributeNode + + Path() string + + Duplicate(int) Node + DuplicateTo(Document, int) Node + + Search(interface{}) ([]Node, error) + SearchWithVariables(interface{}, xpath.VariableScope) ([]Node, error) + EvalXPath(interface{}, xpath.VariableScope) (interface{}, error) + EvalXPathAsBoolean(interface{}, xpath.VariableScope) bool + + Unlink() + Remove() + ResetChildren() + + SerializeWithFormat(SerializationOption, []byte, []byte) ([]byte, int) + ToXml([]byte, []byte) ([]byte, int) + ToUnformattedXml() string + ToHtml([]byte, []byte) ([]byte, int) + ToBuffer([]byte) []byte + String() string + Content() string + InnerHtml() string + + RecursivelyRemoveNamespaces() error + Namespace() string + SetNamespace(string, string) + DeclareNamespace(string, string) + RemoveDefaultNamespace() + DeclaredNamespaces() []NamespaceDeclaration +} + +//run out of memory +var ErrTooLarge = errors.New("Output buffer too large") + +//pre-allocate a buffer for serializing the document +const initialOutputBufferSize = 10 //100K + +/* +XmlNode implements the Node interface, and as such is the heart of the API. +*/ +type XmlNode struct { + Ptr *C.xmlNode + Document + valid bool +} + +type WriteBuffer struct { + Node *XmlNode + Buffer []byte + Offset int +} + +// NewNode takes a C pointer from the libxml2 library and returns a Node instance of +// the appropriate type. +func NewNode(nodePtr unsafe.Pointer, document Document) (node Node) { + if nodePtr == nil { + return nil + } + xmlNode := &XmlNode{ + Ptr: (*C.xmlNode)(nodePtr), + Document: document, + valid: true, + } + nodeType := NodeType(C.getNodeType((*C.xmlNode)(nodePtr))) + + switch nodeType { + default: + node = xmlNode + case XML_ATTRIBUTE_NODE: + node = &AttributeNode{XmlNode: xmlNode} + case XML_ELEMENT_NODE: + node = &ElementNode{XmlNode: xmlNode} + case XML_CDATA_SECTION_NODE: + node = &CDataNode{XmlNode: xmlNode} + case XML_COMMENT_NODE: + node = &CommentNode{XmlNode: xmlNode} + case XML_PI_NODE: + node = &ProcessingInstructionNode{XmlNode: xmlNode} + case XML_TEXT_NODE: + node = &TextNode{XmlNode: xmlNode} + } + return +} + +func (xmlNode *XmlNode) coerce(data interface{}) (nodes []Node, err error) { + switch t := data.(type) { + default: + err = ERR_UNDEFINED_COERCE_PARAM + case []Node: + nodes = t + case *DocumentFragment: + nodes = t.Children() + case string: + f, err := xmlNode.MyDocument().ParseFragment([]byte(t), nil, DefaultParseOption) + if err == nil { + nodes = f.Children() + } + case []byte: + f, err := xmlNode.MyDocument().ParseFragment(t, nil, DefaultParseOption) + if err == nil { + nodes = f.Children() + } + } + return +} + +func (xmlNode *XmlNode) Coerce(data interface{}) (nodes []Node, err error) { + return xmlNode.coerce(data) +} + +// Add a node as a child of the current node. +// Passing in a nodeset will add all the nodes as children of the current node. +func (xmlNode *XmlNode) AddChild(data interface{}) (err error) { + switch t := data.(type) { + default: + if nodes, err := xmlNode.coerce(data); err == nil { + for _, node := range nodes { + if err = xmlNode.addChild(node); err != nil { + break + } + } + } + case *DocumentFragment: + if nodes, err := xmlNode.coerce(data); err == nil { + for _, node := range nodes { + if err = xmlNode.addChild(node); err != nil { + break + } + } + } + case Node: + err = xmlNode.addChild(t) + } + return +} + +// Insert a node immediately before this node in the document. +// Passing in a nodeset will add all the nodes, in order. +func (xmlNode *XmlNode) AddPreviousSibling(data interface{}) (err error) { + switch t := data.(type) { + default: + if nodes, err := xmlNode.coerce(data); err == nil { + for _, node := range nodes { + if err = xmlNode.addPreviousSibling(node); err != nil { + break + } + } + } + case *DocumentFragment: + if nodes, err := xmlNode.coerce(data); err == nil { + for _, node := range nodes { + if err = xmlNode.addPreviousSibling(node); err != nil { + break + } + } + } + case Node: + err = xmlNode.addPreviousSibling(t) + } + return +} + +// Insert a node immediately after this node in the document. +// Passing in a nodeset will add all the nodes, in order. +func (xmlNode *XmlNode) AddNextSibling(data interface{}) (err error) { + switch t := data.(type) { + default: + if nodes, err := xmlNode.coerce(data); err == nil { + for i := len(nodes) - 1; i >= 0; i-- { + node := nodes[i] + if err = xmlNode.addNextSibling(node); err != nil { + break + } + } + } + case *DocumentFragment: + if nodes, err := xmlNode.coerce(data); err == nil { + for i := len(nodes) - 1; i >= 0; i-- { + node := nodes[i] + if err = xmlNode.addNextSibling(node); err != nil { + break + } + } + } + case Node: + err = xmlNode.addNextSibling(t) + } + return +} + +func (xmlNode *XmlNode) ResetNodePtr() { + xmlNode.Ptr = nil + return +} + +// Returns true if the node is valid. Nodes become +// invalid when Remove() is called. +func (xmlNode *XmlNode) IsValid() bool { + return xmlNode.valid +} + +// Return the document containing this node. Removed or unlinked +// nodes still have a document associated with them. +func (xmlNode *XmlNode) MyDocument() (document Document) { + document = xmlNode.Document.DocRef() + return +} + +// NodePtr returns a pointer to the underlying C struct. +func (xmlNode *XmlNode) NodePtr() (p unsafe.Pointer) { + p = unsafe.Pointer(xmlNode.Ptr) + return +} + +func (xmlNode *XmlNode) NodeType() (nodeType NodeType) { + nodeType = NodeType(C.getNodeType(xmlNode.Ptr)) + return +} + +// Path returns an XPath expression that can be used to +// select this node in the document. +func (xmlNode *XmlNode) Path() (path string) { + pathPtr := C.xmlGetNodePath(xmlNode.Ptr) + if pathPtr != nil { + p := (*C.char)(unsafe.Pointer(pathPtr)) + defer C.xmlFreeChars(p) + path = C.GoString(p) + } + return +} + +// NextSibling returns the next sibling (if any) of the current node. +// It is often used when iterating over the children of a node. +func (xmlNode *XmlNode) NextSibling() Node { + siblingPtr := (*C.xmlNode)(xmlNode.Ptr.next) + return NewNode(unsafe.Pointer(siblingPtr), xmlNode.Document) +} + +// PreviousSibling returns the previous sibling (if any) of the current node. +// It is often used when iterating over the children of a node in reverse. +func (xmlNode *XmlNode) PreviousSibling() Node { + siblingPtr := (*C.xmlNode)(xmlNode.Ptr.prev) + return NewNode(unsafe.Pointer(siblingPtr), xmlNode.Document) +} + +// CountChildren returns the number of child nodes. +func (xmlNode *XmlNode) CountChildren() int { + return int(C.xmlLsCountNode(xmlNode.Ptr)) +} + +func (xmlNode *XmlNode) FirstChild() Node { + return NewNode(unsafe.Pointer(xmlNode.Ptr.children), xmlNode.Document) +} + +func (xmlNode *XmlNode) LastChild() Node { + return NewNode(unsafe.Pointer(xmlNode.Ptr.last), xmlNode.Document) +} + +/* +Parent returns the parent of the current node (or nil if there isn't one). +This will always be an element or document node, as those are the only node types +that can have children. +*/ +func (xmlNode *XmlNode) Parent() Node { + if C.xmlNodePtrCheck(unsafe.Pointer(xmlNode.Ptr.parent)) == C.int(0) { + return nil + } + return NewNode(unsafe.Pointer(xmlNode.Ptr.parent), xmlNode.Document) +} + +func (xmlNode *XmlNode) ResetChildren() { + var p unsafe.Pointer + for childPtr := xmlNode.Ptr.children; childPtr != nil; { + nextPtr := childPtr.next + p = unsafe.Pointer(childPtr) + C.xmlUnlinkNodeWithCheck((*C.xmlNode)(p)) + xmlNode.Document.AddUnlinkedNode(p) + childPtr = nextPtr + } +} + +var ( + contentNode *XmlNode + contentMutex sync.Mutex +) + +func (xmlNode *XmlNode) SetContent(content interface{}) (err error) { + switch data := content.(type) { + default: + err = ERR_UNDEFINED_SET_CONTENT_PARAM + case string: + contentMutex.Lock() + contentNode = xmlNode + C.xmlSetContent(unsafe.Pointer(xmlNode.Ptr), C.CString(data)) + contentNode = nil + contentMutex.Unlock() + case []byte: + err = xmlNode.SetContent(string(data)) + } + return +} + +func (xmlNode *XmlNode) InsertBefore(data interface{}) (err error) { + err = xmlNode.AddPreviousSibling(data) + return +} + +func (xmlNode *XmlNode) InsertAfter(data interface{}) (err error) { + err = xmlNode.AddNextSibling(data) + return +} + +func (xmlNode *XmlNode) InsertBegin(data interface{}) (err error) { + if parent := xmlNode.Parent(); parent != nil { + if last := parent.LastChild(); last != nil { + err = last.AddPreviousSibling(data) + } + } + return +} + +func (xmlNode *XmlNode) InsertEnd(data interface{}) (err error) { + if parent := xmlNode.Parent(); parent != nil { + if first := parent.FirstChild(); first != nil { + err = first.AddPreviousSibling(data) + } + } + return +} + +func (xmlNode *XmlNode) SetChildren(data interface{}) (err error) { + nodes, err := xmlNode.coerce(data) + if err != nil { + return + } + xmlNode.ResetChildren() + err = xmlNode.AddChild(nodes) + return nil +} + +func (xmlNode *XmlNode) SetInnerHtml(data interface{}) (err error) { + err = xmlNode.SetChildren(data) + return +} + +func (xmlNode *XmlNode) Replace(data interface{}) (err error) { + err = xmlNode.AddPreviousSibling(data) + if err != nil { + return + } + xmlNode.Remove() + return +} + +// Return a document-ordered list of attribute nodes. +func (xmlNode *XmlNode) AttributeList() (attributes []*AttributeNode) { + for prop := xmlNode.Ptr.properties; prop != nil; prop = prop.next { + if prop.name != nil { + attrPtr := unsafe.Pointer(prop) + attributeNode := NewNode(attrPtr, xmlNode.Document) + if attr, ok := attributeNode.(*AttributeNode); ok { + attributes = append(attributes, attr) + } + } + } + return +} + +// Return the attribute nodes indexed by name. +func (xmlNode *XmlNode) Attributes() (attributes map[string]*AttributeNode) { + attributes = make(map[string]*AttributeNode) + for prop := xmlNode.Ptr.properties; prop != nil; prop = prop.next { + if prop.name != nil { + namePtr := unsafe.Pointer(prop.name) + name := C.GoString((*C.char)(namePtr)) + attrPtr := unsafe.Pointer(prop) + attributeNode := NewNode(attrPtr, xmlNode.Document) + if attr, ok := attributeNode.(*AttributeNode); ok { + attributes[name] = attr + } + } + } + return +} + +// Return the attribute node, or nil if the attribute does not exist. +func (xmlNode *XmlNode) Attribute(name string) (attribute *AttributeNode) { + if xmlNode.NodeType() != XML_ELEMENT_NODE { + return + } + nameBytes := GetCString([]byte(name)) + namePtr := unsafe.Pointer(&nameBytes[0]) + attrPtr := C.xmlHasNsProp(xmlNode.Ptr, (*C.xmlChar)(namePtr), nil) + if attrPtr == nil { + return + } else { + node := NewNode(unsafe.Pointer(attrPtr), xmlNode.Document) + if node, ok := node.(*AttributeNode); ok { + attribute = node + } + } + return +} + +// Attr returns the value of an attribute. +// +// If you need to check for the existence of an attribute, +// use Attribute. +func (xmlNode *XmlNode) Attr(name string) (val string) { + if xmlNode.NodeType() != XML_ELEMENT_NODE { + return + } + nameBytes := GetCString([]byte(name)) + namePtr := unsafe.Pointer(&nameBytes[0]) + valPtr := C.xmlGetProp(xmlNode.Ptr, (*C.xmlChar)(namePtr)) + if valPtr == nil { + return + } + p := unsafe.Pointer(valPtr) + defer C.xmlFreeChars((*C.char)(p)) + val = C.GoString((*C.char)(p)) + return +} + +// SetAttr sets the value of an attribute. If the attribute is in a namespace, +// use SetNsAttr instead. +// +// While this call accepts QNames for the name parameter, it does not check +// their validity. +// +// Attributes such as "xml:lang" or "xml:space" are not is a formal namespace +// and should be set by calling SetAttr with the prefix as part of the name. +func (xmlNode *XmlNode) SetAttr(name, value string) (val string) { + val = value + if xmlNode.NodeType() != XML_ELEMENT_NODE { + return + } + nameBytes := GetCString([]byte(name)) + namePtr := unsafe.Pointer(&nameBytes[0]) + + valueBytes := GetCString([]byte(value)) + valuePtr := unsafe.Pointer(&valueBytes[0]) + + C.xmlSetProp(xmlNode.Ptr, (*C.xmlChar)(namePtr), (*C.xmlChar)(valuePtr)) + return +} + +// SetNsAttr sets the value of a namespaced attribute. +// +// Attributes such as "xml:lang" or "xml:space" are not is a formal namespace +// and should be set by calling SetAttr with the xml prefix as part of the name. +// +// The namespace should already be declared and in-scope when SetNsAttr is called. +// This restriction will be lifted in a future version. +func (xmlNode *XmlNode) SetNsAttr(href, name, value string) (val string) { + val = value + if xmlNode.NodeType() != XML_ELEMENT_NODE { + return + } + nameBytes := GetCString([]byte(name)) + namePtr := unsafe.Pointer(&nameBytes[0]) + + valueBytes := GetCString([]byte(value)) + valuePtr := unsafe.Pointer(&valueBytes[0]) + + hrefBytes := GetCString([]byte(href)) + hrefPtr := unsafe.Pointer(&hrefBytes[0]) + + ns := C.xmlSearchNsByHref((*C.xmlDoc)(xmlNode.Document.DocPtr()), xmlNode.Ptr, (*C.xmlChar)(hrefPtr)) + if ns == nil { + return + } + + C.xmlSetNsProp(xmlNode.Ptr, ns, (*C.xmlChar)(namePtr), (*C.xmlChar)(valuePtr)) + return +} + +// Search for nodes that match an XPath. This is the simplest way to look for nodes. +func (xmlNode *XmlNode) Search(data interface{}) (result []Node, err error) { + switch data := data.(type) { + default: + err = ERR_UNDEFINED_SEARCH_PARAM + case string: + if xpathExpr := xpath.Compile(data); xpathExpr != nil { + defer xpathExpr.Free() + result, err = xmlNode.Search(xpathExpr) + } else { + err = errors.New("cannot compile xpath: " + data) + } + case []byte: + result, err = xmlNode.Search(string(data)) + case *xpath.Expression: + xpathCtx := xmlNode.Document.DocXPathCtx() + nodePtrs, err := xpathCtx.EvaluateAsNodeset(unsafe.Pointer(xmlNode.Ptr), data) + if nodePtrs == nil || err != nil { + return nil, err + } + for _, nodePtr := range nodePtrs { + result = append(result, NewNode(nodePtr, xmlNode.Document)) + } + } + return +} + +// As the Search function, but passing a VariableScope that can be used to reolve variable +// names or registered function references in the XPath being evaluated. +func (xmlNode *XmlNode) SearchWithVariables(data interface{}, v xpath.VariableScope) (result []Node, err error) { + switch data := data.(type) { + default: + err = ERR_UNDEFINED_SEARCH_PARAM + case string: + if xpathExpr := xpath.Compile(data); xpathExpr != nil { + defer xpathExpr.Free() + result, err = xmlNode.SearchWithVariables(xpathExpr, v) + } else { + err = errors.New("cannot compile xpath: " + data) + } + case []byte: + result, err = xmlNode.SearchWithVariables(string(data), v) + case *xpath.Expression: + xpathCtx := xmlNode.Document.DocXPathCtx() + xpathCtx.SetResolver(v) + nodePtrs, err := xpathCtx.EvaluateAsNodeset(unsafe.Pointer(xmlNode.Ptr), data) + if nodePtrs == nil || err != nil { + return nil, err + } + for _, nodePtr := range nodePtrs { + result = append(result, NewNode(nodePtr, xmlNode.Document)) + } + } + return +} + +// Evaluate an XPath and return a result of the appropriate type. +// If a non-nil VariableScope is provided, any variables or functions present +// in the xpath will be resolved. +// +// If the result is a nodeset (or the empty nodeset), a nodeset will be returned. +// +// If the result is a number, a float64 will be returned. +// +// If the result is a boolean, a bool will be returned. +// +// In any other cases, the result will be coerced to a string. +func (xmlNode *XmlNode) EvalXPath(data interface{}, v xpath.VariableScope) (result interface{}, err error) { + switch data := data.(type) { + case string: + if xpathExpr := xpath.Compile(data); xpathExpr != nil { + defer xpathExpr.Free() + result, err = xmlNode.EvalXPath(xpathExpr, v) + } else { + err = errors.New("cannot compile xpath: " + data) + } + case []byte: + result, err = xmlNode.EvalXPath(string(data), v) + case *xpath.Expression: + xpathCtx := xmlNode.Document.DocXPathCtx() + xpathCtx.SetResolver(v) + err := xpathCtx.Evaluate(unsafe.Pointer(xmlNode.Ptr), data) + if err != nil { + return nil, err + } + rt := xpathCtx.ReturnType() + switch rt { + case xpath.XPATH_NODESET, xpath.XPATH_XSLT_TREE: + nodePtrs, err := xpathCtx.ResultAsNodeset() + if err != nil { + return nil, err + } + var output []Node + for _, nodePtr := range nodePtrs { + output = append(output, NewNode(nodePtr, xmlNode.Document)) + } + result = output + case xpath.XPATH_NUMBER: + result, _ = xpathCtx.ResultAsNumber() + case xpath.XPATH_BOOLEAN: + result, _ = xpathCtx.ResultAsBoolean() + default: + result, _ = xpathCtx.ResultAsString() + } + default: + err = ERR_UNDEFINED_SEARCH_PARAM + } + return +} + +// Evaluate an XPath and coerce the result to a boolean according to the +// XPath rules. In the presence of an error, this function will return false +// even if the expression cannot actually be evaluated. +// +// In most cases you are better advised to call EvalXPath; this function is +// intended for packages that implement XML standards and that are fully aware +// of the consequences of suppressing a compilation error. +// +// If a non-nil VariableScope is provided, any variables or registered functions present +// in the xpath will be resolved. +func (xmlNode *XmlNode) EvalXPathAsBoolean(data interface{}, v xpath.VariableScope) (result bool) { + switch data := data.(type) { + case string: + if xpathExpr := xpath.Compile(data); xpathExpr != nil { + defer xpathExpr.Free() + result = xmlNode.EvalXPathAsBoolean(xpathExpr, v) + } else { + //err = errors.New("cannot compile xpath: " + data) + } + case []byte: + result = xmlNode.EvalXPathAsBoolean(string(data), v) + case *xpath.Expression: + xpathCtx := xmlNode.Document.DocXPathCtx() + xpathCtx.SetResolver(v) + err := xpathCtx.Evaluate(unsafe.Pointer(xmlNode.Ptr), data) + if err != nil { + return false + } + result, _ = xpathCtx.ResultAsBoolean() + default: + //err = ERR_UNDEFINED_SEARCH_PARAM + } + return +} + +// The local name of the node. Use Namespace() to get the namespace. +func (xmlNode *XmlNode) Name() (name string) { + if xmlNode.Ptr.name != nil { + p := unsafe.Pointer(xmlNode.Ptr.name) + name = C.GoString((*C.char)(p)) + } + return +} + +// The namespace of the node. This is the empty string if there +// no associated namespace. +func (xmlNode *XmlNode) Namespace() (href string) { + if xmlNode.Ptr.ns != nil { + p := unsafe.Pointer(xmlNode.Ptr.ns.href) + href = C.GoString((*C.char)(p)) + } + return +} + +// Set the local name of the node. The namespace is set via SetNamespace(). +func (xmlNode *XmlNode) SetName(name string) { + if len(name) > 0 { + nameBytes := GetCString([]byte(name)) + namePtr := unsafe.Pointer(&nameBytes[0]) + C.xmlNodeSetName(xmlNode.Ptr, (*C.xmlChar)(namePtr)) + } +} + +func (xmlNode *XmlNode) Duplicate(level int) Node { + return xmlNode.DuplicateTo(xmlNode.Document, level) +} + +func (xmlNode *XmlNode) DuplicateTo(doc Document, level int) (dup Node) { + if xmlNode.valid { + dupPtr := C.xmlDocCopyNode(xmlNode.Ptr, (*C.xmlDoc)(doc.DocPtr()), C.int(level)) + if dupPtr != nil { + dup = NewNode(unsafe.Pointer(dupPtr), xmlNode.Document) + } + } + return +} + +func (xmlNode *XmlNode) serialize(format SerializationOption, encoding, outputBuffer []byte) ([]byte, int) { + nodePtr := unsafe.Pointer(xmlNode.Ptr) + var encodingPtr unsafe.Pointer + if len(encoding) == 0 { + encoding = xmlNode.Document.OutputEncoding() + } + if len(encoding) > 0 { + encodingPtr = unsafe.Pointer(&(encoding[0])) + } else { + encodingPtr = nil + } + + wbufferMutex.Lock() + defer wbufferMutex.Unlock() + if outputBuffer == nil { + outputBuffer = make([]byte, 0) + } + wbuffer = &WriteBuffer{Node: xmlNode, Buffer: outputBuffer} + + ret := int(C.xmlSaveNode(nodePtr, encodingPtr, C.int(format))) + if ret < 0 { + panic("output error in xml node serialization: " + strconv.Itoa(ret)) + } + b, o := wbuffer.Buffer, wbuffer.Offset + wbuffer = nil + + return b, o +} + +// SerializeWithFormat allows you to control the serialization flags passed to libxml. +// In most cases ToXml() and ToHtml() provide sensible defaults and should be preferred. +// +// The format parameter should be a set of SerializationOption constants or'd together. +// If encoding is nil, the document's output encoding is used - this defaults to UTF-8. +// If outputBuffer is nil, one will be created for you. +func (xmlNode *XmlNode) SerializeWithFormat(format SerializationOption, encoding, outputBuffer []byte) ([]byte, int) { + return xmlNode.serialize(format, encoding, outputBuffer) +} + +// ToXml generates an indented XML document with an XML declaration. +// It is not guaranteed to be well formed unless xmlNode is an element node, +// or a document node with only one element child. +// +// If you need finer control over the formatting, call SerializeWithFormat. +// +// If encoding is nil, the document's output encoding is used - this defaults to UTF-8. +// If outputBuffer is nil, one will be created for you. +func (xmlNode *XmlNode) ToXml(encoding, outputBuffer []byte) ([]byte, int) { + return xmlNode.serialize(XML_SAVE_AS_XML|XML_SAVE_FORMAT, encoding, outputBuffer) +} + +// ToUnformattedXml generates an unformatted XML document without an XML declaration. +// This is useful for conforming to various standards and for unit testing, although +// the output is not guaranteed to be well formed unless xmlNode is an element node. +func (xmlNode *XmlNode) ToUnformattedXml() string { + var b []byte + var size int + b, size = xmlNode.serialize(XML_SAVE_AS_XML|XML_SAVE_NO_DECL, nil, nil) + if b == nil { + return "" + } + return string(b[:size]) +} + +// ToHtml generates an indented XML document that conforms to HTML 4.0 rules; meaning +// that some elements may be unclosed or forced to use end tags even when empty. +// +// If you want to output XHTML, call SerializeWithFormat and enable the XML_SAVE_XHTML +// flag as part of the format. +// +// If encoding is nil, the document's output encoding is used - this defaults to UTF-8. +// If outputBuffer is nil, one will be created for you. +func (xmlNode *XmlNode) ToHtml(encoding, outputBuffer []byte) ([]byte, int) { + return xmlNode.serialize(XML_SAVE_AS_HTML|XML_SAVE_FORMAT, encoding, outputBuffer) +} + +func (xmlNode *XmlNode) ToBuffer(outputBuffer []byte) []byte { + var b []byte + var size int + if docType := xmlNode.Document.DocType(); docType == XML_HTML_DOCUMENT_NODE { + b, size = xmlNode.ToHtml(nil, outputBuffer) + } else { + b, size = xmlNode.ToXml(nil, outputBuffer) + } + return b[:size] +} + +func (xmlNode *XmlNode) String() string { + b := xmlNode.ToBuffer(nil) + if b == nil { + return "" + } + return string(b) +} + +func (xmlNode *XmlNode) Content() string { + contentPtr := C.xmlNodeGetContent(xmlNode.Ptr) + charPtr := (*C.char)(unsafe.Pointer(contentPtr)) + defer C.xmlFreeChars(charPtr) + return C.GoString(charPtr) +} + +func (xmlNode *XmlNode) InnerHtml() string { + out := "" + + for child := xmlNode.FirstChild(); child != nil; child = child.NextSibling() { + out += child.String() + } + return out +} + +func (xmlNode *XmlNode) Unlink() { + if int(C.xmlUnlinkNodeWithCheck(xmlNode.Ptr)) != 0 { + xmlNode.Document.AddUnlinkedNode(unsafe.Pointer(xmlNode.Ptr)) + } +} + +func (xmlNode *XmlNode) Remove() { + if xmlNode.valid && unsafe.Pointer(xmlNode.Ptr) != xmlNode.Document.DocPtr() { + xmlNode.Unlink() + xmlNode.valid = false + } +} + +func (xmlNode *XmlNode) addChild(node Node) (err error) { + nodeType := node.NodeType() + if nodeType == XML_DOCUMENT_NODE || nodeType == XML_HTML_DOCUMENT_NODE { + err = ERR_CANNOT_MAKE_DUCMENT_AS_CHILD + return + } + nodePtr := node.NodePtr() + if xmlNode.NodePtr() == nodePtr { + return + } + ret := xmlNode.isAccestor(nodePtr) + if ret < 0 { + return + } else if ret == 0 { + if !xmlNode.Document.RemoveUnlinkedNode(nodePtr) { + C.xmlUnlinkNodeWithCheck((*C.xmlNode)(nodePtr)) + } + C.xmlAddChild(xmlNode.Ptr, (*C.xmlNode)(nodePtr)) + } else if ret > 0 { + node.Remove() + } + + return +} + +func (xmlNode *XmlNode) addPreviousSibling(node Node) (err error) { + nodeType := node.NodeType() + if nodeType == XML_DOCUMENT_NODE || nodeType == XML_HTML_DOCUMENT_NODE { + err = ERR_CANNOT_MAKE_DUCMENT_AS_CHILD + return + } + nodePtr := node.NodePtr() + if xmlNode.NodePtr() == nodePtr { + return + } + ret := xmlNode.isAccestor(nodePtr) + if ret < 0 { + return + } else if ret == 0 { + if !xmlNode.Document.RemoveUnlinkedNode(nodePtr) { + C.xmlUnlinkNodeWithCheck((*C.xmlNode)(nodePtr)) + } + C.xmlAddPrevSibling(xmlNode.Ptr, (*C.xmlNode)(nodePtr)) + } else if ret > 0 { + node.Remove() + } + return +} + +func (xmlNode *XmlNode) addNextSibling(node Node) (err error) { + nodeType := node.NodeType() + if nodeType == XML_DOCUMENT_NODE || nodeType == XML_HTML_DOCUMENT_NODE { + err = ERR_CANNOT_MAKE_DUCMENT_AS_CHILD + return + } + nodePtr := node.NodePtr() + if xmlNode.NodePtr() == nodePtr { + return + } + ret := xmlNode.isAccestor(nodePtr) + if ret < 0 { + return + } else if ret == 0 { + if !xmlNode.Document.RemoveUnlinkedNode(nodePtr) { + C.xmlUnlinkNodeWithCheck((*C.xmlNode)(nodePtr)) + } + C.xmlAddNextSibling(xmlNode.Ptr, (*C.xmlNode)(nodePtr)) + } else if ret > 0 { + node.Remove() + } + return +} + +func (xmlNode *XmlNode) Wrap(data string) (err error) { + newNodes, err := xmlNode.coerce(data) + if err == nil && len(newNodes) > 0 { + newParent := newNodes[0] + xmlNode.addNextSibling(newParent) + newParent.AddChild(xmlNode) + } + return +} + +func (xmlNode *XmlNode) ParseFragment(input, url []byte, options ParseOption) (fragment *DocumentFragment, err error) { + fragment, err = parsefragment(xmlNode.Document, xmlNode, input, url, options) + return +} + +var ( + wbuffer *WriteBuffer + wbufferMutex sync.Mutex +) + +//export xmlNodeWriteCallback +// NOTE: wbufferMutex is locked +func xmlNodeWriteCallback(data unsafe.Pointer, data_len C.int) { + offset := wbuffer.Offset + + if offset > len(wbuffer.Buffer) { + panic("fatal error in xmlNodeWriteCallback") + } + + buffer := wbuffer.Buffer[:offset] + dataLen := int(data_len) + + if dataLen > 0 { + if len(buffer)+dataLen > cap(buffer) { + newBuffer := grow(buffer, dataLen) + wbuffer.Buffer = newBuffer + } + destBufPtr := unsafe.Pointer(&(wbuffer.Buffer[offset])) + C.memcpy(destBufPtr, data, C.size_t(dataLen)) + wbuffer.Offset += dataLen + } +} + +//export xmlUnlinkNodeCallback +// NOTE: contentMutex is locked +func xmlUnlinkNodeCallback(nodePtr unsafe.Pointer) { + contentNode.Document.AddUnlinkedNode(nodePtr) +} + +func grow(buffer []byte, n int) (newBuffer []byte) { + newBuffer = makeSlice(2*cap(buffer) + n) + copy(newBuffer, buffer) + return +} + +func makeSlice(n int) []byte { + // If the make fails, give a known error. + defer func() { + if recover() != nil { + panic(ErrTooLarge) + } + }() + return make([]byte, n) +} + +func (xmlNode *XmlNode) isAccestor(nodePtr unsafe.Pointer) int { + parentPtr := xmlNode.Ptr.parent + + if C.xmlNodePtrCheck(unsafe.Pointer(parentPtr)) == C.int(0) { + return -1 + } + for ; parentPtr != nil; parentPtr = parentPtr.parent { + if C.xmlNodePtrCheck(unsafe.Pointer(parentPtr)) == C.int(0) { + return -1 + } + p := unsafe.Pointer(parentPtr) + if p == nodePtr { + return 1 + } + } + return 0 +} + +func (xmlNode *XmlNode) RecursivelyRemoveNamespaces() (err error) { + nodePtr := xmlNode.Ptr + C.xmlSetNs(nodePtr, nil) + + for child := xmlNode.FirstChild(); child != nil; { + child.RecursivelyRemoveNamespaces() + child = child.NextSibling() + } + + nodeType := xmlNode.NodeType() + + if ((nodeType == XML_ELEMENT_NODE) || + (nodeType == XML_XINCLUDE_START) || + (nodeType == XML_XINCLUDE_END)) && + (nodePtr.nsDef != nil) { + C.xmlFreeNsList((*C.xmlNs)(nodePtr.nsDef)) + nodePtr.nsDef = nil + } + + if nodeType == XML_ELEMENT_NODE && nodePtr.properties != nil { + property := nodePtr.properties + for property != nil { + if property.ns != nil { + property.ns = nil + } + property = property.next + } + } + return +} + +func (xmlNode *XmlNode) RemoveDefaultNamespace() { + nodePtr := xmlNode.Ptr + C.xmlRemoveDefaultNamespace(nodePtr) +} + +// Returns a list of all the namespace declarations that exist on this node. +// +// You can add a namespace declaration by calling DeclareNamespace. +// Calling SetNamespace will automatically add a declaration if required. +// +// Calling SetNsAttr does *not* automatically create a declaration. This will +// fixed in a future version. +func (xmlNode *XmlNode) DeclaredNamespaces() (result []NamespaceDeclaration) { + nodePtr := xmlNode.Ptr + for ns := nodePtr.nsDef; ns != nil; ns = (*C.xmlNs)(ns.next) { + prefixPtr := unsafe.Pointer(ns.prefix) + prefix := C.GoString((*C.char)(prefixPtr)) + hrefPtr := unsafe.Pointer(ns.href) + uri := C.GoString((*C.char)(hrefPtr)) + decl := NamespaceDeclaration{prefix, uri} + result = append(result, decl) + } + return +} + +// Add a namespace declaration to an element. +// +// This is typically done on the root element or node high up in the tree +// to avoid duplication. The declaration is not created if the namespace +// is already declared in this scope with the same prefix. +func (xmlNode *XmlNode) DeclareNamespace(prefix, href string) { + //can only declare namespaces on elements + if xmlNode.NodeType() != XML_ELEMENT_NODE { + return + } + hrefBytes := GetCString([]byte(href)) + hrefPtr := unsafe.Pointer(&hrefBytes[0]) + + //if the namespace is already declared using this prefix, just return + _ns := C.xmlSearchNsByHref((*C.xmlDoc)(xmlNode.Document.DocPtr()), xmlNode.Ptr, (*C.xmlChar)(hrefPtr)) + if _ns != nil { + _prefixPtr := unsafe.Pointer(_ns.prefix) + _prefix := C.GoString((*C.char)(_prefixPtr)) + if prefix == _prefix { + return + } + } + + prefixBytes := GetCString([]byte(prefix)) + prefixPtr := unsafe.Pointer(&prefixBytes[0]) + if prefix == "" { + prefixPtr = nil + } + + //this adds the namespace declaration to the node + _ = C.xmlNewNs(xmlNode.Ptr, (*C.xmlChar)(hrefPtr), (*C.xmlChar)(prefixPtr)) +} + +// Set the namespace of an element. +func (xmlNode *XmlNode) SetNamespace(prefix, href string) { + if xmlNode.NodeType() != XML_ELEMENT_NODE { + return + } + + prefixBytes := GetCString([]byte(prefix)) + prefixPtr := unsafe.Pointer(&prefixBytes[0]) + if prefix == "" { + prefixPtr = nil + } + + hrefBytes := GetCString([]byte(href)) + hrefPtr := unsafe.Pointer(&hrefBytes[0]) + + // use the existing namespace declaration if there is one + _ns := C.xmlSearchNsByHref((*C.xmlDoc)(xmlNode.Document.DocPtr()), xmlNode.Ptr, (*C.xmlChar)(hrefPtr)) + if _ns != nil { + _prefixPtr := unsafe.Pointer(_ns.prefix) + _prefix := C.GoString((*C.char)(_prefixPtr)) + if prefix == _prefix { + C.xmlSetNs(xmlNode.Ptr, _ns) + return + } + } + + ns := C.xmlNewNs(xmlNode.Ptr, (*C.xmlChar)(hrefPtr), (*C.xmlChar)(prefixPtr)) + C.xmlSetNs(xmlNode.Ptr, ns) +} + +// Returns the line number on which the node appears, or a -1 if the +// line number cannot be determined. +func (xmlNode *XmlNode) LineNumber() int { + return int(C.xmlGetLineNo(xmlNode.Ptr)) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/nodeset.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/nodeset.go new file mode 100644 index 000000000..df994c90a --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/nodeset.go @@ -0,0 +1,48 @@ +package xml + +/* +#cgo pkg-config: libxml-2.0 + +#include +#include + +*/ +import "C" + +import "unsafe" + +type Nodeset []Node + +// Produce a slice of unsafe.Pointer objects, suitable for passing to a C function +func (n Nodeset) ToPointers() (pointers []unsafe.Pointer) { + for _, node := range n { + pointers = append(pointers, node.NodePtr()) + } + return +} + +// Produce a C.xmlXPathObjectPtr suitable for passing to libxml2 +func (n Nodeset) ToXPathNodeset() (ret C.xmlXPathObjectPtr) { + ret = C.xmlXPathNewNodeSet(nil) + for _, node := range n { + C.xmlXPathNodeSetAdd(ret.nodesetval, (*C.xmlNode)(node.NodePtr())) + } + return +} + +// Produce a C.xmlXPathObjectPtr marked as a ResultValueTree, suitable for passing to libxml2 +func (n Nodeset) ToXPathValueTree() (ret C.xmlXPathObjectPtr) { + if len(n) == 0 { + ret = C.xmlXPathNewValueTree(nil) + return + } + + ret = C.xmlXPathNewValueTree(nil) + for _, node := range n { + C.xmlXPathNodeSetAdd(ret.nodesetval, (*C.xmlNode)(node.NodePtr())) + } + //this hack-ish looking line tells libxml2 not to free the RVT + //if we don't do this we get horrible double-free crashes everywhere + ret.boolval = 0 + return +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/pi.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/pi.go new file mode 100644 index 000000000..bc5d9aa7e --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/pi.go @@ -0,0 +1,5 @@ +package xml + +type ProcessingInstructionNode struct { + *XmlNode +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/stub.go deleted file mode 100644 index 26db7472c..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/stub.go +++ /dev/null @@ -1,2372 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/jbowtie/gokogiri/xml, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/jbowtie/gokogiri/xml (exports: Node; functions: ) - -// Package xml is a stub of github.com/jbowtie/gokogiri/xml, generated by depstubber. -package xml - -import () - -type AttributeNode struct { - XmlNode *XmlNode -} - -func (_ AttributeNode) AddChild(_ interface{}) error { - return nil -} - -func (_ AttributeNode) AddNextSibling(_ interface{}) error { - return nil -} - -func (_ AttributeNode) AddPreviousSibling(_ interface{}) error { - return nil -} - -func (_ AttributeNode) AddUnlinkedNode(_ interface{}) {} - -func (_ AttributeNode) Attr(_ string) string { - return "" -} - -func (_ AttributeNode) Attribute(_ string) *AttributeNode { - return nil -} - -func (_ AttributeNode) AttributeList() []*AttributeNode { - return nil -} - -func (_ AttributeNode) Attributes() map[string]*AttributeNode { - return nil -} - -func (_ AttributeNode) BookkeepFragment(_ *DocumentFragment) {} - -func (_ AttributeNode) Coerce(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ AttributeNode) Content() string { - return "" -} - -func (_ AttributeNode) CountChildren() int { - return 0 -} - -func (_ AttributeNode) CreateCDataNode(_ string) *CDataNode { - return nil -} - -func (_ AttributeNode) CreateCommentNode(_ string) *CommentNode { - return nil -} - -func (_ AttributeNode) CreateElementNode(_ string) *ElementNode { - return nil -} - -func (_ AttributeNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode { - return nil -} - -func (_ AttributeNode) CreateTextNode(_ string) *TextNode { - return nil -} - -func (_ AttributeNode) DeclareNamespace(_ string, _ string) {} - -func (_ AttributeNode) DeclaredNamespaces() []NamespaceDeclaration { - return nil -} - -func (_ AttributeNode) DocPtr() interface{} { - return nil -} - -func (_ AttributeNode) DocRef() Document { - return nil -} - -func (_ AttributeNode) DocType() NodeType { - return 0 -} - -func (_ AttributeNode) DocXPathCtx() interface{} { - return nil -} - -func (_ AttributeNode) Duplicate(_ int) Node { - return nil -} - -func (_ AttributeNode) DuplicateTo(_ Document, _ int) Node { - return nil -} - -func (_ AttributeNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) { - return nil, nil -} - -func (_ AttributeNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool { - return false -} - -func (_ AttributeNode) FirstChild() Node { - return nil -} - -func (_ AttributeNode) Free() {} - -func (_ AttributeNode) InnerHtml() string { - return "" -} - -func (_ AttributeNode) InputEncoding() []byte { - return nil -} - -func (_ AttributeNode) InsertAfter(_ interface{}) error { - return nil -} - -func (_ AttributeNode) InsertBefore(_ interface{}) error { - return nil -} - -func (_ AttributeNode) InsertBegin(_ interface{}) error { - return nil -} - -func (_ AttributeNode) InsertEnd(_ interface{}) error { - return nil -} - -func (_ AttributeNode) IsValid() bool { - return false -} - -func (_ AttributeNode) LastChild() Node { - return nil -} - -func (_ AttributeNode) LineNumber() int { - return 0 -} - -func (_ AttributeNode) MyDocument() Document { - return nil -} - -func (_ AttributeNode) Name() string { - return "" -} - -func (_ AttributeNode) Namespace() string { - return "" -} - -func (_ AttributeNode) NextSibling() Node { - return nil -} - -func (_ AttributeNode) NodeById(_ string) *ElementNode { - return nil -} - -func (_ AttributeNode) NodePtr() interface{} { - return nil -} - -func (_ AttributeNode) NodeType() NodeType { - return 0 -} - -func (_ AttributeNode) OutputEncoding() []byte { - return nil -} - -func (_ AttributeNode) Parent() Node { - return nil -} - -func (_ AttributeNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) { - return nil, nil -} - -func (_ AttributeNode) Path() string { - return "" -} - -func (_ AttributeNode) PreviousSibling() Node { - return nil -} - -func (_ AttributeNode) RecursivelyRemoveNamespaces() error { - return nil -} - -func (_ AttributeNode) Remove() {} - -func (_ AttributeNode) RemoveDefaultNamespace() {} - -func (_ AttributeNode) RemoveUnlinkedNode(_ interface{}) bool { - return false -} - -func (_ AttributeNode) Replace(_ interface{}) error { - return nil -} - -func (_ AttributeNode) ResetChildren() {} - -func (_ AttributeNode) ResetNodePtr() {} - -func (_ AttributeNode) Root() *ElementNode { - return nil -} - -func (_ AttributeNode) Search(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ AttributeNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ AttributeNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ AttributeNode) SetAttr(_ string, _ string) string { - return "" -} - -func (_ AttributeNode) SetChildren(_ interface{}) error { - return nil -} - -func (_ AttributeNode) SetContent(_ interface{}) error { - return nil -} - -func (_ AttributeNode) SetInnerHtml(_ interface{}) error { - return nil -} - -func (_ AttributeNode) SetName(_ string) {} - -func (_ AttributeNode) SetNamespace(_ string, _ string) {} - -func (_ AttributeNode) SetNsAttr(_ string, _ string, _ string) string { - return "" -} - -func (_ AttributeNode) ToBuffer(_ []byte) []byte { - return nil -} - -func (_ AttributeNode) ToHtml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ AttributeNode) ToUnformattedXml() string { - return "" -} - -func (_ AttributeNode) ToXml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ AttributeNode) Unlink() {} - -func (_ AttributeNode) UnparsedEntityURI(_ string) string { - return "" -} - -func (_ AttributeNode) Uri() string { - return "" -} - -func (_ AttributeNode) Wrap(_ string) error { - return nil -} - -func (_ *AttributeNode) SetValue(_ interface{}) {} - -func (_ *AttributeNode) String() string { - return "" -} - -func (_ *AttributeNode) Value() string { - return "" -} - -type CDataNode struct { - XmlNode *XmlNode -} - -func (_ CDataNode) AddChild(_ interface{}) error { - return nil -} - -func (_ CDataNode) AddNextSibling(_ interface{}) error { - return nil -} - -func (_ CDataNode) AddPreviousSibling(_ interface{}) error { - return nil -} - -func (_ CDataNode) AddUnlinkedNode(_ interface{}) {} - -func (_ CDataNode) Attr(_ string) string { - return "" -} - -func (_ CDataNode) Attribute(_ string) *AttributeNode { - return nil -} - -func (_ CDataNode) AttributeList() []*AttributeNode { - return nil -} - -func (_ CDataNode) Attributes() map[string]*AttributeNode { - return nil -} - -func (_ CDataNode) BookkeepFragment(_ *DocumentFragment) {} - -func (_ CDataNode) Coerce(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ CDataNode) Content() string { - return "" -} - -func (_ CDataNode) CountChildren() int { - return 0 -} - -func (_ CDataNode) CreateCDataNode(_ string) *CDataNode { - return nil -} - -func (_ CDataNode) CreateCommentNode(_ string) *CommentNode { - return nil -} - -func (_ CDataNode) CreateElementNode(_ string) *ElementNode { - return nil -} - -func (_ CDataNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode { - return nil -} - -func (_ CDataNode) CreateTextNode(_ string) *TextNode { - return nil -} - -func (_ CDataNode) DeclareNamespace(_ string, _ string) {} - -func (_ CDataNode) DeclaredNamespaces() []NamespaceDeclaration { - return nil -} - -func (_ CDataNode) DocPtr() interface{} { - return nil -} - -func (_ CDataNode) DocRef() Document { - return nil -} - -func (_ CDataNode) DocType() NodeType { - return 0 -} - -func (_ CDataNode) DocXPathCtx() interface{} { - return nil -} - -func (_ CDataNode) Duplicate(_ int) Node { - return nil -} - -func (_ CDataNode) DuplicateTo(_ Document, _ int) Node { - return nil -} - -func (_ CDataNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) { - return nil, nil -} - -func (_ CDataNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool { - return false -} - -func (_ CDataNode) FirstChild() Node { - return nil -} - -func (_ CDataNode) Free() {} - -func (_ CDataNode) InnerHtml() string { - return "" -} - -func (_ CDataNode) InputEncoding() []byte { - return nil -} - -func (_ CDataNode) InsertAfter(_ interface{}) error { - return nil -} - -func (_ CDataNode) InsertBefore(_ interface{}) error { - return nil -} - -func (_ CDataNode) InsertBegin(_ interface{}) error { - return nil -} - -func (_ CDataNode) InsertEnd(_ interface{}) error { - return nil -} - -func (_ CDataNode) IsValid() bool { - return false -} - -func (_ CDataNode) LastChild() Node { - return nil -} - -func (_ CDataNode) LineNumber() int { - return 0 -} - -func (_ CDataNode) MyDocument() Document { - return nil -} - -func (_ CDataNode) Name() string { - return "" -} - -func (_ CDataNode) Namespace() string { - return "" -} - -func (_ CDataNode) NextSibling() Node { - return nil -} - -func (_ CDataNode) NodeById(_ string) *ElementNode { - return nil -} - -func (_ CDataNode) NodePtr() interface{} { - return nil -} - -func (_ CDataNode) NodeType() NodeType { - return 0 -} - -func (_ CDataNode) OutputEncoding() []byte { - return nil -} - -func (_ CDataNode) Parent() Node { - return nil -} - -func (_ CDataNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) { - return nil, nil -} - -func (_ CDataNode) Path() string { - return "" -} - -func (_ CDataNode) PreviousSibling() Node { - return nil -} - -func (_ CDataNode) RecursivelyRemoveNamespaces() error { - return nil -} - -func (_ CDataNode) Remove() {} - -func (_ CDataNode) RemoveDefaultNamespace() {} - -func (_ CDataNode) RemoveUnlinkedNode(_ interface{}) bool { - return false -} - -func (_ CDataNode) Replace(_ interface{}) error { - return nil -} - -func (_ CDataNode) ResetChildren() {} - -func (_ CDataNode) ResetNodePtr() {} - -func (_ CDataNode) Root() *ElementNode { - return nil -} - -func (_ CDataNode) Search(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ CDataNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ CDataNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ CDataNode) SetAttr(_ string, _ string) string { - return "" -} - -func (_ CDataNode) SetChildren(_ interface{}) error { - return nil -} - -func (_ CDataNode) SetContent(_ interface{}) error { - return nil -} - -func (_ CDataNode) SetInnerHtml(_ interface{}) error { - return nil -} - -func (_ CDataNode) SetName(_ string) {} - -func (_ CDataNode) SetNamespace(_ string, _ string) {} - -func (_ CDataNode) SetNsAttr(_ string, _ string, _ string) string { - return "" -} - -func (_ CDataNode) String() string { - return "" -} - -func (_ CDataNode) ToBuffer(_ []byte) []byte { - return nil -} - -func (_ CDataNode) ToHtml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ CDataNode) ToUnformattedXml() string { - return "" -} - -func (_ CDataNode) ToXml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ CDataNode) Unlink() {} - -func (_ CDataNode) UnparsedEntityURI(_ string) string { - return "" -} - -func (_ CDataNode) Uri() string { - return "" -} - -func (_ CDataNode) Wrap(_ string) error { - return nil -} - -type CommentNode struct { - XmlNode *XmlNode -} - -func (_ CommentNode) AddChild(_ interface{}) error { - return nil -} - -func (_ CommentNode) AddNextSibling(_ interface{}) error { - return nil -} - -func (_ CommentNode) AddPreviousSibling(_ interface{}) error { - return nil -} - -func (_ CommentNode) AddUnlinkedNode(_ interface{}) {} - -func (_ CommentNode) Attr(_ string) string { - return "" -} - -func (_ CommentNode) Attribute(_ string) *AttributeNode { - return nil -} - -func (_ CommentNode) AttributeList() []*AttributeNode { - return nil -} - -func (_ CommentNode) Attributes() map[string]*AttributeNode { - return nil -} - -func (_ CommentNode) BookkeepFragment(_ *DocumentFragment) {} - -func (_ CommentNode) Coerce(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ CommentNode) Content() string { - return "" -} - -func (_ CommentNode) CountChildren() int { - return 0 -} - -func (_ CommentNode) CreateCDataNode(_ string) *CDataNode { - return nil -} - -func (_ CommentNode) CreateCommentNode(_ string) *CommentNode { - return nil -} - -func (_ CommentNode) CreateElementNode(_ string) *ElementNode { - return nil -} - -func (_ CommentNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode { - return nil -} - -func (_ CommentNode) CreateTextNode(_ string) *TextNode { - return nil -} - -func (_ CommentNode) DeclareNamespace(_ string, _ string) {} - -func (_ CommentNode) DeclaredNamespaces() []NamespaceDeclaration { - return nil -} - -func (_ CommentNode) DocPtr() interface{} { - return nil -} - -func (_ CommentNode) DocRef() Document { - return nil -} - -func (_ CommentNode) DocType() NodeType { - return 0 -} - -func (_ CommentNode) DocXPathCtx() interface{} { - return nil -} - -func (_ CommentNode) Duplicate(_ int) Node { - return nil -} - -func (_ CommentNode) DuplicateTo(_ Document, _ int) Node { - return nil -} - -func (_ CommentNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) { - return nil, nil -} - -func (_ CommentNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool { - return false -} - -func (_ CommentNode) FirstChild() Node { - return nil -} - -func (_ CommentNode) Free() {} - -func (_ CommentNode) InnerHtml() string { - return "" -} - -func (_ CommentNode) InputEncoding() []byte { - return nil -} - -func (_ CommentNode) InsertAfter(_ interface{}) error { - return nil -} - -func (_ CommentNode) InsertBefore(_ interface{}) error { - return nil -} - -func (_ CommentNode) InsertBegin(_ interface{}) error { - return nil -} - -func (_ CommentNode) InsertEnd(_ interface{}) error { - return nil -} - -func (_ CommentNode) IsValid() bool { - return false -} - -func (_ CommentNode) LastChild() Node { - return nil -} - -func (_ CommentNode) LineNumber() int { - return 0 -} - -func (_ CommentNode) MyDocument() Document { - return nil -} - -func (_ CommentNode) Name() string { - return "" -} - -func (_ CommentNode) Namespace() string { - return "" -} - -func (_ CommentNode) NextSibling() Node { - return nil -} - -func (_ CommentNode) NodeById(_ string) *ElementNode { - return nil -} - -func (_ CommentNode) NodePtr() interface{} { - return nil -} - -func (_ CommentNode) NodeType() NodeType { - return 0 -} - -func (_ CommentNode) OutputEncoding() []byte { - return nil -} - -func (_ CommentNode) Parent() Node { - return nil -} - -func (_ CommentNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) { - return nil, nil -} - -func (_ CommentNode) Path() string { - return "" -} - -func (_ CommentNode) PreviousSibling() Node { - return nil -} - -func (_ CommentNode) RecursivelyRemoveNamespaces() error { - return nil -} - -func (_ CommentNode) Remove() {} - -func (_ CommentNode) RemoveDefaultNamespace() {} - -func (_ CommentNode) RemoveUnlinkedNode(_ interface{}) bool { - return false -} - -func (_ CommentNode) Replace(_ interface{}) error { - return nil -} - -func (_ CommentNode) ResetChildren() {} - -func (_ CommentNode) ResetNodePtr() {} - -func (_ CommentNode) Root() *ElementNode { - return nil -} - -func (_ CommentNode) Search(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ CommentNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ CommentNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ CommentNode) SetAttr(_ string, _ string) string { - return "" -} - -func (_ CommentNode) SetChildren(_ interface{}) error { - return nil -} - -func (_ CommentNode) SetContent(_ interface{}) error { - return nil -} - -func (_ CommentNode) SetInnerHtml(_ interface{}) error { - return nil -} - -func (_ CommentNode) SetName(_ string) {} - -func (_ CommentNode) SetNamespace(_ string, _ string) {} - -func (_ CommentNode) SetNsAttr(_ string, _ string, _ string) string { - return "" -} - -func (_ CommentNode) String() string { - return "" -} - -func (_ CommentNode) ToBuffer(_ []byte) []byte { - return nil -} - -func (_ CommentNode) ToHtml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ CommentNode) ToUnformattedXml() string { - return "" -} - -func (_ CommentNode) ToXml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ CommentNode) Unlink() {} - -func (_ CommentNode) UnparsedEntityURI(_ string) string { - return "" -} - -func (_ CommentNode) Uri() string { - return "" -} - -func (_ CommentNode) Wrap(_ string) error { - return nil -} - -type Document interface { - AddUnlinkedNode(_ interface{}) - BookkeepFragment(_ *DocumentFragment) - CreateCDataNode(_ string) *CDataNode - CreateCommentNode(_ string) *CommentNode - CreateElementNode(_ string) *ElementNode - CreatePINode(_ string, _ string) *ProcessingInstructionNode - CreateTextNode(_ string) *TextNode - DocPtr() interface{} - DocRef() Document - DocType() NodeType - DocXPathCtx() interface{} - Free() - InputEncoding() []byte - NodeById(_ string) *ElementNode - OutputEncoding() []byte - ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) - RecursivelyRemoveNamespaces() error - RemoveUnlinkedNode(_ interface{}) bool - Root() *ElementNode - String() string - UnparsedEntityURI(_ string) string - Uri() string -} - -type DocumentFragment struct { - Node Node - InEncoding []byte - OutEncoding []byte -} - -func (_ DocumentFragment) AddChild(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) AddNextSibling(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) AddPreviousSibling(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) Attr(_ string) string { - return "" -} - -func (_ DocumentFragment) Attribute(_ string) *AttributeNode { - return nil -} - -func (_ DocumentFragment) AttributeList() []*AttributeNode { - return nil -} - -func (_ DocumentFragment) Attributes() map[string]*AttributeNode { - return nil -} - -func (_ DocumentFragment) Coerce(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ DocumentFragment) Content() string { - return "" -} - -func (_ DocumentFragment) CountChildren() int { - return 0 -} - -func (_ DocumentFragment) DeclareNamespace(_ string, _ string) {} - -func (_ DocumentFragment) DeclaredNamespaces() []NamespaceDeclaration { - return nil -} - -func (_ DocumentFragment) Duplicate(_ int) Node { - return nil -} - -func (_ DocumentFragment) DuplicateTo(_ Document, _ int) Node { - return nil -} - -func (_ DocumentFragment) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) { - return nil, nil -} - -func (_ DocumentFragment) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool { - return false -} - -func (_ DocumentFragment) FirstChild() Node { - return nil -} - -func (_ DocumentFragment) InnerHtml() string { - return "" -} - -func (_ DocumentFragment) InsertAfter(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) InsertBefore(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) InsertBegin(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) InsertEnd(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) IsValid() bool { - return false -} - -func (_ DocumentFragment) LastChild() Node { - return nil -} - -func (_ DocumentFragment) LineNumber() int { - return 0 -} - -func (_ DocumentFragment) MyDocument() Document { - return nil -} - -func (_ DocumentFragment) Name() string { - return "" -} - -func (_ DocumentFragment) Namespace() string { - return "" -} - -func (_ DocumentFragment) NextSibling() Node { - return nil -} - -func (_ DocumentFragment) NodePtr() interface{} { - return nil -} - -func (_ DocumentFragment) NodeType() NodeType { - return 0 -} - -func (_ DocumentFragment) Parent() Node { - return nil -} - -func (_ DocumentFragment) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) { - return nil, nil -} - -func (_ DocumentFragment) Path() string { - return "" -} - -func (_ DocumentFragment) PreviousSibling() Node { - return nil -} - -func (_ DocumentFragment) RecursivelyRemoveNamespaces() error { - return nil -} - -func (_ DocumentFragment) RemoveDefaultNamespace() {} - -func (_ DocumentFragment) Replace(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) ResetChildren() {} - -func (_ DocumentFragment) ResetNodePtr() {} - -func (_ DocumentFragment) Search(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ DocumentFragment) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ DocumentFragment) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ DocumentFragment) SetAttr(_ string, _ string) string { - return "" -} - -func (_ DocumentFragment) SetChildren(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) SetContent(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) SetInnerHtml(_ interface{}) error { - return nil -} - -func (_ DocumentFragment) SetName(_ string) {} - -func (_ DocumentFragment) SetNamespace(_ string, _ string) {} - -func (_ DocumentFragment) SetNsAttr(_ string, _ string, _ string) string { - return "" -} - -func (_ DocumentFragment) ToHtml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ DocumentFragment) ToUnformattedXml() string { - return "" -} - -func (_ DocumentFragment) ToXml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ DocumentFragment) Unlink() {} - -func (_ DocumentFragment) Wrap(_ string) error { - return nil -} - -func (_ *DocumentFragment) Children() []Node { - return nil -} - -func (_ *DocumentFragment) Remove() {} - -func (_ *DocumentFragment) String() string { - return "" -} - -func (_ *DocumentFragment) ToBuffer(_ []byte) []byte { - return nil -} - -type ElementNode struct { - XmlNode *XmlNode -} - -func (_ ElementNode) AddChild(_ interface{}) error { - return nil -} - -func (_ ElementNode) AddNextSibling(_ interface{}) error { - return nil -} - -func (_ ElementNode) AddPreviousSibling(_ interface{}) error { - return nil -} - -func (_ ElementNode) AddUnlinkedNode(_ interface{}) {} - -func (_ ElementNode) Attr(_ string) string { - return "" -} - -func (_ ElementNode) Attribute(_ string) *AttributeNode { - return nil -} - -func (_ ElementNode) AttributeList() []*AttributeNode { - return nil -} - -func (_ ElementNode) Attributes() map[string]*AttributeNode { - return nil -} - -func (_ ElementNode) BookkeepFragment(_ *DocumentFragment) {} - -func (_ ElementNode) Coerce(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ ElementNode) Content() string { - return "" -} - -func (_ ElementNode) CountChildren() int { - return 0 -} - -func (_ ElementNode) CreateCDataNode(_ string) *CDataNode { - return nil -} - -func (_ ElementNode) CreateCommentNode(_ string) *CommentNode { - return nil -} - -func (_ ElementNode) CreateElementNode(_ string) *ElementNode { - return nil -} - -func (_ ElementNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode { - return nil -} - -func (_ ElementNode) CreateTextNode(_ string) *TextNode { - return nil -} - -func (_ ElementNode) DeclareNamespace(_ string, _ string) {} - -func (_ ElementNode) DeclaredNamespaces() []NamespaceDeclaration { - return nil -} - -func (_ ElementNode) DocPtr() interface{} { - return nil -} - -func (_ ElementNode) DocRef() Document { - return nil -} - -func (_ ElementNode) DocType() NodeType { - return 0 -} - -func (_ ElementNode) DocXPathCtx() interface{} { - return nil -} - -func (_ ElementNode) Duplicate(_ int) Node { - return nil -} - -func (_ ElementNode) DuplicateTo(_ Document, _ int) Node { - return nil -} - -func (_ ElementNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) { - return nil, nil -} - -func (_ ElementNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool { - return false -} - -func (_ ElementNode) FirstChild() Node { - return nil -} - -func (_ ElementNode) Free() {} - -func (_ ElementNode) InnerHtml() string { - return "" -} - -func (_ ElementNode) InputEncoding() []byte { - return nil -} - -func (_ ElementNode) InsertAfter(_ interface{}) error { - return nil -} - -func (_ ElementNode) InsertBefore(_ interface{}) error { - return nil -} - -func (_ ElementNode) InsertBegin(_ interface{}) error { - return nil -} - -func (_ ElementNode) InsertEnd(_ interface{}) error { - return nil -} - -func (_ ElementNode) IsValid() bool { - return false -} - -func (_ ElementNode) LastChild() Node { - return nil -} - -func (_ ElementNode) LineNumber() int { - return 0 -} - -func (_ ElementNode) MyDocument() Document { - return nil -} - -func (_ ElementNode) Name() string { - return "" -} - -func (_ ElementNode) Namespace() string { - return "" -} - -func (_ ElementNode) NextSibling() Node { - return nil -} - -func (_ ElementNode) NodeById(_ string) *ElementNode { - return nil -} - -func (_ ElementNode) NodePtr() interface{} { - return nil -} - -func (_ ElementNode) NodeType() NodeType { - return 0 -} - -func (_ ElementNode) OutputEncoding() []byte { - return nil -} - -func (_ ElementNode) Parent() Node { - return nil -} - -func (_ ElementNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) { - return nil, nil -} - -func (_ ElementNode) Path() string { - return "" -} - -func (_ ElementNode) PreviousSibling() Node { - return nil -} - -func (_ ElementNode) RecursivelyRemoveNamespaces() error { - return nil -} - -func (_ ElementNode) Remove() {} - -func (_ ElementNode) RemoveDefaultNamespace() {} - -func (_ ElementNode) RemoveUnlinkedNode(_ interface{}) bool { - return false -} - -func (_ ElementNode) Replace(_ interface{}) error { - return nil -} - -func (_ ElementNode) ResetChildren() {} - -func (_ ElementNode) ResetNodePtr() {} - -func (_ ElementNode) Root() *ElementNode { - return nil -} - -func (_ ElementNode) Search(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ ElementNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ ElementNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ ElementNode) SetAttr(_ string, _ string) string { - return "" -} - -func (_ ElementNode) SetChildren(_ interface{}) error { - return nil -} - -func (_ ElementNode) SetContent(_ interface{}) error { - return nil -} - -func (_ ElementNode) SetInnerHtml(_ interface{}) error { - return nil -} - -func (_ ElementNode) SetName(_ string) {} - -func (_ ElementNode) SetNamespace(_ string, _ string) {} - -func (_ ElementNode) SetNsAttr(_ string, _ string, _ string) string { - return "" -} - -func (_ ElementNode) String() string { - return "" -} - -func (_ ElementNode) ToBuffer(_ []byte) []byte { - return nil -} - -func (_ ElementNode) ToHtml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ ElementNode) ToUnformattedXml() string { - return "" -} - -func (_ ElementNode) ToXml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ ElementNode) Unlink() {} - -func (_ ElementNode) UnparsedEntityURI(_ string) string { - return "" -} - -func (_ ElementNode) Uri() string { - return "" -} - -func (_ ElementNode) Wrap(_ string) error { - return nil -} - -type NamespaceDeclaration struct { - Prefix string - Uri string -} - -type Node interface { - AddChild(_ interface{}) error - AddNextSibling(_ interface{}) error - AddPreviousSibling(_ interface{}) error - Attr(_ string) string - Attribute(_ string) *AttributeNode - AttributeList() []*AttributeNode - Attributes() map[string]*AttributeNode - Coerce(_ interface{}) ([]Node, error) - Content() string - CountChildren() int - DeclareNamespace(_ string, _ string) - DeclaredNamespaces() []NamespaceDeclaration - Duplicate(_ int) Node - DuplicateTo(_ Document, _ int) Node - EvalXPath(_ interface{}, _ interface{}) (interface{}, error) - EvalXPathAsBoolean(_ interface{}, _ interface{}) bool - FirstChild() Node - InnerHtml() string - InsertAfter(_ interface{}) error - InsertBefore(_ interface{}) error - InsertBegin(_ interface{}) error - InsertEnd(_ interface{}) error - IsValid() bool - LastChild() Node - LineNumber() int - MyDocument() Document - Name() string - Namespace() string - NextSibling() Node - NodePtr() interface{} - NodeType() NodeType - Parent() Node - ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) - Path() string - PreviousSibling() Node - RecursivelyRemoveNamespaces() error - Remove() - RemoveDefaultNamespace() - Replace(_ interface{}) error - ResetChildren() - ResetNodePtr() - Search(_ interface{}) ([]Node, error) - SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) - SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) - SetAttr(_ string, _ string) string - SetChildren(_ interface{}) error - SetContent(_ interface{}) error - SetInnerHtml(_ interface{}) error - SetName(_ string) - SetNamespace(_ string, _ string) - SetNsAttr(_ string, _ string, _ string) string - String() string - ToBuffer(_ []byte) []byte - ToHtml(_ []byte, _ []byte) ([]byte, int) - ToUnformattedXml() string - ToXml(_ []byte, _ []byte) ([]byte, int) - Unlink() - Wrap(_ string) error -} - -type NodeType int - -type ParseOption int - -type ProcessingInstructionNode struct { - XmlNode *XmlNode -} - -func (_ ProcessingInstructionNode) AddChild(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) AddNextSibling(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) AddPreviousSibling(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) AddUnlinkedNode(_ interface{}) {} - -func (_ ProcessingInstructionNode) Attr(_ string) string { - return "" -} - -func (_ ProcessingInstructionNode) Attribute(_ string) *AttributeNode { - return nil -} - -func (_ ProcessingInstructionNode) AttributeList() []*AttributeNode { - return nil -} - -func (_ ProcessingInstructionNode) Attributes() map[string]*AttributeNode { - return nil -} - -func (_ ProcessingInstructionNode) BookkeepFragment(_ *DocumentFragment) {} - -func (_ ProcessingInstructionNode) Coerce(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ ProcessingInstructionNode) Content() string { - return "" -} - -func (_ ProcessingInstructionNode) CountChildren() int { - return 0 -} - -func (_ ProcessingInstructionNode) CreateCDataNode(_ string) *CDataNode { - return nil -} - -func (_ ProcessingInstructionNode) CreateCommentNode(_ string) *CommentNode { - return nil -} - -func (_ ProcessingInstructionNode) CreateElementNode(_ string) *ElementNode { - return nil -} - -func (_ ProcessingInstructionNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode { - return nil -} - -func (_ ProcessingInstructionNode) CreateTextNode(_ string) *TextNode { - return nil -} - -func (_ ProcessingInstructionNode) DeclareNamespace(_ string, _ string) {} - -func (_ ProcessingInstructionNode) DeclaredNamespaces() []NamespaceDeclaration { - return nil -} - -func (_ ProcessingInstructionNode) DocPtr() interface{} { - return nil -} - -func (_ ProcessingInstructionNode) DocRef() Document { - return nil -} - -func (_ ProcessingInstructionNode) DocType() NodeType { - return 0 -} - -func (_ ProcessingInstructionNode) DocXPathCtx() interface{} { - return nil -} - -func (_ ProcessingInstructionNode) Duplicate(_ int) Node { - return nil -} - -func (_ ProcessingInstructionNode) DuplicateTo(_ Document, _ int) Node { - return nil -} - -func (_ ProcessingInstructionNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) { - return nil, nil -} - -func (_ ProcessingInstructionNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool { - return false -} - -func (_ ProcessingInstructionNode) FirstChild() Node { - return nil -} - -func (_ ProcessingInstructionNode) Free() {} - -func (_ ProcessingInstructionNode) InnerHtml() string { - return "" -} - -func (_ ProcessingInstructionNode) InputEncoding() []byte { - return nil -} - -func (_ ProcessingInstructionNode) InsertAfter(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) InsertBefore(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) InsertBegin(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) InsertEnd(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) IsValid() bool { - return false -} - -func (_ ProcessingInstructionNode) LastChild() Node { - return nil -} - -func (_ ProcessingInstructionNode) LineNumber() int { - return 0 -} - -func (_ ProcessingInstructionNode) MyDocument() Document { - return nil -} - -func (_ ProcessingInstructionNode) Name() string { - return "" -} - -func (_ ProcessingInstructionNode) Namespace() string { - return "" -} - -func (_ ProcessingInstructionNode) NextSibling() Node { - return nil -} - -func (_ ProcessingInstructionNode) NodeById(_ string) *ElementNode { - return nil -} - -func (_ ProcessingInstructionNode) NodePtr() interface{} { - return nil -} - -func (_ ProcessingInstructionNode) NodeType() NodeType { - return 0 -} - -func (_ ProcessingInstructionNode) OutputEncoding() []byte { - return nil -} - -func (_ ProcessingInstructionNode) Parent() Node { - return nil -} - -func (_ ProcessingInstructionNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) { - return nil, nil -} - -func (_ ProcessingInstructionNode) Path() string { - return "" -} - -func (_ ProcessingInstructionNode) PreviousSibling() Node { - return nil -} - -func (_ ProcessingInstructionNode) RecursivelyRemoveNamespaces() error { - return nil -} - -func (_ ProcessingInstructionNode) Remove() {} - -func (_ ProcessingInstructionNode) RemoveDefaultNamespace() {} - -func (_ ProcessingInstructionNode) RemoveUnlinkedNode(_ interface{}) bool { - return false -} - -func (_ ProcessingInstructionNode) Replace(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) ResetChildren() {} - -func (_ ProcessingInstructionNode) ResetNodePtr() {} - -func (_ ProcessingInstructionNode) Root() *ElementNode { - return nil -} - -func (_ ProcessingInstructionNode) Search(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ ProcessingInstructionNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ ProcessingInstructionNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ ProcessingInstructionNode) SetAttr(_ string, _ string) string { - return "" -} - -func (_ ProcessingInstructionNode) SetChildren(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) SetContent(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) SetInnerHtml(_ interface{}) error { - return nil -} - -func (_ ProcessingInstructionNode) SetName(_ string) {} - -func (_ ProcessingInstructionNode) SetNamespace(_ string, _ string) {} - -func (_ ProcessingInstructionNode) SetNsAttr(_ string, _ string, _ string) string { - return "" -} - -func (_ ProcessingInstructionNode) String() string { - return "" -} - -func (_ ProcessingInstructionNode) ToBuffer(_ []byte) []byte { - return nil -} - -func (_ ProcessingInstructionNode) ToHtml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ ProcessingInstructionNode) ToUnformattedXml() string { - return "" -} - -func (_ ProcessingInstructionNode) ToXml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ ProcessingInstructionNode) Unlink() {} - -func (_ ProcessingInstructionNode) UnparsedEntityURI(_ string) string { - return "" -} - -func (_ ProcessingInstructionNode) Uri() string { - return "" -} - -func (_ ProcessingInstructionNode) Wrap(_ string) error { - return nil -} - -type SerializationOption int - -type TextNode struct { - XmlNode *XmlNode -} - -func (_ TextNode) AddChild(_ interface{}) error { - return nil -} - -func (_ TextNode) AddNextSibling(_ interface{}) error { - return nil -} - -func (_ TextNode) AddPreviousSibling(_ interface{}) error { - return nil -} - -func (_ TextNode) AddUnlinkedNode(_ interface{}) {} - -func (_ TextNode) Attr(_ string) string { - return "" -} - -func (_ TextNode) Attribute(_ string) *AttributeNode { - return nil -} - -func (_ TextNode) AttributeList() []*AttributeNode { - return nil -} - -func (_ TextNode) Attributes() map[string]*AttributeNode { - return nil -} - -func (_ TextNode) BookkeepFragment(_ *DocumentFragment) {} - -func (_ TextNode) Coerce(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ TextNode) Content() string { - return "" -} - -func (_ TextNode) CountChildren() int { - return 0 -} - -func (_ TextNode) CreateCDataNode(_ string) *CDataNode { - return nil -} - -func (_ TextNode) CreateCommentNode(_ string) *CommentNode { - return nil -} - -func (_ TextNode) CreateElementNode(_ string) *ElementNode { - return nil -} - -func (_ TextNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode { - return nil -} - -func (_ TextNode) CreateTextNode(_ string) *TextNode { - return nil -} - -func (_ TextNode) DeclareNamespace(_ string, _ string) {} - -func (_ TextNode) DeclaredNamespaces() []NamespaceDeclaration { - return nil -} - -func (_ TextNode) DocPtr() interface{} { - return nil -} - -func (_ TextNode) DocRef() Document { - return nil -} - -func (_ TextNode) DocType() NodeType { - return 0 -} - -func (_ TextNode) DocXPathCtx() interface{} { - return nil -} - -func (_ TextNode) Duplicate(_ int) Node { - return nil -} - -func (_ TextNode) DuplicateTo(_ Document, _ int) Node { - return nil -} - -func (_ TextNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) { - return nil, nil -} - -func (_ TextNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool { - return false -} - -func (_ TextNode) FirstChild() Node { - return nil -} - -func (_ TextNode) Free() {} - -func (_ TextNode) InnerHtml() string { - return "" -} - -func (_ TextNode) InputEncoding() []byte { - return nil -} - -func (_ TextNode) InsertAfter(_ interface{}) error { - return nil -} - -func (_ TextNode) InsertBefore(_ interface{}) error { - return nil -} - -func (_ TextNode) InsertBegin(_ interface{}) error { - return nil -} - -func (_ TextNode) InsertEnd(_ interface{}) error { - return nil -} - -func (_ TextNode) IsValid() bool { - return false -} - -func (_ TextNode) LastChild() Node { - return nil -} - -func (_ TextNode) LineNumber() int { - return 0 -} - -func (_ TextNode) MyDocument() Document { - return nil -} - -func (_ TextNode) Name() string { - return "" -} - -func (_ TextNode) Namespace() string { - return "" -} - -func (_ TextNode) NextSibling() Node { - return nil -} - -func (_ TextNode) NodeById(_ string) *ElementNode { - return nil -} - -func (_ TextNode) NodePtr() interface{} { - return nil -} - -func (_ TextNode) NodeType() NodeType { - return 0 -} - -func (_ TextNode) OutputEncoding() []byte { - return nil -} - -func (_ TextNode) Parent() Node { - return nil -} - -func (_ TextNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) { - return nil, nil -} - -func (_ TextNode) Path() string { - return "" -} - -func (_ TextNode) PreviousSibling() Node { - return nil -} - -func (_ TextNode) RecursivelyRemoveNamespaces() error { - return nil -} - -func (_ TextNode) Remove() {} - -func (_ TextNode) RemoveDefaultNamespace() {} - -func (_ TextNode) RemoveUnlinkedNode(_ interface{}) bool { - return false -} - -func (_ TextNode) Replace(_ interface{}) error { - return nil -} - -func (_ TextNode) ResetChildren() {} - -func (_ TextNode) ResetNodePtr() {} - -func (_ TextNode) Root() *ElementNode { - return nil -} - -func (_ TextNode) Search(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ TextNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ TextNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ TextNode) SetAttr(_ string, _ string) string { - return "" -} - -func (_ TextNode) SetChildren(_ interface{}) error { - return nil -} - -func (_ TextNode) SetContent(_ interface{}) error { - return nil -} - -func (_ TextNode) SetInnerHtml(_ interface{}) error { - return nil -} - -func (_ TextNode) SetName(_ string) {} - -func (_ TextNode) SetNamespace(_ string, _ string) {} - -func (_ TextNode) SetNsAttr(_ string, _ string, _ string) string { - return "" -} - -func (_ TextNode) String() string { - return "" -} - -func (_ TextNode) ToBuffer(_ []byte) []byte { - return nil -} - -func (_ TextNode) ToHtml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ TextNode) ToUnformattedXml() string { - return "" -} - -func (_ TextNode) ToXml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ TextNode) Unlink() {} - -func (_ TextNode) UnparsedEntityURI(_ string) string { - return "" -} - -func (_ TextNode) Uri() string { - return "" -} - -func (_ TextNode) Wrap(_ string) error { - return nil -} - -func (_ *TextNode) DisableOutputEscaping() {} - -type XmlNode struct { - Ptr interface{} - Document Document -} - -func (_ XmlNode) AddUnlinkedNode(_ interface{}) {} - -func (_ XmlNode) BookkeepFragment(_ *DocumentFragment) {} - -func (_ XmlNode) CreateCDataNode(_ string) *CDataNode { - return nil -} - -func (_ XmlNode) CreateCommentNode(_ string) *CommentNode { - return nil -} - -func (_ XmlNode) CreateElementNode(_ string) *ElementNode { - return nil -} - -func (_ XmlNode) CreatePINode(_ string, _ string) *ProcessingInstructionNode { - return nil -} - -func (_ XmlNode) CreateTextNode(_ string) *TextNode { - return nil -} - -func (_ XmlNode) DocPtr() interface{} { - return nil -} - -func (_ XmlNode) DocRef() Document { - return nil -} - -func (_ XmlNode) DocType() NodeType { - return 0 -} - -func (_ XmlNode) DocXPathCtx() interface{} { - return nil -} - -func (_ XmlNode) Free() {} - -func (_ XmlNode) InputEncoding() []byte { - return nil -} - -func (_ XmlNode) NodeById(_ string) *ElementNode { - return nil -} - -func (_ XmlNode) OutputEncoding() []byte { - return nil -} - -func (_ XmlNode) RemoveUnlinkedNode(_ interface{}) bool { - return false -} - -func (_ XmlNode) Root() *ElementNode { - return nil -} - -func (_ XmlNode) UnparsedEntityURI(_ string) string { - return "" -} - -func (_ XmlNode) Uri() string { - return "" -} - -func (_ *XmlNode) AddChild(_ interface{}) error { - return nil -} - -func (_ *XmlNode) AddNextSibling(_ interface{}) error { - return nil -} - -func (_ *XmlNode) AddPreviousSibling(_ interface{}) error { - return nil -} - -func (_ *XmlNode) Attr(_ string) string { - return "" -} - -func (_ *XmlNode) Attribute(_ string) *AttributeNode { - return nil -} - -func (_ *XmlNode) AttributeList() []*AttributeNode { - return nil -} - -func (_ *XmlNode) Attributes() map[string]*AttributeNode { - return nil -} - -func (_ *XmlNode) Coerce(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ *XmlNode) Content() string { - return "" -} - -func (_ *XmlNode) CountChildren() int { - return 0 -} - -func (_ *XmlNode) DeclareNamespace(_ string, _ string) {} - -func (_ *XmlNode) DeclaredNamespaces() []NamespaceDeclaration { - return nil -} - -func (_ *XmlNode) Duplicate(_ int) Node { - return nil -} - -func (_ *XmlNode) DuplicateTo(_ Document, _ int) Node { - return nil -} - -func (_ *XmlNode) EvalXPath(_ interface{}, _ interface{}) (interface{}, error) { - return nil, nil -} - -func (_ *XmlNode) EvalXPathAsBoolean(_ interface{}, _ interface{}) bool { - return false -} - -func (_ *XmlNode) FirstChild() Node { - return nil -} - -func (_ *XmlNode) InnerHtml() string { - return "" -} - -func (_ *XmlNode) InsertAfter(_ interface{}) error { - return nil -} - -func (_ *XmlNode) InsertBefore(_ interface{}) error { - return nil -} - -func (_ *XmlNode) InsertBegin(_ interface{}) error { - return nil -} - -func (_ *XmlNode) InsertEnd(_ interface{}) error { - return nil -} - -func (_ *XmlNode) IsValid() bool { - return false -} - -func (_ *XmlNode) LastChild() Node { - return nil -} - -func (_ *XmlNode) LineNumber() int { - return 0 -} - -func (_ *XmlNode) MyDocument() Document { - return nil -} - -func (_ *XmlNode) Name() string { - return "" -} - -func (_ *XmlNode) Namespace() string { - return "" -} - -func (_ *XmlNode) NextSibling() Node { - return nil -} - -func (_ *XmlNode) NodePtr() interface{} { - return nil -} - -func (_ *XmlNode) NodeType() NodeType { - return 0 -} - -func (_ *XmlNode) Parent() Node { - return nil -} - -func (_ *XmlNode) ParseFragment(_ []byte, _ []byte, _ ParseOption) (*DocumentFragment, error) { - return nil, nil -} - -func (_ *XmlNode) Path() string { - return "" -} - -func (_ *XmlNode) PreviousSibling() Node { - return nil -} - -func (_ *XmlNode) RecursivelyRemoveNamespaces() error { - return nil -} - -func (_ *XmlNode) Remove() {} - -func (_ *XmlNode) RemoveDefaultNamespace() {} - -func (_ *XmlNode) Replace(_ interface{}) error { - return nil -} - -func (_ *XmlNode) ResetChildren() {} - -func (_ *XmlNode) ResetNodePtr() {} - -func (_ *XmlNode) Search(_ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ *XmlNode) SearchWithVariables(_ interface{}, _ interface{}) ([]Node, error) { - return nil, nil -} - -func (_ *XmlNode) SerializeWithFormat(_ SerializationOption, _ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ *XmlNode) SetAttr(_ string, _ string) string { - return "" -} - -func (_ *XmlNode) SetChildren(_ interface{}) error { - return nil -} - -func (_ *XmlNode) SetContent(_ interface{}) error { - return nil -} - -func (_ *XmlNode) SetInnerHtml(_ interface{}) error { - return nil -} - -func (_ *XmlNode) SetName(_ string) {} - -func (_ *XmlNode) SetNamespace(_ string, _ string) {} - -func (_ *XmlNode) SetNsAttr(_ string, _ string, _ string) string { - return "" -} - -func (_ *XmlNode) String() string { - return "" -} - -func (_ *XmlNode) ToBuffer(_ []byte) []byte { - return nil -} - -func (_ *XmlNode) ToHtml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ *XmlNode) ToUnformattedXml() string { - return "" -} - -func (_ *XmlNode) ToXml(_ []byte, _ []byte) ([]byte, int) { - return nil, 0 -} - -func (_ *XmlNode) Unlink() {} - -func (_ *XmlNode) Wrap(_ string) error { - return nil -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/text.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/text.go new file mode 100644 index 000000000..1723f4dac --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xml/text.go @@ -0,0 +1,24 @@ +package xml + +/* +#include + +void disable_escaping(xmlNodePtr node) { + node->name = xmlStringTextNoenc; +} +*/ +import "C" + +type TextNode struct { + *XmlNode +} + +// DisableOutputEscaping disables the usual safeguards against creating invalid XML and allows the +// characters '<', '>', and '&' to be written out verbatim. Normally they are safely escaped as entities. +// +// This API is intended to provide support for XSLT processors and similar XML manipulation libraries that +// may need to output unsupported entity references or use the XML API for non-XML output. It should never +// be used in the normal course of XML processing. +func (node *TextNode) DisableOutputEscaping() { + C.disable_escaping(node.Ptr) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/expression.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/expression.go new file mode 100644 index 000000000..92526ecf4 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/expression.go @@ -0,0 +1,81 @@ +package xpath + +/* +#include +#include +#include + +void check_xpath_syntax_noop(void *ctx, const char *fmt, ...) { +} + +char *check_xpath_syntax(const char *xpath) { + xmlGenericErrorFunc err_func = check_xpath_syntax_noop; + initGenericErrorDefaultFunc(&err_func); + xmlResetLastError(); + xmlXPathCompile((const xmlChar *)xpath); + xmlErrorPtr err = xmlGetLastError(); + if (err != NULL) { + if (err->code == XML_XPATH_EXPR_ERROR) { + // TODO: Not the cleanest but should scale well + int size = strlen(err->message) + strlen(err->str1) + err->int1 + 16; + char *msg = malloc(size); + sprintf(msg, "%s%s\n%*s^", err->message, err->str1, err->int1, " "); + return msg; + } else { + char *msg = malloc(strlen(err->message)); + sprintf(msg, "%s", err->message); + return msg; + } + } + return NULL; +} +*/ +import "C" +import "unsafe" +import . "github.com/jbowtie/gokogiri/util" + +//import "runtime" +import "errors" + +type Expression struct { + Ptr *C.xmlXPathCompExpr + xpath string +} + +func Check(path string) (err error) { + str := C.CString(path) + defer C.free(unsafe.Pointer(str)) + cstr := C.check_xpath_syntax(str) + if cstr != nil { + defer C.free(unsafe.Pointer(cstr)) + err = errors.New(C.GoString(cstr)) + } + return +} + +func Compile(path string) (expr *Expression) { + if len(path) == 0 { + return + } + + xpathBytes := GetCString([]byte(path)) + xpathPtr := unsafe.Pointer(&xpathBytes[0]) + ptr := C.xmlXPathCompile((*C.xmlChar)(xpathPtr)) + if ptr == nil { + return + } + expr = &Expression{Ptr: ptr, xpath: path} + //runtime.SetFinalizer(expr, (*Expression).Free) + return +} + +func (exp *Expression) String() string { + return exp.xpath +} + +func (exp *Expression) Free() { + if exp.Ptr != nil { + C.xmlXPathFreeCompExpr(exp.Ptr) + exp.Ptr = nil + } +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/stub.go deleted file mode 100644 index c1e32cba5..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/stub.go +++ /dev/null @@ -1,24 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/jbowtie/gokogiri/xpath, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/jbowtie/gokogiri/xpath (exports: ; functions: Compile) - -// Package xpath is a stub of github.com/jbowtie/gokogiri/xpath, generated by depstubber. -package xpath - -import () - -func Compile(_ string) *Expression { - return nil -} - -type Expression struct { - Ptr interface{} -} - -func (_ *Expression) Free() {} - -func (_ *Expression) String() string { - return "" -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/util.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/util.go new file mode 100644 index 000000000..5d7787880 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/util.go @@ -0,0 +1,146 @@ +package xpath + +/* +#cgo pkg-config: libxml-2.0 + +#include +#include +#include + +int getXPathObjectType(xmlXPathObject* o); + +*/ +import "C" + +import ( + "sync" + "unsafe" +) +import "reflect" +import . "github.com/jbowtie/gokogiri/util" + +var ( + contextMap = make(map[unsafe.Pointer]VariableScope) + contextMutex sync.Mutex +) + +func GetScope(ctxt unsafe.Pointer) VariableScope { + contextMutex.Lock() + context := contextMap[ctxt] + contextMutex.Unlock() + return context +} + +func SetScope(ctxt unsafe.Pointer, v VariableScope) { + contextMutex.Lock() + contextMap[ctxt] = v + contextMutex.Unlock() +} + +func ClearScope(ctxt unsafe.Pointer) { + contextMutex.Lock() + delete(contextMap, ctxt) + contextMutex.Unlock() + +} + +//export go_resolve_variables +func go_resolve_variables(ctxt unsafe.Pointer, name, ns *C.char) (ret C.xmlXPathObjectPtr) { + if context := GetScope(ctxt); context != nil { + variable := C.GoString(name) + namespace := C.GoString(ns) + + val := context.ResolveVariable(variable, namespace) + return ValueToXPathObject(val) + } + return nil +} + +// Convert an arbitrary value into a C.xmlXPathObjectPtr +// Unrecognised and nil values are converted to empty node sets. +func ValueToXPathObject(val interface{}) (ret C.xmlXPathObjectPtr) { + if val == nil { + //return the empty node set + ret = C.xmlXPathNewNodeSet(nil) + return + } + switch v := val.(type) { + case unsafe.Pointer: + return (C.xmlXPathObjectPtr)(v) + case []unsafe.Pointer: + ptrs := v + if len(ptrs) > 0 { + //default - return a node set + ret = C.xmlXPathNewNodeSet(nil) + for _, p := range ptrs { + C.xmlXPathNodeSetAdd(ret.nodesetval, (*C.xmlNode)(p)) + } + } else { + ret = C.xmlXPathNewNodeSet(nil) + return + } + case float64: + ret = C.xmlXPathNewFloat(C.double(v)) + case string: + xpathBytes := GetCString([]byte(v)) + xpathPtr := unsafe.Pointer(&xpathBytes[0]) + ret = C.xmlXPathNewString((*C.xmlChar)(xpathPtr)) + default: + typ := reflect.TypeOf(val) + // if a pointer to a struct is passed, get the type of the dereferenced object + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + } + //log the unknown type, return an empty node set + //fmt.Println("go-resolve wrong-type", typ.Kind()) + ret = C.xmlXPathNewNodeSet(nil) + } + return +} + +//export exec_xpath_function +func exec_xpath_function(ctxt C.xmlXPathParserContextPtr, nargs C.int) { + function := C.GoString((*C.char)(unsafe.Pointer(ctxt.context.function))) + namespace := C.GoString((*C.char)(unsafe.Pointer(ctxt.context.functionURI))) + + context := GetScope(unsafe.Pointer(ctxt.context)) + + argcount := int(nargs) + var args []interface{} + + for i := 0; i < argcount; i = i + 1 { + args = append(args, XPathObjectToValue(C.valuePop(ctxt))) + } + + // arguments are popped off the stack in reverse order, so + // we reverse the slice before invoking our callback + if argcount > 1 { + for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 { + args[i], args[j] = args[j], args[i] + } + } + + // push the result onto the stack + // if for some reason we are unable to resolve the + // function we push an empty nodeset + f := context.ResolveFunction(function, namespace) + if f != nil { + retval := f(context, args) + C.valuePush(ctxt, ValueToXPathObject(retval)) + } else { + ret := C.xmlXPathNewNodeSet(nil) + C.valuePush(ctxt, ret) + } + +} + +//export go_can_resolve_function +func go_can_resolve_function(ctxt unsafe.Pointer, name, ns *C.char) (ret C.int) { + function := C.GoString(name) + namespace := C.GoString(ns) + context := GetScope(ctxt) + if context != nil && context.IsFunctionRegistered(function, namespace) { + return C.int(1) + } + return C.int(0) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/xpath.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/xpath.go new file mode 100644 index 000000000..d82e7e1af --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/jbowtie/gokogiri/xpath/xpath.go @@ -0,0 +1,274 @@ +package xpath + +/* +#cgo pkg-config: libxml-2.0 + +#include +#include +#include + +xmlNode* fetchNode(xmlNodeSet *nodeset, int index) { + return nodeset->nodeTab[index]; +} + +xmlXPathObjectPtr go_resolve_variables(void* ctxt, char* name, char* ns); +int go_can_resolve_function(void* ctxt, char* name, char* ns); +void exec_xpath_function(xmlXPathParserContextPtr ctxt, int nargs); + +xmlXPathFunction go_resolve_function(void* ctxt, char* name, char* ns) { + if (go_can_resolve_function(ctxt, name, ns)) + return exec_xpath_function; + + return 0; +} + +static void set_var_lookup(xmlXPathContext* c, void* data) { + c->varLookupFunc = (void *)go_resolve_variables; + c->varLookupData = data; +} + +static void set_function_lookup(xmlXPathContext* c, void* data) { + c->funcLookupFunc = (void *)go_resolve_function; + c->funcLookupData = data; +} + +int getXPathObjectType(xmlXPathObject* o) { + if(o == 0) + return 0; + return o->type; +} +*/ +import "C" + +import "unsafe" +import . "github.com/jbowtie/gokogiri/util" +import "runtime" +import "errors" + +type XPath struct { + ContextPtr *C.xmlXPathContext + ResultPtr *C.xmlXPathObject +} + +type XPathObjectType int + +const ( + XPATH_UNDEFINED XPathObjectType = 0 + XPATH_NODESET = 1 + XPATH_BOOLEAN = 2 + XPATH_NUMBER = 3 + XPATH_STRING = 4 + XPATH_POINT = 5 + XPATH_RANGE = 6 + XPATH_LOCATIONSET = 7 + XPATH_USERS = 8 + XPATH_XSLT_TREE = 9 // An XSLT value tree, non modifiable +) + +type XPathFunction func(context VariableScope, args []interface{}) interface{} + +// Types that provide the VariableScope interface know how to resolve +// XPath variable names into values. +// +//This interface exist primarily for the benefit of XSLT processors. +type VariableScope interface { + ResolveVariable(string, string) interface{} + IsFunctionRegistered(string, string) bool + ResolveFunction(string, string) XPathFunction +} + +func NewXPath(docPtr unsafe.Pointer) (xpath *XPath) { + if docPtr == nil { + return + } + xpath = &XPath{ContextPtr: C.xmlXPathNewContext((*C.xmlDoc)(docPtr)), ResultPtr: nil} + runtime.SetFinalizer(xpath, (*XPath).Free) + return +} + +func (xpath *XPath) RegisterNamespace(prefix, href string) bool { + var prefixPtr unsafe.Pointer = nil + if len(prefix) > 0 { + prefixBytes := AppendCStringTerminator([]byte(prefix)) + prefixPtr = unsafe.Pointer(&prefixBytes[0]) + } + + var hrefPtr unsafe.Pointer = nil + if len(href) > 0 { + hrefBytes := AppendCStringTerminator([]byte(href)) + hrefPtr = unsafe.Pointer(&hrefBytes[0]) + } + + result := C.xmlXPathRegisterNs(xpath.ContextPtr, (*C.xmlChar)(prefixPtr), (*C.xmlChar)(hrefPtr)) + return result == 0 +} + +// Evaluate an XPath and attempt to consume the result as a nodeset. +func (xpath *XPath) EvaluateAsNodeset(nodePtr unsafe.Pointer, xpathExpr *Expression) (nodes []unsafe.Pointer, err error) { + if nodePtr == nil { + //evaluating xpath on a nil node returns no result. + return + } + + err = xpath.Evaluate(nodePtr, xpathExpr) + if err != nil { + return + } + + nodes, err = xpath.ResultAsNodeset() + return +} + +// Evaluate an XPath. The returned result is stored in the struct. Call ReturnType to +// discover the type of result, and call one of the ResultAs* functions to return a +// copy of the result as a particular type. +func (xpath *XPath) Evaluate(nodePtr unsafe.Pointer, xpathExpr *Expression) (err error) { + if nodePtr == nil { + //evaluating xpath on a nil node returns no result. + return + } + + oldXPContextDoc := xpath.ContextPtr.doc + oldXPContextNode := xpath.ContextPtr.node + oldXPProximityPosition := xpath.ContextPtr.proximityPosition + oldXPContextSize := xpath.ContextPtr.contextSize + oldXPNsNr := xpath.ContextPtr.nsNr + oldXPNamespaces := xpath.ContextPtr.namespaces + + xpath.ContextPtr.node = (*C.xmlNode)(nodePtr) + if xpath.ResultPtr != nil { + C.xmlXPathFreeObject(xpath.ResultPtr) + } + xpath.ResultPtr = C.xmlXPathCompiledEval(xpathExpr.Ptr, xpath.ContextPtr) + + xpath.ContextPtr.doc = oldXPContextDoc + xpath.ContextPtr.node = oldXPContextNode + xpath.ContextPtr.proximityPosition = oldXPProximityPosition + xpath.ContextPtr.contextSize = oldXPContextSize + xpath.ContextPtr.nsNr = oldXPNsNr + xpath.ContextPtr.namespaces = oldXPNamespaces + + if xpath.ResultPtr == nil { + err = errors.New("err in evaluating xpath: " + xpathExpr.String()) + return + } + return +} + +// Determine the actual return type of the XPath evaluation. +func (xpath *XPath) ReturnType() XPathObjectType { + return XPathObjectType(C.getXPathObjectType(xpath.ResultPtr)) +} + +// Get the XPath result as a nodeset. +func (xpath *XPath) ResultAsNodeset() (nodes []unsafe.Pointer, err error) { + if xpath.ResultPtr == nil { + return + } + + if xpath.ReturnType() != XPATH_NODESET { + err = errors.New("Cannot convert XPath result to nodeset") + } + + if nodesetPtr := xpath.ResultPtr.nodesetval; nodesetPtr != nil { + if nodesetSize := int(nodesetPtr.nodeNr); nodesetSize > 0 { + nodes = make([]unsafe.Pointer, nodesetSize) + for i := 0; i < nodesetSize; i++ { + nodes[i] = unsafe.Pointer(C.fetchNode(nodesetPtr, C.int(i))) + } + } + } + return +} + +// Coerce the result into a string +func (xpath *XPath) ResultAsString() (val string, err error) { + if xpath.ReturnType() != XPATH_STRING { + xpath.ResultPtr = C.xmlXPathConvertString(xpath.ResultPtr) + } + val = C.GoString((*C.char)(unsafe.Pointer(xpath.ResultPtr.stringval))) + return +} + +// Coerce the result into a number +func (xpath *XPath) ResultAsNumber() (val float64, err error) { + if xpath.ReturnType() != XPATH_NUMBER { + xpath.ResultPtr = C.xmlXPathConvertNumber(xpath.ResultPtr) + } + val = float64(xpath.ResultPtr.floatval) + return +} + +// Coerce the result into a boolean +func (xpath *XPath) ResultAsBoolean() (val bool, err error) { + xpath.ResultPtr = C.xmlXPathConvertBoolean(xpath.ResultPtr) + val = xpath.ResultPtr.boolval != 0 + return +} + +// Add a variable resolver. +func (xpath *XPath) SetResolver(v VariableScope) { + SetScope(unsafe.Pointer(xpath.ContextPtr), v) + C.set_var_lookup(xpath.ContextPtr, unsafe.Pointer(xpath.ContextPtr)) + C.set_function_lookup(xpath.ContextPtr, unsafe.Pointer(xpath.ContextPtr)) +} + +// SetContextPosition sets the internal values needed to +// determine the values of position() and last() for the +// current context node. +func (xpath *XPath) SetContextPosition(position, size int) { + xpath.ContextPtr.proximityPosition = C.int(position) + xpath.ContextPtr.contextSize = C.int(size) +} + +// GetContextPosition retrieves the internal values used to +// determine the values of position() and last() for the +// current context node. +// +// This allows values to saved and restored during processing +// of a document. +func (xpath *XPath) GetContextPosition() (position, size int) { + position = int(xpath.ContextPtr.proximityPosition) + size = int(xpath.ContextPtr.contextSize) + return +} + +func (xpath *XPath) Free() { + if xpath.ContextPtr != nil { + ClearScope(unsafe.Pointer(xpath.ContextPtr)) + C.xmlXPathFreeContext(xpath.ContextPtr) + xpath.ContextPtr = nil + } + if xpath.ResultPtr != nil { + C.xmlXPathFreeObject(xpath.ResultPtr) + xpath.ResultPtr = nil + } +} + +func XPathObjectToValue(obj C.xmlXPathObjectPtr) (result interface{}) { + rt := XPathObjectType(C.getXPathObjectType(obj)) + switch rt { + case XPATH_NODESET, XPATH_XSLT_TREE: + if nodesetPtr := obj.nodesetval; nodesetPtr != nil { + if nodesetSize := int(nodesetPtr.nodeNr); nodesetSize > 0 { + nodes := make([]unsafe.Pointer, nodesetSize) + for i := 0; i < nodesetSize; i++ { + nodes[i] = unsafe.Pointer(C.fetchNode(nodesetPtr, C.int(i))) + } + result = nodes + return + } + } + result = nil + case XPATH_NUMBER: + obj = C.xmlXPathConvertNumber(obj) + result = float64(obj.floatval) + case XPATH_BOOLEAN: + obj = C.xmlXPathConvertBoolean(obj) + result = obj.boolval != 0 + default: + obj = C.xmlXPathConvertString(obj) + result = C.GoString((*C.char)(unsafe.Pointer(obj.stringval))) + } + return +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/.travis.yml b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/.travis.yml new file mode 100644 index 000000000..eb336b4ff --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/.travis.yml @@ -0,0 +1,10 @@ +language: go + +go: + - 1.8.1 + +script: + - go test -v -race -coverprofile=coverage.txt -covermode=atomic + +after_success: + - bash <(curl -s https://codecov.io/bash) diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/README.md b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/README.md new file mode 100644 index 000000000..a8573f8d0 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/README.md @@ -0,0 +1,22 @@ +# xpathparser + +[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) +[![GoDoc](https://godoc.org/github.com/santhosh-tekuri/xpathparser?status.svg)](https://godoc.org/github.com/santhosh-tekuri/xpathparser) +[![Go Report Card](https://goreportcard.com/badge/github.com/santhosh-tekuri/xpathparser)](https://goreportcard.com/report/github.com/santhosh-tekuri/xpathparser) +[![Build Status](https://travis-ci.org/santhosh-tekuri/xpathparser.svg?branch=master)](https://travis-ci.org/santhosh-tekuri/xpathparser) +[![codecov.io](https://codecov.io/github/santhosh-tekuri/xpathparser/coverage.svg?branch=master)](https://codecov.io/github/santhosh-tekuri/xpathparser?branch=master) + +Package xpathparser provides lexer and parser for XPath 1.0. + +This Package parses given XPath expression to expression model. + +## Example + +An example of using this package: + +```go +expr := xpathparser.MustParse("(/a/b)[5]") +fmt.Println(expr) +``` + +This package does not evaluate xpath. For evaluating xpaths use https://github.com/santhosh-tekuri/xpath diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/doc.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/doc.go new file mode 100644 index 000000000..3c8b59d85 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/doc.go @@ -0,0 +1,16 @@ +// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package xpathparser provides lexer and parser for XPath 1.0. + +This Package parses given XPath expression to expression model. + +An example of using this package: + + expr := xpathparser.MustParse("(/a/b)[5]") + fmt.Println(expr) + +*/ +package xpathparser diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/lexer.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/lexer.go new file mode 100644 index 000000000..ad6434705 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/lexer.go @@ -0,0 +1,301 @@ +// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xpathparser + +// see lexer specification at https://www.w3.org/TR/xpath/#exprlex + +import ( + "bytes" + "strings" + "unicode/utf8" +) + +type kind int + +const ( + eof kind = iota - 1 + + // operators, note the order must same as Op enum values + eq + neq + lt + lte + gt + gte + plus + minus + multiply + mod + div + and + or + pipe + + slash + slashSlash + dot + dotDot + colon + colonColon + + at + dollar + comma + star + + lbracket + rbracket + lparen + rparen + + identifier + literal + number +) + +var kindNames = []string{ + ``, + `'='`, `"!="`, `'<'`, `"<="`, `'>'`, `">="`, + `'+'`, `'-'`, `'*'`, `"mod"`, `"div"`, + `"and"`, `"or"`, `'|'`, + `'/'`, `"//"`, `'.'`, `".."`, `':'`, `"::"`, + `'@'`, `'$'`, `','`, `'*'`, + `'['`, `']'`, `'('`, `')'`, + ``, ``, ``, +} + +func (k kind) String() string { + return kindNames[k+1] +} + +type token struct { + xpath string + kind kind + begin int + end int +} + +func (t token) text() string { + return t.xpath[t.begin:t.end] +} + +type lexer struct { + xpath string + pos int + expectOp bool +} + +func (l *lexer) err(msg string) (token, error) { + return token{}, &Error{msg, l.xpath, l.pos} +} + +func (l *lexer) char(i int) int { + if l.pos+i < len(l.xpath) { + return int(l.xpath[l.pos+i]) + } + return -1 +} + +func (l *lexer) consume(n int) { + l.pos += n +} + +func (l *lexer) hasMore() bool { + return l.pos < len(l.xpath) +} + +func (l *lexer) token(kind kind, n int) (token, error) { + var t token + if n > 0 { + t = token{l.xpath, kind, l.pos, l.pos + n} + l.consume(n) + } else { + t = token{l.xpath, kind, l.pos + n, l.pos} + } + switch kind { + case at, colonColon, lparen, lbracket, and, or, mod, div, colon, slash, slashSlash, + pipe, dollar, plus, minus, multiply, comma, lt, gt, lte, gte, eq, neq: + l.expectOp = false + default: + l.expectOp = true + } + return t, nil +} + +func (l *lexer) next() (token, error) { +SkipWS: + for l.hasMore() { + switch l.char(0) { + case ' ', '\t', '\n', '\r': + l.consume(1) + default: + break SkipWS + } + } + + switch l.char(0) { + case -1: + return l.token(eof, 0) + case '$': + return l.token(dollar, 1) + case '"', '\'': + return l.literal() + case '/': + if l.char(1) == '/' { + return l.token(slashSlash, 2) + } + return l.token(slash, 1) + case ',': + return l.token(comma, 1) + case '(': + return l.token(lparen, 1) + case ')': + return l.token(rparen, 1) + case '[': + return l.token(lbracket, 1) + case ']': + return l.token(rbracket, 1) + case '+': + return l.token(plus, 1) + case '-': + return l.token(minus, 1) + case '<': + if l.char(1) == '=' { + return l.token(lte, 2) + } + return l.token(lt, 1) + case '>': + if l.char(1) == '=' { + return l.token(gte, 2) + } + return l.token(gt, 1) + case '=': + return l.token(eq, 1) + case '!': + if l.char(1) == '=' { + return l.token(neq, 2) + } + return l.err("expected '!='") + case '|': + return l.token(pipe, 1) + case '@': + return l.token(at, 1) + case ':': + if l.char(1) == ':' { + return l.token(colonColon, 2) + } + return l.token(colon, 1) + case '*': + if l.expectOp { + return l.token(multiply, 1) + } + return l.token(star, 1) + case '.': + switch l.char(1) { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return l.number() + case '.': + return l.token(dotDot, 2) + default: + return l.token(dot, 1) + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + return l.number() + default: + if l.expectOp { + return l.operator() + } + return l.identifier() + } +} + +func (l *lexer) literal() (token, error) { + quote := l.char(0) + l.consume(1) + begin := l.pos + for { + switch l.char(0) { + case quote: + t, _ := l.token(literal, begin-l.pos) + l.consume(1) + return t, nil + case -1: + return l.err("unclosed literal") + } + l.consume(1) + } +} + +func (l *lexer) number() (token, error) { + begin := l.pos + dotAllowed := true +Loop: + for { + switch l.char(0) { + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + l.consume(1) + case '.': + if dotAllowed { + dotAllowed = false + l.consume(1) + } else { + break Loop + } + default: + break Loop + } + } + return l.token(number, begin-l.pos) +} + +func (l *lexer) operator() (token, error) { + remaining := l.xpath[l.pos:] + switch { + case strings.HasPrefix(remaining, "and"): + return l.token(and, 3) + case strings.HasPrefix(remaining, "or"): + return l.token(or, 2) + case strings.HasPrefix(remaining, "mod"): + return l.token(mod, 3) + case strings.HasPrefix(remaining, "div"): + return l.token(div, 3) + } + return l.err("operatorName expected") +} + +func (l *lexer) identifier() (token, error) { + begin := l.pos + b, ok := l.readName() + if !ok { + return l.err("identifier expected") + } + if !isName(b) { + l.pos = begin + return l.err("invalid identifier") + } + return l.token(identifier, begin-l.pos) +} + +func (l *lexer) readName() ([]byte, bool) { + if !l.hasMore() { + return nil, false + } + buf := new(bytes.Buffer) + b := byte(l.char(0)) + if b < utf8.RuneSelf && !isNameByte(b) { + return nil, false + } + buf.WriteByte(b) + l.consume(1) + for l.hasMore() { + b = byte(l.char(0)) + if b < utf8.RuneSelf && !isNameByte(b) { + break + } + buf.WriteByte(b) + l.consume(1) + } + return buf.Bytes(), true +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/name.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/name.go new file mode 100644 index 000000000..e802e9542 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/name.go @@ -0,0 +1,352 @@ +// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xpathparser + +import ( + "unicode" + "unicode/utf8" +) + +var first = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x0041, 0x005A, 1}, + {0x005F, 0x005F, 1}, + {0x0061, 0x007A, 1}, + {0x00C0, 0x00D6, 1}, + {0x00D8, 0x00F6, 1}, + {0x00F8, 0x00FF, 1}, + {0x0100, 0x0131, 1}, + {0x0134, 0x013E, 1}, + {0x0141, 0x0148, 1}, + {0x014A, 0x017E, 1}, + {0x0180, 0x01C3, 1}, + {0x01CD, 0x01F0, 1}, + {0x01F4, 0x01F5, 1}, + {0x01FA, 0x0217, 1}, + {0x0250, 0x02A8, 1}, + {0x02BB, 0x02C1, 1}, + {0x0386, 0x0386, 1}, + {0x0388, 0x038A, 1}, + {0x038C, 0x038C, 1}, + {0x038E, 0x03A1, 1}, + {0x03A3, 0x03CE, 1}, + {0x03D0, 0x03D6, 1}, + {0x03DA, 0x03E0, 2}, + {0x03E2, 0x03F3, 1}, + {0x0401, 0x040C, 1}, + {0x040E, 0x044F, 1}, + {0x0451, 0x045C, 1}, + {0x045E, 0x0481, 1}, + {0x0490, 0x04C4, 1}, + {0x04C7, 0x04C8, 1}, + {0x04CB, 0x04CC, 1}, + {0x04D0, 0x04EB, 1}, + {0x04EE, 0x04F5, 1}, + {0x04F8, 0x04F9, 1}, + {0x0531, 0x0556, 1}, + {0x0559, 0x0559, 1}, + {0x0561, 0x0586, 1}, + {0x05D0, 0x05EA, 1}, + {0x05F0, 0x05F2, 1}, + {0x0621, 0x063A, 1}, + {0x0641, 0x064A, 1}, + {0x0671, 0x06B7, 1}, + {0x06BA, 0x06BE, 1}, + {0x06C0, 0x06CE, 1}, + {0x06D0, 0x06D3, 1}, + {0x06D5, 0x06D5, 1}, + {0x06E5, 0x06E6, 1}, + {0x0905, 0x0939, 1}, + {0x093D, 0x093D, 1}, + {0x0958, 0x0961, 1}, + {0x0985, 0x098C, 1}, + {0x098F, 0x0990, 1}, + {0x0993, 0x09A8, 1}, + {0x09AA, 0x09B0, 1}, + {0x09B2, 0x09B2, 1}, + {0x09B6, 0x09B9, 1}, + {0x09DC, 0x09DD, 1}, + {0x09DF, 0x09E1, 1}, + {0x09F0, 0x09F1, 1}, + {0x0A05, 0x0A0A, 1}, + {0x0A0F, 0x0A10, 1}, + {0x0A13, 0x0A28, 1}, + {0x0A2A, 0x0A30, 1}, + {0x0A32, 0x0A33, 1}, + {0x0A35, 0x0A36, 1}, + {0x0A38, 0x0A39, 1}, + {0x0A59, 0x0A5C, 1}, + {0x0A5E, 0x0A5E, 1}, + {0x0A72, 0x0A74, 1}, + {0x0A85, 0x0A8B, 1}, + {0x0A8D, 0x0A8D, 1}, + {0x0A8F, 0x0A91, 1}, + {0x0A93, 0x0AA8, 1}, + {0x0AAA, 0x0AB0, 1}, + {0x0AB2, 0x0AB3, 1}, + {0x0AB5, 0x0AB9, 1}, + {0x0ABD, 0x0AE0, 0x23}, + {0x0B05, 0x0B0C, 1}, + {0x0B0F, 0x0B10, 1}, + {0x0B13, 0x0B28, 1}, + {0x0B2A, 0x0B30, 1}, + {0x0B32, 0x0B33, 1}, + {0x0B36, 0x0B39, 1}, + {0x0B3D, 0x0B3D, 1}, + {0x0B5C, 0x0B5D, 1}, + {0x0B5F, 0x0B61, 1}, + {0x0B85, 0x0B8A, 1}, + {0x0B8E, 0x0B90, 1}, + {0x0B92, 0x0B95, 1}, + {0x0B99, 0x0B9A, 1}, + {0x0B9C, 0x0B9C, 1}, + {0x0B9E, 0x0B9F, 1}, + {0x0BA3, 0x0BA4, 1}, + {0x0BA8, 0x0BAA, 1}, + {0x0BAE, 0x0BB5, 1}, + {0x0BB7, 0x0BB9, 1}, + {0x0C05, 0x0C0C, 1}, + {0x0C0E, 0x0C10, 1}, + {0x0C12, 0x0C28, 1}, + {0x0C2A, 0x0C33, 1}, + {0x0C35, 0x0C39, 1}, + {0x0C60, 0x0C61, 1}, + {0x0C85, 0x0C8C, 1}, + {0x0C8E, 0x0C90, 1}, + {0x0C92, 0x0CA8, 1}, + {0x0CAA, 0x0CB3, 1}, + {0x0CB5, 0x0CB9, 1}, + {0x0CDE, 0x0CDE, 1}, + {0x0CE0, 0x0CE1, 1}, + {0x0D05, 0x0D0C, 1}, + {0x0D0E, 0x0D10, 1}, + {0x0D12, 0x0D28, 1}, + {0x0D2A, 0x0D39, 1}, + {0x0D60, 0x0D61, 1}, + {0x0E01, 0x0E2E, 1}, + {0x0E30, 0x0E30, 1}, + {0x0E32, 0x0E33, 1}, + {0x0E40, 0x0E45, 1}, + {0x0E81, 0x0E82, 1}, + {0x0E84, 0x0E84, 1}, + {0x0E87, 0x0E88, 1}, + {0x0E8A, 0x0E8D, 3}, + {0x0E94, 0x0E97, 1}, + {0x0E99, 0x0E9F, 1}, + {0x0EA1, 0x0EA3, 1}, + {0x0EA5, 0x0EA7, 2}, + {0x0EAA, 0x0EAB, 1}, + {0x0EAD, 0x0EAE, 1}, + {0x0EB0, 0x0EB0, 1}, + {0x0EB2, 0x0EB3, 1}, + {0x0EBD, 0x0EBD, 1}, + {0x0EC0, 0x0EC4, 1}, + {0x0F40, 0x0F47, 1}, + {0x0F49, 0x0F69, 1}, + {0x10A0, 0x10C5, 1}, + {0x10D0, 0x10F6, 1}, + {0x1100, 0x1100, 1}, + {0x1102, 0x1103, 1}, + {0x1105, 0x1107, 1}, + {0x1109, 0x1109, 1}, + {0x110B, 0x110C, 1}, + {0x110E, 0x1112, 1}, + {0x113C, 0x1140, 2}, + {0x114C, 0x1150, 2}, + {0x1154, 0x1155, 1}, + {0x1159, 0x1159, 1}, + {0x115F, 0x1161, 1}, + {0x1163, 0x1169, 2}, + {0x116D, 0x116E, 1}, + {0x1172, 0x1173, 1}, + {0x1175, 0x119E, 0x119E - 0x1175}, + {0x11A8, 0x11AB, 0x11AB - 0x11A8}, + {0x11AE, 0x11AF, 1}, + {0x11B7, 0x11B8, 1}, + {0x11BA, 0x11BA, 1}, + {0x11BC, 0x11C2, 1}, + {0x11EB, 0x11F0, 0x11F0 - 0x11EB}, + {0x11F9, 0x11F9, 1}, + {0x1E00, 0x1E9B, 1}, + {0x1EA0, 0x1EF9, 1}, + {0x1F00, 0x1F15, 1}, + {0x1F18, 0x1F1D, 1}, + {0x1F20, 0x1F45, 1}, + {0x1F48, 0x1F4D, 1}, + {0x1F50, 0x1F57, 1}, + {0x1F59, 0x1F5B, 0x1F5B - 0x1F59}, + {0x1F5D, 0x1F5D, 1}, + {0x1F5F, 0x1F7D, 1}, + {0x1F80, 0x1FB4, 1}, + {0x1FB6, 0x1FBC, 1}, + {0x1FBE, 0x1FBE, 1}, + {0x1FC2, 0x1FC4, 1}, + {0x1FC6, 0x1FCC, 1}, + {0x1FD0, 0x1FD3, 1}, + {0x1FD6, 0x1FDB, 1}, + {0x1FE0, 0x1FEC, 1}, + {0x1FF2, 0x1FF4, 1}, + {0x1FF6, 0x1FFC, 1}, + {0x2126, 0x2126, 1}, + {0x212A, 0x212B, 1}, + {0x212E, 0x212E, 1}, + {0x2180, 0x2182, 1}, + {0x3007, 0x3007, 1}, + {0x3021, 0x3029, 1}, + {0x3041, 0x3094, 1}, + {0x30A1, 0x30FA, 1}, + {0x3105, 0x312C, 1}, + {0x4E00, 0x9FA5, 1}, + {0xAC00, 0xD7A3, 1}, + }, +} + +var second = &unicode.RangeTable{ + R16: []unicode.Range16{ + {0x002D, 0x002E, 1}, + {0x0030, 0x0039, 1}, + {0x00B7, 0x00B7, 1}, + {0x02D0, 0x02D1, 1}, + {0x0300, 0x0345, 1}, + {0x0360, 0x0361, 1}, + {0x0387, 0x0387, 1}, + {0x0483, 0x0486, 1}, + {0x0591, 0x05A1, 1}, + {0x05A3, 0x05B9, 1}, + {0x05BB, 0x05BD, 1}, + {0x05BF, 0x05BF, 1}, + {0x05C1, 0x05C2, 1}, + {0x05C4, 0x0640, 0x0640 - 0x05C4}, + {0x064B, 0x0652, 1}, + {0x0660, 0x0669, 1}, + {0x0670, 0x0670, 1}, + {0x06D6, 0x06DC, 1}, + {0x06DD, 0x06DF, 1}, + {0x06E0, 0x06E4, 1}, + {0x06E7, 0x06E8, 1}, + {0x06EA, 0x06ED, 1}, + {0x06F0, 0x06F9, 1}, + {0x0901, 0x0903, 1}, + {0x093C, 0x093C, 1}, + {0x093E, 0x094C, 1}, + {0x094D, 0x094D, 1}, + {0x0951, 0x0954, 1}, + {0x0962, 0x0963, 1}, + {0x0966, 0x096F, 1}, + {0x0981, 0x0983, 1}, + {0x09BC, 0x09BC, 1}, + {0x09BE, 0x09BF, 1}, + {0x09C0, 0x09C4, 1}, + {0x09C7, 0x09C8, 1}, + {0x09CB, 0x09CD, 1}, + {0x09D7, 0x09D7, 1}, + {0x09E2, 0x09E3, 1}, + {0x09E6, 0x09EF, 1}, + {0x0A02, 0x0A3C, 0x3A}, + {0x0A3E, 0x0A3F, 1}, + {0x0A40, 0x0A42, 1}, + {0x0A47, 0x0A48, 1}, + {0x0A4B, 0x0A4D, 1}, + {0x0A66, 0x0A6F, 1}, + {0x0A70, 0x0A71, 1}, + {0x0A81, 0x0A83, 1}, + {0x0ABC, 0x0ABC, 1}, + {0x0ABE, 0x0AC5, 1}, + {0x0AC7, 0x0AC9, 1}, + {0x0ACB, 0x0ACD, 1}, + {0x0AE6, 0x0AEF, 1}, + {0x0B01, 0x0B03, 1}, + {0x0B3C, 0x0B3C, 1}, + {0x0B3E, 0x0B43, 1}, + {0x0B47, 0x0B48, 1}, + {0x0B4B, 0x0B4D, 1}, + {0x0B56, 0x0B57, 1}, + {0x0B66, 0x0B6F, 1}, + {0x0B82, 0x0B83, 1}, + {0x0BBE, 0x0BC2, 1}, + {0x0BC6, 0x0BC8, 1}, + {0x0BCA, 0x0BCD, 1}, + {0x0BD7, 0x0BD7, 1}, + {0x0BE7, 0x0BEF, 1}, + {0x0C01, 0x0C03, 1}, + {0x0C3E, 0x0C44, 1}, + {0x0C46, 0x0C48, 1}, + {0x0C4A, 0x0C4D, 1}, + {0x0C55, 0x0C56, 1}, + {0x0C66, 0x0C6F, 1}, + {0x0C82, 0x0C83, 1}, + {0x0CBE, 0x0CC4, 1}, + {0x0CC6, 0x0CC8, 1}, + {0x0CCA, 0x0CCD, 1}, + {0x0CD5, 0x0CD6, 1}, + {0x0CE6, 0x0CEF, 1}, + {0x0D02, 0x0D03, 1}, + {0x0D3E, 0x0D43, 1}, + {0x0D46, 0x0D48, 1}, + {0x0D4A, 0x0D4D, 1}, + {0x0D57, 0x0D57, 1}, + {0x0D66, 0x0D6F, 1}, + {0x0E31, 0x0E31, 1}, + {0x0E34, 0x0E3A, 1}, + {0x0E46, 0x0E46, 1}, + {0x0E47, 0x0E4E, 1}, + {0x0E50, 0x0E59, 1}, + {0x0EB1, 0x0EB1, 1}, + {0x0EB4, 0x0EB9, 1}, + {0x0EBB, 0x0EBC, 1}, + {0x0EC6, 0x0EC6, 1}, + {0x0EC8, 0x0ECD, 1}, + {0x0ED0, 0x0ED9, 1}, + {0x0F18, 0x0F19, 1}, + {0x0F20, 0x0F29, 1}, + {0x0F35, 0x0F39, 2}, + {0x0F3E, 0x0F3F, 1}, + {0x0F71, 0x0F84, 1}, + {0x0F86, 0x0F8B, 1}, + {0x0F90, 0x0F95, 1}, + {0x0F97, 0x0F97, 1}, + {0x0F99, 0x0FAD, 1}, + {0x0FB1, 0x0FB7, 1}, + {0x0FB9, 0x0FB9, 1}, + {0x20D0, 0x20DC, 1}, + {0x20E1, 0x3005, 0x3005 - 0x20E1}, + {0x302A, 0x302F, 1}, + {0x3031, 0x3035, 1}, + {0x3099, 0x309A, 1}, + {0x309D, 0x309E, 1}, + {0x30FC, 0x30FE, 1}, + }, +} + +func isNameByte(c byte) bool { + return 'A' <= c && c <= 'Z' || + 'a' <= c && c <= 'z' || + '0' <= c && c <= '9' || + c == '_' || c == '.' || c == '-' +} + +func isName(s []byte) bool { + if len(s) == 0 { + return false + } + c, n := utf8.DecodeRune(s) + if c == utf8.RuneError && n == 1 { + return false + } + if !unicode.Is(first, c) { + return false + } + for n < len(s) { + s = s[n:] + c, n = utf8.DecodeRune(s) + if c == utf8.RuneError && n == 1 { + return false + } + if !unicode.Is(first, c) && !unicode.Is(second, c) { + return false + } + } + return true +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/parser.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/parser.go new file mode 100644 index 000000000..a12d4a0ee --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/parser.go @@ -0,0 +1,435 @@ +// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xpathparser + +import ( + "fmt" + "strconv" + "strings" +) + +type parser struct { + lexer lexer + tokens []token +} + +func (p *parser) error(format string, args ...interface{}) error { + return &Error{fmt.Sprintf(format, args...), p.lexer.xpath, p.token(0).begin} +} + +func (p *parser) unexpectedToken() error { + return p.error("unexpected token %s", p.token(0).kind) +} + +func (p *parser) expectedTokens(expected ...kind) error { + tokens := make([]string, len(expected)) + for i, k := range expected { + tokens[i] = k.String() + } + return p.error("expected %s, but got %v", strings.Join(tokens, " or "), p.token(0).kind) +} + +func (p *parser) token(i int) token { + for i > len(p.tokens)-1 { + t, err := p.lexer.next() + if err != nil { + panic(err) + } + p.tokens = append(p.tokens, t) + } + return p.tokens[i] +} + +func (p *parser) match(k kind) token { + t := p.token(0) + if t.kind != k { + panic(p.error("expected %v, but got %v", k, t.kind)) + } + p.tokens = p.tokens[1:] + return t +} + +func (p *parser) parse() Expr { + expr := p.orExpr() + p.match(eof) + return expr +} + +func (p *parser) orExpr() Expr { + expr := p.andExpr() + if p.token(0).kind == or { + p.match(or) + return &BinaryExpr{expr, Or, p.orExpr()} + } + return expr +} + +func (p *parser) andExpr() Expr { + expr := p.equalityExpr() + if p.token(0).kind == and { + p.match(and) + return &BinaryExpr{expr, And, p.andExpr()} + } + return expr +} + +func (p *parser) equalityExpr() Expr { + expr := p.relationalExpr() + for { + switch kind := p.token(0).kind; kind { + case eq, neq: + p.match(kind) + expr = &BinaryExpr{expr, Op(kind), p.relationalExpr()} + default: + return expr + } + } +} + +func (p *parser) relationalExpr() Expr { + expr := p.additiveExpr() + for { + switch kind := p.token(0).kind; kind { + case lt, lte, gt, gte: + p.match(kind) + expr = &BinaryExpr{expr, Op(kind), p.additiveExpr()} + default: + return expr + } + } +} + +func (p *parser) additiveExpr() Expr { + expr := p.multiplicativeExpr() + for { + switch kind := p.token(0).kind; kind { + case plus, minus: + p.match(kind) + expr = &BinaryExpr{expr, Op(kind), p.multiplicativeExpr()} + default: + return expr + } + } +} + +func (p *parser) multiplicativeExpr() Expr { + expr := p.unaryExpr() + for { + switch kind := p.token(0).kind; kind { + case multiply, div, mod: + p.match(kind) + expr = &BinaryExpr{expr, Op(kind), p.unaryExpr()} + default: + return expr + } + } +} + +func (p *parser) unaryExpr() Expr { + if p.token(0).kind == minus { + p.match(minus) + return &NegateExpr{p.unionExpr()} + } + return p.unionExpr() +} + +func (p *parser) unionExpr() Expr { + expr := p.pathExpr() + if p.token(0).kind == pipe { + p.match(pipe) + return &BinaryExpr{expr, Union, p.orExpr()} + } + return expr +} + +func (p *parser) pathExpr() Expr { + switch p.token(0).kind { + case number, literal: + filter := p.filterExpr() + switch p.token(0).kind { + case slash, slashSlash: + panic(p.error("nodeset expected")) + } + return filter + case lparen, dollar: + filter := p.filterExpr() + switch p.token(0).kind { + case slash, slashSlash: + return &PathExpr{filter, p.locationPath(false)} + } + return filter + case identifier: + if (p.token(1).kind == lparen && !isNodeTypeName(p.token(0))) || (p.token(1).kind == colon && p.token(3).kind == lparen) { + filter := p.filterExpr() + switch p.token(0).kind { + case slash, slashSlash: + return &PathExpr{filter, p.locationPath(false)} + } + return filter + } + return p.locationPath(false) + case dot, dotDot, star, at: + return p.locationPath(false) + case slash, slashSlash: + return p.locationPath(true) + default: + panic(p.unexpectedToken()) + } +} + +func (p *parser) filterExpr() Expr { + var expr Expr + switch p.token(0).kind { + case number: + f, err := strconv.ParseFloat(p.match(number).text(), 64) + if err != nil { + panic(err) + } + expr = Number(f) + case literal: + expr = String(p.match(literal).text()) + case lparen: + p.match(lparen) + expr = p.orExpr() + p.match(rparen) + case identifier: + expr = p.functionCall() + case dollar: + expr = p.variableReference() + } + predicates := p.predicates() + if len(predicates) == 0 { + return expr + } + return &FilterExpr{expr, predicates} +} + +func (p *parser) functionCall() *FuncCall { + prefix := "" + if p.token(1).kind == colon { + prefix = p.match(identifier).text() + p.match(colon) + } + local := p.match(identifier).text() + p.match(lparen) + args := p.arguments() + p.match(rparen) + return &FuncCall{prefix, local, args} +} + +func (p *parser) arguments() []Expr { + var args []Expr + for p.token(0).kind != rparen { + args = append(args, p.orExpr()) + if p.token(0).kind == comma { + p.match(comma) + continue + } + break + } + return args +} + +func (p *parser) predicates() []Expr { + var predicates []Expr + for p.token(0).kind == lbracket { + p.match(lbracket) + predicates = append(predicates, p.orExpr()) + p.match(rbracket) + } + return predicates +} + +func (p *parser) variableReference() *VarRef { + p.match(dollar) + prefix := "" + if p.token(1).kind == colon { + prefix = p.match(identifier).text() + p.match(colon) + } + return &VarRef{prefix, p.match(identifier).text()} +} + +func (p *parser) locationPath(abs bool) *LocationPath { + switch p.token(0).kind { + case slash, slashSlash: + if abs { + return p.absoluteLocationPath() + } + return p.relativeLocationPath() + case at, identifier, dot, dotDot, star: + return p.relativeLocationPath() + } + panic(p.unexpectedToken()) +} + +func (p *parser) absoluteLocationPath() *LocationPath { + var steps []*Step + switch p.token(0).kind { + case slash: + p.match(slash) + switch p.token(0).kind { + case dot, dotDot, at, identifier, star: + steps = p.steps() + } + case slashSlash: + p.match(slashSlash) + steps = append(steps, &Step{DescendantOrSelf, Node, nil}) + switch p.token(0).kind { + case dot, dotDot, at, identifier, star: + steps = append(steps, p.steps()...) + default: + panic(p.error(`locationPath cannot end with "//"`)) + } + } + return &LocationPath{true, steps} +} + +func (p *parser) relativeLocationPath() *LocationPath { + var steps []*Step + switch p.token(0).kind { + case slash: + p.match(slash) + case slashSlash: + p.match(slashSlash) + steps = append(steps, &Step{DescendantOrSelf, Node, nil}) + } + steps = append(steps, p.steps()...) + return &LocationPath{false, steps} +} + +func (p *parser) steps() []*Step { + var steps []*Step + switch p.token(0).kind { + case dot, dotDot, at, identifier, star: + steps = append(steps, p.step()) + case eof: + return steps + default: + panic(p.expectedTokens(dot, dotDot, at, identifier, star)) + } + for { + switch p.token(0).kind { + case slash: + p.match(slash) + case slashSlash: + p.match(slashSlash) + steps = append(steps, &Step{DescendantOrSelf, Node, nil}) + default: + return steps + } + switch p.token(0).kind { + case dot, dotDot, at, identifier, star: + steps = append(steps, p.step()) + default: + panic(p.expectedTokens(dot, dotDot, at, identifier, star)) + } + } +} + +func (p *parser) step() *Step { + var axis Axis + var nodeTest NodeTest + switch p.token(0).kind { + case dot: + p.match(dot) + axis, nodeTest = Self, Node + case dotDot: + p.match(dotDot) + axis, nodeTest = Parent, Node + default: + switch p.token(0).kind { + case at: + p.match(at) + axis = Attribute + case identifier: + if p.token(1).kind == colonColon { + axis = p.axisSpecifier() + } else { + axis = Child + } + case star: + axis = Child + } + nodeTest = p.nodeTest(axis) + } + return &Step{axis, nodeTest, p.predicates()} +} + +func (p *parser) nodeTest(axis Axis) NodeTest { + switch p.token(0).kind { + case identifier: + if p.token(1).kind == lparen { + return p.nodeTypeTest(axis) + } + return p.nameTest(axis) + case star: + return p.nameTest(axis) + } + panic(p.expectedTokens(identifier, star)) +} + +func (p *parser) nodeTypeTest(axis Axis) NodeTest { + ntype := p.match(identifier).text() + p.match(lparen) + var nodeTest NodeTest + switch ntype { + case "processing-instruction": + piName := "" + if p.token(0).kind == literal { + piName = p.match(literal).text() + } + nodeTest = PITest(piName) + case "node": + nodeTest = Node + case "text": + nodeTest = Text + case "comment": + nodeTest = Comment + default: + panic(p.error("invalid nodeType %q", ntype)) + } + p.match(rparen) + return nodeTest +} + +func (p *parser) nameTest(axis Axis) NodeTest { + var prefix string + if p.token(0).kind == identifier && p.token(1).kind == colon { + prefix = p.match(identifier).text() + p.match(colon) + } + var local string + switch p.token(0).kind { + case identifier: + local = p.match(identifier).text() + case star: + p.match(star) + local = "*" + default: + // let us assume localName as empty-string and continue + } + return &NameTest{prefix, local} +} + +func (p *parser) axisSpecifier() Axis { + name := p.token(0).text() + axis, ok := name2Axis[name] + if !ok { + panic(p.error("invalid axis %s", name)) + } + p.match(identifier) + p.match(colonColon) + return axis +} + +func isNodeTypeName(t token) bool { + switch t.text() { + case "node", "comment", "text", "processing-instruction": + return true + default: + return false + } +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/stub.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/stub.go deleted file mode 100644 index 8bb9a6ced..000000000 --- a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/stub.go +++ /dev/null @@ -1,20 +0,0 @@ -// Code generated by depstubber. DO NOT EDIT. -// This is a simple stub for github.com/santhosh-tekuri/xpathparser, strictly for use in testing. - -// See the LICENSE file for information about the licensing of the original library. -// Source: github.com/santhosh-tekuri/xpathparser (exports: ; functions: Parse,MustParse) - -// Package xpathparser is a stub of github.com/santhosh-tekuri/xpathparser, generated by depstubber. -package xpathparser - -import () - -type Expr interface{} - -func MustParse(_ string) Expr { - return nil -} - -func Parse(_ string) (Expr, error) { - return nil, nil -} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/xpath.go b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/xpath.go new file mode 100644 index 000000000..c35469865 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/github.com/santhosh-tekuri/xpathparser/xpath.go @@ -0,0 +1,288 @@ +// Copyright 2017 Santhosh Kumar Tekuri. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xpathparser + +import ( + "fmt" + "runtime" + "strconv" + "strings" +) + +// Error is the error type returned by Parse function. +// +// It represents a syntax error in the XPath expression. +type Error struct { + Msg string + XPath string + Offset int +} + +func (e *Error) Error() string { + return fmt.Sprintf("%s in xpath %s at offset %d", e.Msg, e.XPath, e.Offset) +} + +// Axis specifies the tree relationship between the nodes selected by the location step and the context node. +type Axis int + +// Possible values for Axis. +const ( + Child Axis = iota + Descendant + Parent + Ancestor + FollowingSibling + PrecedingSibling + Following + Preceding + Attribute + Namespace + Self + DescendantOrSelf + AncestorOrSelf +) + +var axisNames = []string{ + "child", + "descendant", + "parent", + "ancestor", + "following-sibling", + "preceding-sibling", + "following", + "preceding", + "attribute", + "namespace", + "self", + "descendant-or-self", + "ancestor-or-self", +} + +func (a Axis) String() string { + return axisNames[a] +} + +var name2Axis = make(map[string]Axis) + +func init() { + for i, name := range axisNames { + name2Axis[name] = Axis(i) + } +} + +// NodeType represents test on node type. +type NodeType int + +// Possible values for NodeType. +const ( + Comment NodeType = iota + Text + Node +) + +var nodeTypeNames = []string{"comment()", "text()", "node()"} + +func (nt NodeType) String() string { + return nodeTypeNames[nt] +} + +// Op represents XPath binrary operator. +type Op int + +// Possible values for Op. +const ( + EQ Op = iota + NEQ + LT + LTE + GT + GTE + Add + Subtract + Multiply + Mod + Div + And + Or + Union +) + +func (op Op) String() string { + str := kind(op).String() + return str[1 : len(str)-1] +} + +// An Expr is an interface holding one of the types: +// *LocationPath, *FilterExpr, *PathExpr, *BinaryExpr, *NegateExpr, *VarRef, *FuncCall, Number or String +type Expr interface{} + +// BinaryExpr represents a binary operation. +type BinaryExpr struct { + LHS Expr + Op Op + RHS Expr +} + +func (b *BinaryExpr) String() string { + return fmt.Sprintf("(%s %s %s)", b.LHS, b.Op, b.RHS) +} + +// NegateExpr represents unary operator `-`. +type NegateExpr struct { + Expr Expr +} + +func (n *NegateExpr) String() string { + return fmt.Sprintf("-%s", n.Expr) +} + +// LocationPath represents XPath location path. +type LocationPath struct { + Abs bool + Steps []*Step +} + +func (lp *LocationPath) String() string { + s := make([]string, len(lp.Steps)) + for i, step := range lp.Steps { + s[i] = step.String() + } + if lp.Abs { + return fmt.Sprintf("/%s", strings.Join(s, "/")) + } + return fmt.Sprintf("%s", strings.Join(s, "/")) +} + +// FilterExpr represents https://www.w3.org/TR/xpath/#NT-FilterExpr. +type FilterExpr struct { + Expr Expr + Predicates []Expr +} + +func (f *FilterExpr) String() string { + return fmt.Sprintf("(%s)%s", f.Expr, predicatesString(f.Predicates)) +} + +// PathExpr represents https://www.w3.org/TR/xpath/#NT-PathExpr. +type PathExpr struct { + Filter Expr + LocationPath *LocationPath +} + +func (p *PathExpr) String() string { + return fmt.Sprintf("(%s)/%s", p.Filter, p.LocationPath) +} + +// Step represents XPath location step. +type Step struct { + Axis Axis + NodeTest NodeTest + Predicates []Expr +} + +func (s *Step) String() string { + return fmt.Sprintf("%v::%s%s", s.Axis, s.NodeTest, predicatesString(s.Predicates)) +} + +// A NodeTest is an interface holding one of the types: +// NodeType, *NameTest, or PITest. +type NodeTest interface{} + +// NameTest represents https://www.w3.org/TR/xpath/#NT-NameTest. +type NameTest struct { + Prefix string + Local string +} + +func (nt *NameTest) String() string { + if nt.Prefix == "" { + return nt.Local + } + return fmt.Sprintf("%s:%s", nt.Prefix, nt.Local) +} + +// PITest represents processing-instruction test. +type PITest string + +func (pt PITest) String() string { + return fmt.Sprintf("processing-instruction(%q)", string(pt)) +} + +// VarRef represents https://www.w3.org/TR/xpath/#NT-VariableReference. +type VarRef struct { + Prefix string + Local string +} + +func (vr *VarRef) String() string { + if vr.Prefix == "" { + return fmt.Sprintf("$%s", vr.Local) + } + return fmt.Sprintf("$%s:%s", vr.Prefix, vr.Local) +} + +// FuncCall represents https://www.w3.org/TR/xpath/#section-Function-Calls. +type FuncCall struct { + Prefix string + Local string + Args []Expr +} + +func (fc *FuncCall) String() string { + p := make([]string, len(fc.Args)) + for i, param := range fc.Args { + p[i] = fmt.Sprint(param) + } + if fc.Prefix == "" { + return fmt.Sprintf("%s(%s)", fc.Local, strings.Join(p, ", ")) + } + return fmt.Sprintf("%s:%s(%s)", fc.Prefix, fc.Local, strings.Join(p, ", ")) +} + +// Number represents number literal. +type Number float64 + +func (n Number) String() string { + return strconv.FormatFloat(float64(n), 'f', -1, 64) +} + +// String represents string literal. +type String string + +func (s String) String() string { + return strconv.Quote(string(s)) +} + +// MustParse is like Parse but panics if the xpath expression has error. +// It simplifies safe initialization of global variables holding parsed expressions. +func MustParse(xpath string) Expr { + p := &parser{lexer: lexer{xpath: xpath}} + return p.parse() +} + +// Parse parses given xpath 1.0 expression. +func Parse(xpath string) (expr Expr, err error) { + defer func() { + if r := recover(); r != nil { + if _, ok := r.(runtime.Error); ok { + panic(r) + } + if _, ok := r.(error); ok { + err = r.(error) + } else { + err = fmt.Errorf("%v", r) + } + } + }() + return MustParse(xpath), nil +} + +func predicatesString(predicates []Expr) string { + p := make([]string, len(predicates)) + for i, predicate := range predicates { + p[i] = fmt.Sprintf("[%s]", predicate) + } + return strings.Join(p, "") +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/AUTHORS b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/AUTHORS new file mode 100644 index 000000000..15167cd74 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/AUTHORS @@ -0,0 +1,3 @@ +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at http://tip.golang.org/AUTHORS. diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/CONTRIBUTORS b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/CONTRIBUTORS new file mode 100644 index 000000000..1c4577e96 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/CONTRIBUTORS @@ -0,0 +1,3 @@ +# This source code was written by the Go contributors. +# The master list of contributors is in the main Go distribution, +# visible at http://tip.golang.org/CONTRIBUTORS. diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/LICENSE b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/PATENTS b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/PATENTS new file mode 100644 index 000000000..733099041 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/atom.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/atom.go new file mode 100644 index 000000000..cd0a8ac15 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/atom.go @@ -0,0 +1,78 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package atom provides integer codes (also known as atoms) for a fixed set of +// frequently occurring HTML strings: tag names and attribute keys such as "p" +// and "id". +// +// Sharing an atom's name between all elements with the same tag can result in +// fewer string allocations when tokenizing and parsing HTML. Integer +// comparisons are also generally faster than string comparisons. +// +// The value of an atom's particular code is not guaranteed to stay the same +// between versions of this package. Neither is any ordering guaranteed: +// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to +// be dense. The only guarantees are that e.g. looking up "div" will yield +// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0. +package atom // import "golang.org/x/net/html/atom" + +// Atom is an integer code for a string. The zero value maps to "". +type Atom uint32 + +// String returns the atom's name. +func (a Atom) String() string { + start := uint32(a >> 8) + n := uint32(a & 0xff) + if start+n > uint32(len(atomText)) { + return "" + } + return atomText[start : start+n] +} + +func (a Atom) string() string { + return atomText[a>>8 : a>>8+a&0xff] +} + +// fnv computes the FNV hash with an arbitrary starting value h. +func fnv(h uint32, s []byte) uint32 { + for i := range s { + h ^= uint32(s[i]) + h *= 16777619 + } + return h +} + +func match(s string, t []byte) bool { + for i, c := range t { + if s[i] != c { + return false + } + } + return true +} + +// Lookup returns the atom whose name is s. It returns zero if there is no +// such atom. The lookup is case sensitive. +func Lookup(s []byte) Atom { + if len(s) == 0 || len(s) > maxAtomLen { + return 0 + } + h := fnv(hash0, s) + if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { + return a + } + if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { + return a + } + return 0 +} + +// String returns a string whose contents are equal to s. In that sense, it is +// equivalent to string(s) but may be more efficient. +func String(s []byte) string { + if a := Lookup(s); a != 0 { + return a.String() + } + return string(s) +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/table.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/table.go new file mode 100644 index 000000000..2a938864c --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/atom/table.go @@ -0,0 +1,783 @@ +// Code generated by go generate gen.go; DO NOT EDIT. + +//go:generate go run gen.go + +package atom + +const ( + A Atom = 0x1 + Abbr Atom = 0x4 + Accept Atom = 0x1a06 + AcceptCharset Atom = 0x1a0e + Accesskey Atom = 0x2c09 + Acronym Atom = 0xaa07 + Action Atom = 0x27206 + Address Atom = 0x6f307 + Align Atom = 0xb105 + Allowfullscreen Atom = 0x2080f + Allowpaymentrequest Atom = 0xc113 + Allowusermedia Atom = 0xdd0e + Alt Atom = 0xf303 + Annotation Atom = 0x1c90a + AnnotationXml Atom = 0x1c90e + Applet Atom = 0x31906 + Area Atom = 0x35604 + Article Atom = 0x3fc07 + As Atom = 0x3c02 + Aside Atom = 0x10705 + Async Atom = 0xff05 + Audio Atom = 0x11505 + Autocomplete Atom = 0x2780c + Autofocus Atom = 0x12109 + Autoplay Atom = 0x13c08 + B Atom = 0x101 + Base Atom = 0x3b04 + Basefont Atom = 0x3b08 + Bdi Atom = 0xba03 + Bdo Atom = 0x14b03 + Bgsound Atom = 0x15e07 + Big Atom = 0x17003 + Blink Atom = 0x17305 + Blockquote Atom = 0x1870a + Body Atom = 0x2804 + Br Atom = 0x202 + Button Atom = 0x19106 + Canvas Atom = 0x10306 + Caption Atom = 0x23107 + Center Atom = 0x22006 + Challenge Atom = 0x29b09 + Charset Atom = 0x2107 + Checked Atom = 0x47907 + Cite Atom = 0x19c04 + Class Atom = 0x56405 + Code Atom = 0x5c504 + Col Atom = 0x1ab03 + Colgroup Atom = 0x1ab08 + Color Atom = 0x1bf05 + Cols Atom = 0x1c404 + Colspan Atom = 0x1c407 + Command Atom = 0x1d707 + Content Atom = 0x58b07 + Contenteditable Atom = 0x58b0f + Contextmenu Atom = 0x3800b + Controls Atom = 0x1de08 + Coords Atom = 0x1ea06 + Crossorigin Atom = 0x1fb0b + Data Atom = 0x4a504 + Datalist Atom = 0x4a508 + Datetime Atom = 0x2b808 + Dd Atom = 0x2d702 + Default Atom = 0x10a07 + Defer Atom = 0x5c705 + Del Atom = 0x45203 + Desc Atom = 0x56104 + Details Atom = 0x7207 + Dfn Atom = 0x8703 + Dialog Atom = 0xbb06 + Dir Atom = 0x9303 + Dirname Atom = 0x9307 + Disabled Atom = 0x16408 + Div Atom = 0x16b03 + Dl Atom = 0x5e602 + Download Atom = 0x46308 + Draggable Atom = 0x17a09 + Dropzone Atom = 0x40508 + Dt Atom = 0x64b02 + Em Atom = 0x6e02 + Embed Atom = 0x6e05 + Enctype Atom = 0x28d07 + Face Atom = 0x21e04 + Fieldset Atom = 0x22608 + Figcaption Atom = 0x22e0a + Figure Atom = 0x24806 + Font Atom = 0x3f04 + Footer Atom = 0xf606 + For Atom = 0x25403 + ForeignObject Atom = 0x2540d + Foreignobject Atom = 0x2610d + Form Atom = 0x26e04 + Formaction Atom = 0x26e0a + Formenctype Atom = 0x2890b + Formmethod Atom = 0x2a40a + Formnovalidate Atom = 0x2ae0e + Formtarget Atom = 0x2c00a + Frame Atom = 0x8b05 + Frameset Atom = 0x8b08 + H1 Atom = 0x15c02 + H2 Atom = 0x2de02 + H3 Atom = 0x30d02 + H4 Atom = 0x34502 + H5 Atom = 0x34f02 + H6 Atom = 0x64d02 + Head Atom = 0x33104 + Header Atom = 0x33106 + Headers Atom = 0x33107 + Height Atom = 0x5206 + Hgroup Atom = 0x2ca06 + Hidden Atom = 0x2d506 + High Atom = 0x2db04 + Hr Atom = 0x15702 + Href Atom = 0x2e004 + Hreflang Atom = 0x2e008 + Html Atom = 0x5604 + HttpEquiv Atom = 0x2e80a + I Atom = 0x601 + Icon Atom = 0x58a04 + Id Atom = 0x10902 + Iframe Atom = 0x2fc06 + Image Atom = 0x30205 + Img Atom = 0x30703 + Input Atom = 0x44b05 + Inputmode Atom = 0x44b09 + Ins Atom = 0x20403 + Integrity Atom = 0x23f09 + Is Atom = 0x16502 + Isindex Atom = 0x30f07 + Ismap Atom = 0x31605 + Itemid Atom = 0x38b06 + Itemprop Atom = 0x19d08 + Itemref Atom = 0x3cd07 + Itemscope Atom = 0x67109 + Itemtype Atom = 0x31f08 + Kbd Atom = 0xb903 + Keygen Atom = 0x3206 + Keytype Atom = 0xd607 + Kind Atom = 0x17704 + Label Atom = 0x5905 + Lang Atom = 0x2e404 + Legend Atom = 0x18106 + Li Atom = 0xb202 + Link Atom = 0x17404 + List Atom = 0x4a904 + Listing Atom = 0x4a907 + Loop Atom = 0x5d04 + Low Atom = 0xc303 + Main Atom = 0x1004 + Malignmark Atom = 0xb00a + Manifest Atom = 0x6d708 + Map Atom = 0x31803 + Mark Atom = 0xb604 + Marquee Atom = 0x32707 + Math Atom = 0x32e04 + Max Atom = 0x33d03 + Maxlength Atom = 0x33d09 + Media Atom = 0xe605 + Mediagroup Atom = 0xe60a + Menu Atom = 0x38704 + Menuitem Atom = 0x38708 + Meta Atom = 0x4b804 + Meter Atom = 0x9805 + Method Atom = 0x2a806 + Mglyph Atom = 0x30806 + Mi Atom = 0x34702 + Min Atom = 0x34703 + Minlength Atom = 0x34709 + Mn Atom = 0x2b102 + Mo Atom = 0xa402 + Ms Atom = 0x67402 + Mtext Atom = 0x35105 + Multiple Atom = 0x35f08 + Muted Atom = 0x36705 + Name Atom = 0x9604 + Nav Atom = 0x1303 + Nobr Atom = 0x3704 + Noembed Atom = 0x6c07 + Noframes Atom = 0x8908 + Nomodule Atom = 0xa208 + Nonce Atom = 0x1a605 + Noscript Atom = 0x21608 + Novalidate Atom = 0x2b20a + Object Atom = 0x26806 + Ol Atom = 0x13702 + Onabort Atom = 0x19507 + Onafterprint Atom = 0x2360c + Onautocomplete Atom = 0x2760e + Onautocompleteerror Atom = 0x27613 + Onauxclick Atom = 0x61f0a + Onbeforeprint Atom = 0x69e0d + Onbeforeunload Atom = 0x6e70e + Onblur Atom = 0x56d06 + Oncancel Atom = 0x11908 + Oncanplay Atom = 0x14d09 + Oncanplaythrough Atom = 0x14d10 + Onchange Atom = 0x41b08 + Onclick Atom = 0x2f507 + Onclose Atom = 0x36c07 + Oncontextmenu Atom = 0x37e0d + Oncopy Atom = 0x39106 + Oncuechange Atom = 0x3970b + Oncut Atom = 0x3a205 + Ondblclick Atom = 0x3a70a + Ondrag Atom = 0x3b106 + Ondragend Atom = 0x3b109 + Ondragenter Atom = 0x3ba0b + Ondragexit Atom = 0x3c50a + Ondragleave Atom = 0x3df0b + Ondragover Atom = 0x3ea0a + Ondragstart Atom = 0x3f40b + Ondrop Atom = 0x40306 + Ondurationchange Atom = 0x41310 + Onemptied Atom = 0x40a09 + Onended Atom = 0x42307 + Onerror Atom = 0x42a07 + Onfocus Atom = 0x43107 + Onhashchange Atom = 0x43d0c + Oninput Atom = 0x44907 + Oninvalid Atom = 0x45509 + Onkeydown Atom = 0x45e09 + Onkeypress Atom = 0x46b0a + Onkeyup Atom = 0x48007 + Onlanguagechange Atom = 0x48d10 + Onload Atom = 0x49d06 + Onloadeddata Atom = 0x49d0c + Onloadedmetadata Atom = 0x4b010 + Onloadend Atom = 0x4c609 + Onloadstart Atom = 0x4cf0b + Onmessage Atom = 0x4da09 + Onmessageerror Atom = 0x4da0e + Onmousedown Atom = 0x4e80b + Onmouseenter Atom = 0x4f30c + Onmouseleave Atom = 0x4ff0c + Onmousemove Atom = 0x50b0b + Onmouseout Atom = 0x5160a + Onmouseover Atom = 0x5230b + Onmouseup Atom = 0x52e09 + Onmousewheel Atom = 0x53c0c + Onoffline Atom = 0x54809 + Ononline Atom = 0x55108 + Onpagehide Atom = 0x5590a + Onpageshow Atom = 0x5730a + Onpaste Atom = 0x57f07 + Onpause Atom = 0x59a07 + Onplay Atom = 0x5a406 + Onplaying Atom = 0x5a409 + Onpopstate Atom = 0x5ad0a + Onprogress Atom = 0x5b70a + Onratechange Atom = 0x5cc0c + Onrejectionhandled Atom = 0x5d812 + Onreset Atom = 0x5ea07 + Onresize Atom = 0x5f108 + Onscroll Atom = 0x60008 + Onsecuritypolicyviolation Atom = 0x60819 + Onseeked Atom = 0x62908 + Onseeking Atom = 0x63109 + Onselect Atom = 0x63a08 + Onshow Atom = 0x64406 + Onsort Atom = 0x64f06 + Onstalled Atom = 0x65909 + Onstorage Atom = 0x66209 + Onsubmit Atom = 0x66b08 + Onsuspend Atom = 0x67b09 + Ontimeupdate Atom = 0x400c + Ontoggle Atom = 0x68408 + Onunhandledrejection Atom = 0x68c14 + Onunload Atom = 0x6ab08 + Onvolumechange Atom = 0x6b30e + Onwaiting Atom = 0x6c109 + Onwheel Atom = 0x6ca07 + Open Atom = 0x1a304 + Optgroup Atom = 0x5f08 + Optimum Atom = 0x6d107 + Option Atom = 0x6e306 + Output Atom = 0x51d06 + P Atom = 0xc01 + Param Atom = 0xc05 + Pattern Atom = 0x6607 + Picture Atom = 0x7b07 + Ping Atom = 0xef04 + Placeholder Atom = 0x1310b + Plaintext Atom = 0x1b209 + Playsinline Atom = 0x1400b + Poster Atom = 0x2cf06 + Pre Atom = 0x47003 + Preload Atom = 0x48607 + Progress Atom = 0x5b908 + Prompt Atom = 0x53606 + Public Atom = 0x58606 + Q Atom = 0xcf01 + Radiogroup Atom = 0x30a + Rb Atom = 0x3a02 + Readonly Atom = 0x35708 + Referrerpolicy Atom = 0x3d10e + Rel Atom = 0x48703 + Required Atom = 0x24c08 + Reversed Atom = 0x8008 + Rows Atom = 0x9c04 + Rowspan Atom = 0x9c07 + Rp Atom = 0x23c02 + Rt Atom = 0x19a02 + Rtc Atom = 0x19a03 + Ruby Atom = 0xfb04 + S Atom = 0x2501 + Samp Atom = 0x7804 + Sandbox Atom = 0x12907 + Scope Atom = 0x67505 + Scoped Atom = 0x67506 + Script Atom = 0x21806 + Seamless Atom = 0x37108 + Section Atom = 0x56807 + Select Atom = 0x63c06 + Selected Atom = 0x63c08 + Shape Atom = 0x1e505 + Size Atom = 0x5f504 + Sizes Atom = 0x5f505 + Slot Atom = 0x1ef04 + Small Atom = 0x20605 + Sortable Atom = 0x65108 + Sorted Atom = 0x33706 + Source Atom = 0x37806 + Spacer Atom = 0x43706 + Span Atom = 0x9f04 + Spellcheck Atom = 0x4740a + Src Atom = 0x5c003 + Srcdoc Atom = 0x5c006 + Srclang Atom = 0x5f907 + Srcset Atom = 0x6f906 + Start Atom = 0x3fa05 + Step Atom = 0x58304 + Strike Atom = 0xd206 + Strong Atom = 0x6dd06 + Style Atom = 0x6ff05 + Sub Atom = 0x66d03 + Summary Atom = 0x70407 + Sup Atom = 0x70b03 + Svg Atom = 0x70e03 + System Atom = 0x71106 + Tabindex Atom = 0x4be08 + Table Atom = 0x59505 + Target Atom = 0x2c406 + Tbody Atom = 0x2705 + Td Atom = 0x9202 + Template Atom = 0x71408 + Textarea Atom = 0x35208 + Tfoot Atom = 0xf505 + Th Atom = 0x15602 + Thead Atom = 0x33005 + Time Atom = 0x4204 + Title Atom = 0x11005 + Tr Atom = 0xcc02 + Track Atom = 0x1ba05 + Translate Atom = 0x1f209 + Tt Atom = 0x6802 + Type Atom = 0xd904 + Typemustmatch Atom = 0x2900d + U Atom = 0xb01 + Ul Atom = 0xa702 + Updateviacache Atom = 0x460e + Usemap Atom = 0x59e06 + Value Atom = 0x1505 + Var Atom = 0x16d03 + Video Atom = 0x2f105 + Wbr Atom = 0x57c03 + Width Atom = 0x64905 + Workertype Atom = 0x71c0a + Wrap Atom = 0x72604 + Xmp Atom = 0x12f03 +) + +const hash0 = 0x81cdf10e + +const maxAtomLen = 25 + +var table = [1 << 9]Atom{ + 0x1: 0xe60a, // mediagroup + 0x2: 0x2e404, // lang + 0x4: 0x2c09, // accesskey + 0x5: 0x8b08, // frameset + 0x7: 0x63a08, // onselect + 0x8: 0x71106, // system + 0xa: 0x64905, // width + 0xc: 0x2890b, // formenctype + 0xd: 0x13702, // ol + 0xe: 0x3970b, // oncuechange + 0x10: 0x14b03, // bdo + 0x11: 0x11505, // audio + 0x12: 0x17a09, // draggable + 0x14: 0x2f105, // video + 0x15: 0x2b102, // mn + 0x16: 0x38704, // menu + 0x17: 0x2cf06, // poster + 0x19: 0xf606, // footer + 0x1a: 0x2a806, // method + 0x1b: 0x2b808, // datetime + 0x1c: 0x19507, // onabort + 0x1d: 0x460e, // updateviacache + 0x1e: 0xff05, // async + 0x1f: 0x49d06, // onload + 0x21: 0x11908, // oncancel + 0x22: 0x62908, // onseeked + 0x23: 0x30205, // image + 0x24: 0x5d812, // onrejectionhandled + 0x26: 0x17404, // link + 0x27: 0x51d06, // output + 0x28: 0x33104, // head + 0x29: 0x4ff0c, // onmouseleave + 0x2a: 0x57f07, // onpaste + 0x2b: 0x5a409, // onplaying + 0x2c: 0x1c407, // colspan + 0x2f: 0x1bf05, // color + 0x30: 0x5f504, // size + 0x31: 0x2e80a, // http-equiv + 0x33: 0x601, // i + 0x34: 0x5590a, // onpagehide + 0x35: 0x68c14, // onunhandledrejection + 0x37: 0x42a07, // onerror + 0x3a: 0x3b08, // basefont + 0x3f: 0x1303, // nav + 0x40: 0x17704, // kind + 0x41: 0x35708, // readonly + 0x42: 0x30806, // mglyph + 0x44: 0xb202, // li + 0x46: 0x2d506, // hidden + 0x47: 0x70e03, // svg + 0x48: 0x58304, // step + 0x49: 0x23f09, // integrity + 0x4a: 0x58606, // public + 0x4c: 0x1ab03, // col + 0x4d: 0x1870a, // blockquote + 0x4e: 0x34f02, // h5 + 0x50: 0x5b908, // progress + 0x51: 0x5f505, // sizes + 0x52: 0x34502, // h4 + 0x56: 0x33005, // thead + 0x57: 0xd607, // keytype + 0x58: 0x5b70a, // onprogress + 0x59: 0x44b09, // inputmode + 0x5a: 0x3b109, // ondragend + 0x5d: 0x3a205, // oncut + 0x5e: 0x43706, // spacer + 0x5f: 0x1ab08, // colgroup + 0x62: 0x16502, // is + 0x65: 0x3c02, // as + 0x66: 0x54809, // onoffline + 0x67: 0x33706, // sorted + 0x69: 0x48d10, // onlanguagechange + 0x6c: 0x43d0c, // onhashchange + 0x6d: 0x9604, // name + 0x6e: 0xf505, // tfoot + 0x6f: 0x56104, // desc + 0x70: 0x33d03, // max + 0x72: 0x1ea06, // coords + 0x73: 0x30d02, // h3 + 0x74: 0x6e70e, // onbeforeunload + 0x75: 0x9c04, // rows + 0x76: 0x63c06, // select + 0x77: 0x9805, // meter + 0x78: 0x38b06, // itemid + 0x79: 0x53c0c, // onmousewheel + 0x7a: 0x5c006, // srcdoc + 0x7d: 0x1ba05, // track + 0x7f: 0x31f08, // itemtype + 0x82: 0xa402, // mo + 0x83: 0x41b08, // onchange + 0x84: 0x33107, // headers + 0x85: 0x5cc0c, // onratechange + 0x86: 0x60819, // onsecuritypolicyviolation + 0x88: 0x4a508, // datalist + 0x89: 0x4e80b, // onmousedown + 0x8a: 0x1ef04, // slot + 0x8b: 0x4b010, // onloadedmetadata + 0x8c: 0x1a06, // accept + 0x8d: 0x26806, // object + 0x91: 0x6b30e, // onvolumechange + 0x92: 0x2107, // charset + 0x93: 0x27613, // onautocompleteerror + 0x94: 0xc113, // allowpaymentrequest + 0x95: 0x2804, // body + 0x96: 0x10a07, // default + 0x97: 0x63c08, // selected + 0x98: 0x21e04, // face + 0x99: 0x1e505, // shape + 0x9b: 0x68408, // ontoggle + 0x9e: 0x64b02, // dt + 0x9f: 0xb604, // mark + 0xa1: 0xb01, // u + 0xa4: 0x6ab08, // onunload + 0xa5: 0x5d04, // loop + 0xa6: 0x16408, // disabled + 0xaa: 0x42307, // onended + 0xab: 0xb00a, // malignmark + 0xad: 0x67b09, // onsuspend + 0xae: 0x35105, // mtext + 0xaf: 0x64f06, // onsort + 0xb0: 0x19d08, // itemprop + 0xb3: 0x67109, // itemscope + 0xb4: 0x17305, // blink + 0xb6: 0x3b106, // ondrag + 0xb7: 0xa702, // ul + 0xb8: 0x26e04, // form + 0xb9: 0x12907, // sandbox + 0xba: 0x8b05, // frame + 0xbb: 0x1505, // value + 0xbc: 0x66209, // onstorage + 0xbf: 0xaa07, // acronym + 0xc0: 0x19a02, // rt + 0xc2: 0x202, // br + 0xc3: 0x22608, // fieldset + 0xc4: 0x2900d, // typemustmatch + 0xc5: 0xa208, // nomodule + 0xc6: 0x6c07, // noembed + 0xc7: 0x69e0d, // onbeforeprint + 0xc8: 0x19106, // button + 0xc9: 0x2f507, // onclick + 0xca: 0x70407, // summary + 0xcd: 0xfb04, // ruby + 0xce: 0x56405, // class + 0xcf: 0x3f40b, // ondragstart + 0xd0: 0x23107, // caption + 0xd4: 0xdd0e, // allowusermedia + 0xd5: 0x4cf0b, // onloadstart + 0xd9: 0x16b03, // div + 0xda: 0x4a904, // list + 0xdb: 0x32e04, // math + 0xdc: 0x44b05, // input + 0xdf: 0x3ea0a, // ondragover + 0xe0: 0x2de02, // h2 + 0xe2: 0x1b209, // plaintext + 0xe4: 0x4f30c, // onmouseenter + 0xe7: 0x47907, // checked + 0xe8: 0x47003, // pre + 0xea: 0x35f08, // multiple + 0xeb: 0xba03, // bdi + 0xec: 0x33d09, // maxlength + 0xed: 0xcf01, // q + 0xee: 0x61f0a, // onauxclick + 0xf0: 0x57c03, // wbr + 0xf2: 0x3b04, // base + 0xf3: 0x6e306, // option + 0xf5: 0x41310, // ondurationchange + 0xf7: 0x8908, // noframes + 0xf9: 0x40508, // dropzone + 0xfb: 0x67505, // scope + 0xfc: 0x8008, // reversed + 0xfd: 0x3ba0b, // ondragenter + 0xfe: 0x3fa05, // start + 0xff: 0x12f03, // xmp + 0x100: 0x5f907, // srclang + 0x101: 0x30703, // img + 0x104: 0x101, // b + 0x105: 0x25403, // for + 0x106: 0x10705, // aside + 0x107: 0x44907, // oninput + 0x108: 0x35604, // area + 0x109: 0x2a40a, // formmethod + 0x10a: 0x72604, // wrap + 0x10c: 0x23c02, // rp + 0x10d: 0x46b0a, // onkeypress + 0x10e: 0x6802, // tt + 0x110: 0x34702, // mi + 0x111: 0x36705, // muted + 0x112: 0xf303, // alt + 0x113: 0x5c504, // code + 0x114: 0x6e02, // em + 0x115: 0x3c50a, // ondragexit + 0x117: 0x9f04, // span + 0x119: 0x6d708, // manifest + 0x11a: 0x38708, // menuitem + 0x11b: 0x58b07, // content + 0x11d: 0x6c109, // onwaiting + 0x11f: 0x4c609, // onloadend + 0x121: 0x37e0d, // oncontextmenu + 0x123: 0x56d06, // onblur + 0x124: 0x3fc07, // article + 0x125: 0x9303, // dir + 0x126: 0xef04, // ping + 0x127: 0x24c08, // required + 0x128: 0x45509, // oninvalid + 0x129: 0xb105, // align + 0x12b: 0x58a04, // icon + 0x12c: 0x64d02, // h6 + 0x12d: 0x1c404, // cols + 0x12e: 0x22e0a, // figcaption + 0x12f: 0x45e09, // onkeydown + 0x130: 0x66b08, // onsubmit + 0x131: 0x14d09, // oncanplay + 0x132: 0x70b03, // sup + 0x133: 0xc01, // p + 0x135: 0x40a09, // onemptied + 0x136: 0x39106, // oncopy + 0x137: 0x19c04, // cite + 0x138: 0x3a70a, // ondblclick + 0x13a: 0x50b0b, // onmousemove + 0x13c: 0x66d03, // sub + 0x13d: 0x48703, // rel + 0x13e: 0x5f08, // optgroup + 0x142: 0x9c07, // rowspan + 0x143: 0x37806, // source + 0x144: 0x21608, // noscript + 0x145: 0x1a304, // open + 0x146: 0x20403, // ins + 0x147: 0x2540d, // foreignObject + 0x148: 0x5ad0a, // onpopstate + 0x14a: 0x28d07, // enctype + 0x14b: 0x2760e, // onautocomplete + 0x14c: 0x35208, // textarea + 0x14e: 0x2780c, // autocomplete + 0x14f: 0x15702, // hr + 0x150: 0x1de08, // controls + 0x151: 0x10902, // id + 0x153: 0x2360c, // onafterprint + 0x155: 0x2610d, // foreignobject + 0x156: 0x32707, // marquee + 0x157: 0x59a07, // onpause + 0x158: 0x5e602, // dl + 0x159: 0x5206, // height + 0x15a: 0x34703, // min + 0x15b: 0x9307, // dirname + 0x15c: 0x1f209, // translate + 0x15d: 0x5604, // html + 0x15e: 0x34709, // minlength + 0x15f: 0x48607, // preload + 0x160: 0x71408, // template + 0x161: 0x3df0b, // ondragleave + 0x162: 0x3a02, // rb + 0x164: 0x5c003, // src + 0x165: 0x6dd06, // strong + 0x167: 0x7804, // samp + 0x168: 0x6f307, // address + 0x169: 0x55108, // ononline + 0x16b: 0x1310b, // placeholder + 0x16c: 0x2c406, // target + 0x16d: 0x20605, // small + 0x16e: 0x6ca07, // onwheel + 0x16f: 0x1c90a, // annotation + 0x170: 0x4740a, // spellcheck + 0x171: 0x7207, // details + 0x172: 0x10306, // canvas + 0x173: 0x12109, // autofocus + 0x174: 0xc05, // param + 0x176: 0x46308, // download + 0x177: 0x45203, // del + 0x178: 0x36c07, // onclose + 0x179: 0xb903, // kbd + 0x17a: 0x31906, // applet + 0x17b: 0x2e004, // href + 0x17c: 0x5f108, // onresize + 0x17e: 0x49d0c, // onloadeddata + 0x180: 0xcc02, // tr + 0x181: 0x2c00a, // formtarget + 0x182: 0x11005, // title + 0x183: 0x6ff05, // style + 0x184: 0xd206, // strike + 0x185: 0x59e06, // usemap + 0x186: 0x2fc06, // iframe + 0x187: 0x1004, // main + 0x189: 0x7b07, // picture + 0x18c: 0x31605, // ismap + 0x18e: 0x4a504, // data + 0x18f: 0x5905, // label + 0x191: 0x3d10e, // referrerpolicy + 0x192: 0x15602, // th + 0x194: 0x53606, // prompt + 0x195: 0x56807, // section + 0x197: 0x6d107, // optimum + 0x198: 0x2db04, // high + 0x199: 0x15c02, // h1 + 0x19a: 0x65909, // onstalled + 0x19b: 0x16d03, // var + 0x19c: 0x4204, // time + 0x19e: 0x67402, // ms + 0x19f: 0x33106, // header + 0x1a0: 0x4da09, // onmessage + 0x1a1: 0x1a605, // nonce + 0x1a2: 0x26e0a, // formaction + 0x1a3: 0x22006, // center + 0x1a4: 0x3704, // nobr + 0x1a5: 0x59505, // table + 0x1a6: 0x4a907, // listing + 0x1a7: 0x18106, // legend + 0x1a9: 0x29b09, // challenge + 0x1aa: 0x24806, // figure + 0x1ab: 0xe605, // media + 0x1ae: 0xd904, // type + 0x1af: 0x3f04, // font + 0x1b0: 0x4da0e, // onmessageerror + 0x1b1: 0x37108, // seamless + 0x1b2: 0x8703, // dfn + 0x1b3: 0x5c705, // defer + 0x1b4: 0xc303, // low + 0x1b5: 0x19a03, // rtc + 0x1b6: 0x5230b, // onmouseover + 0x1b7: 0x2b20a, // novalidate + 0x1b8: 0x71c0a, // workertype + 0x1ba: 0x3cd07, // itemref + 0x1bd: 0x1, // a + 0x1be: 0x31803, // map + 0x1bf: 0x400c, // ontimeupdate + 0x1c0: 0x15e07, // bgsound + 0x1c1: 0x3206, // keygen + 0x1c2: 0x2705, // tbody + 0x1c5: 0x64406, // onshow + 0x1c7: 0x2501, // s + 0x1c8: 0x6607, // pattern + 0x1cc: 0x14d10, // oncanplaythrough + 0x1ce: 0x2d702, // dd + 0x1cf: 0x6f906, // srcset + 0x1d0: 0x17003, // big + 0x1d2: 0x65108, // sortable + 0x1d3: 0x48007, // onkeyup + 0x1d5: 0x5a406, // onplay + 0x1d7: 0x4b804, // meta + 0x1d8: 0x40306, // ondrop + 0x1da: 0x60008, // onscroll + 0x1db: 0x1fb0b, // crossorigin + 0x1dc: 0x5730a, // onpageshow + 0x1dd: 0x4, // abbr + 0x1de: 0x9202, // td + 0x1df: 0x58b0f, // contenteditable + 0x1e0: 0x27206, // action + 0x1e1: 0x1400b, // playsinline + 0x1e2: 0x43107, // onfocus + 0x1e3: 0x2e008, // hreflang + 0x1e5: 0x5160a, // onmouseout + 0x1e6: 0x5ea07, // onreset + 0x1e7: 0x13c08, // autoplay + 0x1e8: 0x63109, // onseeking + 0x1ea: 0x67506, // scoped + 0x1ec: 0x30a, // radiogroup + 0x1ee: 0x3800b, // contextmenu + 0x1ef: 0x52e09, // onmouseup + 0x1f1: 0x2ca06, // hgroup + 0x1f2: 0x2080f, // allowfullscreen + 0x1f3: 0x4be08, // tabindex + 0x1f6: 0x30f07, // isindex + 0x1f7: 0x1a0e, // accept-charset + 0x1f8: 0x2ae0e, // formnovalidate + 0x1fb: 0x1c90e, // annotation-xml + 0x1fc: 0x6e05, // embed + 0x1fd: 0x21806, // script + 0x1fe: 0xbb06, // dialog + 0x1ff: 0x1d707, // command +} + +const atomText = "abbradiogrouparamainavalueaccept-charsetbodyaccesskeygenobrb" + + "asefontimeupdateviacacheightmlabelooptgroupatternoembedetail" + + "sampictureversedfnoframesetdirnameterowspanomoduleacronymali" + + "gnmarkbdialogallowpaymentrequestrikeytypeallowusermediagroup" + + "ingaltfooterubyasyncanvasidefaultitleaudioncancelautofocusan" + + "dboxmplaceholderautoplaysinlinebdoncanplaythrough1bgsoundisa" + + "bledivarbigblinkindraggablegendblockquotebuttonabortcitempro" + + "penoncecolgrouplaintextrackcolorcolspannotation-xmlcommandco" + + "ntrolshapecoordslotranslatecrossoriginsmallowfullscreenoscri" + + "ptfacenterfieldsetfigcaptionafterprintegrityfigurequiredfore" + + "ignObjectforeignobjectformactionautocompleteerrorformenctype" + + "mustmatchallengeformmethodformnovalidatetimeformtargethgroup" + + "osterhiddenhigh2hreflanghttp-equivideonclickiframeimageimgly" + + "ph3isindexismappletitemtypemarqueematheadersortedmaxlength4m" + + "inlength5mtextareadonlymultiplemutedoncloseamlessourceoncont" + + "extmenuitemidoncopyoncuechangeoncutondblclickondragendondrag" + + "enterondragexitemreferrerpolicyondragleaveondragoverondragst" + + "articleondropzonemptiedondurationchangeonendedonerroronfocus" + + "paceronhashchangeoninputmodeloninvalidonkeydownloadonkeypres" + + "spellcheckedonkeyupreloadonlanguagechangeonloadeddatalisting" + + "onloadedmetadatabindexonloadendonloadstartonmessageerroronmo" + + "usedownonmouseenteronmouseleaveonmousemoveonmouseoutputonmou" + + "seoveronmouseupromptonmousewheelonofflineononlineonpagehides" + + "classectionbluronpageshowbronpastepublicontenteditableonpaus" + + "emaponplayingonpopstateonprogressrcdocodeferonratechangeonre" + + "jectionhandledonresetonresizesrclangonscrollonsecuritypolicy" + + "violationauxclickonseekedonseekingonselectedonshowidth6onsor" + + "tableonstalledonstorageonsubmitemscopedonsuspendontoggleonun" + + "handledrejectionbeforeprintonunloadonvolumechangeonwaitingon" + + "wheeloptimumanifestrongoptionbeforeunloaddressrcsetstylesumm" + + "arysupsvgsystemplateworkertypewrap" diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/charset/charset.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/charset/charset.go new file mode 100644 index 000000000..13bed1599 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/charset/charset.go @@ -0,0 +1,257 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package charset provides common text encodings for HTML documents. +// +// The mapping from encoding labels to encodings is defined at +// https://encoding.spec.whatwg.org/. +package charset // import "golang.org/x/net/html/charset" + +import ( + "bytes" + "fmt" + "io" + "mime" + "strings" + "unicode/utf8" + + "golang.org/x/net/html" + "golang.org/x/text/encoding" + "golang.org/x/text/encoding/charmap" + "golang.org/x/text/encoding/htmlindex" + "golang.org/x/text/transform" +) + +// Lookup returns the encoding with the specified label, and its canonical +// name. It returns nil and the empty string if label is not one of the +// standard encodings for HTML. Matching is case-insensitive and ignores +// leading and trailing whitespace. Encoders will use HTML escape sequences for +// runes that are not supported by the character set. +func Lookup(label string) (e encoding.Encoding, name string) { + e, err := htmlindex.Get(label) + if err != nil { + return nil, "" + } + name, _ = htmlindex.Name(e) + return &htmlEncoding{e}, name +} + +type htmlEncoding struct{ encoding.Encoding } + +func (h *htmlEncoding) NewEncoder() *encoding.Encoder { + // HTML requires a non-terminating legacy encoder. We use HTML escapes to + // substitute unsupported code points. + return encoding.HTMLEscapeUnsupported(h.Encoding.NewEncoder()) +} + +// DetermineEncoding determines the encoding of an HTML document by examining +// up to the first 1024 bytes of content and the declared Content-Type. +// +// See http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding +func DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool) { + if len(content) > 1024 { + content = content[:1024] + } + + for _, b := range boms { + if bytes.HasPrefix(content, b.bom) { + e, name = Lookup(b.enc) + return e, name, true + } + } + + if _, params, err := mime.ParseMediaType(contentType); err == nil { + if cs, ok := params["charset"]; ok { + if e, name = Lookup(cs); e != nil { + return e, name, true + } + } + } + + if len(content) > 0 { + e, name = prescan(content) + if e != nil { + return e, name, false + } + } + + // Try to detect UTF-8. + // First eliminate any partial rune at the end. + for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- { + b := content[i] + if b < 0x80 { + break + } + if utf8.RuneStart(b) { + content = content[:i] + break + } + } + hasHighBit := false + for _, c := range content { + if c >= 0x80 { + hasHighBit = true + break + } + } + if hasHighBit && utf8.Valid(content) { + return encoding.Nop, "utf-8", false + } + + // TODO: change default depending on user's locale? + return charmap.Windows1252, "windows-1252", false +} + +// NewReader returns an io.Reader that converts the content of r to UTF-8. +// It calls DetermineEncoding to find out what r's encoding is. +func NewReader(r io.Reader, contentType string) (io.Reader, error) { + preview := make([]byte, 1024) + n, err := io.ReadFull(r, preview) + switch { + case err == io.ErrUnexpectedEOF: + preview = preview[:n] + r = bytes.NewReader(preview) + case err != nil: + return nil, err + default: + r = io.MultiReader(bytes.NewReader(preview), r) + } + + if e, _, _ := DetermineEncoding(preview, contentType); e != encoding.Nop { + r = transform.NewReader(r, e.NewDecoder()) + } + return r, nil +} + +// NewReaderLabel returns a reader that converts from the specified charset to +// UTF-8. It uses Lookup to find the encoding that corresponds to label, and +// returns an error if Lookup returns nil. It is suitable for use as +// encoding/xml.Decoder's CharsetReader function. +func NewReaderLabel(label string, input io.Reader) (io.Reader, error) { + e, _ := Lookup(label) + if e == nil { + return nil, fmt.Errorf("unsupported charset: %q", label) + } + return transform.NewReader(input, e.NewDecoder()), nil +} + +func prescan(content []byte) (e encoding.Encoding, name string) { + z := html.NewTokenizer(bytes.NewReader(content)) + for { + switch z.Next() { + case html.ErrorToken: + return nil, "" + + case html.StartTagToken, html.SelfClosingTagToken: + tagName, hasAttr := z.TagName() + if !bytes.Equal(tagName, []byte("meta")) { + continue + } + attrList := make(map[string]bool) + gotPragma := false + + const ( + dontKnow = iota + doNeedPragma + doNotNeedPragma + ) + needPragma := dontKnow + + name = "" + e = nil + for hasAttr { + var key, val []byte + key, val, hasAttr = z.TagAttr() + ks := string(key) + if attrList[ks] { + continue + } + attrList[ks] = true + for i, c := range val { + if 'A' <= c && c <= 'Z' { + val[i] = c + 0x20 + } + } + + switch ks { + case "http-equiv": + if bytes.Equal(val, []byte("content-type")) { + gotPragma = true + } + + case "content": + if e == nil { + name = fromMetaElement(string(val)) + if name != "" { + e, name = Lookup(name) + if e != nil { + needPragma = doNeedPragma + } + } + } + + case "charset": + e, name = Lookup(string(val)) + needPragma = doNotNeedPragma + } + } + + if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma { + continue + } + + if strings.HasPrefix(name, "utf-16") { + name = "utf-8" + e = encoding.Nop + } + + if e != nil { + return e, name + } + } + } +} + +func fromMetaElement(s string) string { + for s != "" { + csLoc := strings.Index(s, "charset") + if csLoc == -1 { + return "" + } + s = s[csLoc+len("charset"):] + s = strings.TrimLeft(s, " \t\n\f\r") + if !strings.HasPrefix(s, "=") { + continue + } + s = s[1:] + s = strings.TrimLeft(s, " \t\n\f\r") + if s == "" { + return "" + } + if q := s[0]; q == '"' || q == '\'' { + s = s[1:] + closeQuote := strings.IndexRune(s, rune(q)) + if closeQuote == -1 { + return "" + } + return s[:closeQuote] + } + + end := strings.IndexAny(s, "; \t\n\f\r") + if end == -1 { + end = len(s) + } + return s[:end] + } + return "" +} + +var boms = []struct { + bom []byte + enc string +}{ + {[]byte{0xfe, 0xff}, "utf-16be"}, + {[]byte{0xff, 0xfe}, "utf-16le"}, + {[]byte{0xef, 0xbb, 0xbf}, "utf-8"}, +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/const.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/const.go new file mode 100644 index 000000000..73804d347 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/const.go @@ -0,0 +1,111 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +// Section 12.2.4.2 of the HTML5 specification says "The following elements +// have varying levels of special parsing rules". +// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements +var isSpecialElementMap = map[string]bool{ + "address": true, + "applet": true, + "area": true, + "article": true, + "aside": true, + "base": true, + "basefont": true, + "bgsound": true, + "blockquote": true, + "body": true, + "br": true, + "button": true, + "caption": true, + "center": true, + "col": true, + "colgroup": true, + "dd": true, + "details": true, + "dir": true, + "div": true, + "dl": true, + "dt": true, + "embed": true, + "fieldset": true, + "figcaption": true, + "figure": true, + "footer": true, + "form": true, + "frame": true, + "frameset": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "header": true, + "hgroup": true, + "hr": true, + "html": true, + "iframe": true, + "img": true, + "input": true, + "keygen": true, + "li": true, + "link": true, + "listing": true, + "main": true, + "marquee": true, + "menu": true, + "meta": true, + "nav": true, + "noembed": true, + "noframes": true, + "noscript": true, + "object": true, + "ol": true, + "p": true, + "param": true, + "plaintext": true, + "pre": true, + "script": true, + "section": true, + "select": true, + "source": true, + "style": true, + "summary": true, + "table": true, + "tbody": true, + "td": true, + "template": true, + "textarea": true, + "tfoot": true, + "th": true, + "thead": true, + "title": true, + "tr": true, + "track": true, + "ul": true, + "wbr": true, + "xmp": true, +} + +func isSpecialElement(element *Node) bool { + switch element.Namespace { + case "", "html": + return isSpecialElementMap[element.Data] + case "math": + switch element.Data { + case "mi", "mo", "mn", "ms", "mtext", "annotation-xml": + return true + } + case "svg": + switch element.Data { + case "foreignObject", "desc", "title": + return true + } + } + return false +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doc.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doc.go new file mode 100644 index 000000000..822ed42a0 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doc.go @@ -0,0 +1,106 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package html implements an HTML5-compliant tokenizer and parser. + +Tokenization is done by creating a Tokenizer for an io.Reader r. It is the +caller's responsibility to ensure that r provides UTF-8 encoded HTML. + + z := html.NewTokenizer(r) + +Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(), +which parses the next token and returns its type, or an error: + + for { + tt := z.Next() + if tt == html.ErrorToken { + // ... + return ... + } + // Process the current token. + } + +There are two APIs for retrieving the current token. The high-level API is to +call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs +allow optionally calling Raw after Next but before Token, Text, TagName, or +TagAttr. In EBNF notation, the valid call sequence per token is: + + Next {Raw} [ Token | Text | TagName {TagAttr} ] + +Token returns an independent data structure that completely describes a token. +Entities (such as "<") are unescaped, tag names and attribute keys are +lower-cased, and attributes are collected into a []Attribute. For example: + + for { + if z.Next() == html.ErrorToken { + // Returning io.EOF indicates success. + return z.Err() + } + emitToken(z.Token()) + } + +The low-level API performs fewer allocations and copies, but the contents of +the []byte values returned by Text, TagName and TagAttr may change on the next +call to Next. For example, to extract an HTML page's anchor text: + + depth := 0 + for { + tt := z.Next() + switch tt { + case html.ErrorToken: + return z.Err() + case html.TextToken: + if depth > 0 { + // emitBytes should copy the []byte it receives, + // if it doesn't process it immediately. + emitBytes(z.Text()) + } + case html.StartTagToken, html.EndTagToken: + tn, _ := z.TagName() + if len(tn) == 1 && tn[0] == 'a' { + if tt == html.StartTagToken { + depth++ + } else { + depth-- + } + } + } + } + +Parsing is done by calling Parse with an io.Reader, which returns the root of +the parse tree (the document element) as a *Node. It is the caller's +responsibility to ensure that the Reader provides UTF-8 encoded HTML. For +example, to process each anchor node in depth-first order: + + doc, err := html.Parse(r) + if err != nil { + // ... + } + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "a" { + // Do something with n... + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + f(doc) + +The relevant specifications include: +https://html.spec.whatwg.org/multipage/syntax.html and +https://html.spec.whatwg.org/multipage/syntax.html#tokenization +*/ +package html // import "golang.org/x/net/html" + +// The tokenization algorithm implemented by this package is not a line-by-line +// transliteration of the relatively verbose state-machine in the WHATWG +// specification. A more direct approach is used instead, where the program +// counter implies the state, such as whether it is tokenizing a tag or a text +// node. Specification compliance is verified by checking expected and actual +// outputs over a test suite rather than aiming for algorithmic fidelity. + +// TODO(nigeltao): Does a DOM API belong in this package or a separate one? +// TODO(nigeltao): How does parsing interact with a JavaScript engine? diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doctype.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doctype.go new file mode 100644 index 000000000..c484e5a94 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/doctype.go @@ -0,0 +1,156 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "strings" +) + +// parseDoctype parses the data from a DoctypeToken into a name, +// public identifier, and system identifier. It returns a Node whose Type +// is DoctypeNode, whose Data is the name, and which has attributes +// named "system" and "public" for the two identifiers if they were present. +// quirks is whether the document should be parsed in "quirks mode". +func parseDoctype(s string) (n *Node, quirks bool) { + n = &Node{Type: DoctypeNode} + + // Find the name. + space := strings.IndexAny(s, whitespace) + if space == -1 { + space = len(s) + } + n.Data = s[:space] + // The comparison to "html" is case-sensitive. + if n.Data != "html" { + quirks = true + } + n.Data = strings.ToLower(n.Data) + s = strings.TrimLeft(s[space:], whitespace) + + if len(s) < 6 { + // It can't start with "PUBLIC" or "SYSTEM". + // Ignore the rest of the string. + return n, quirks || s != "" + } + + key := strings.ToLower(s[:6]) + s = s[6:] + for key == "public" || key == "system" { + s = strings.TrimLeft(s, whitespace) + if s == "" { + break + } + quote := s[0] + if quote != '"' && quote != '\'' { + break + } + s = s[1:] + q := strings.IndexRune(s, rune(quote)) + var id string + if q == -1 { + id = s + s = "" + } else { + id = s[:q] + s = s[q+1:] + } + n.Attr = append(n.Attr, Attribute{Key: key, Val: id}) + if key == "public" { + key = "system" + } else { + key = "" + } + } + + if key != "" || s != "" { + quirks = true + } else if len(n.Attr) > 0 { + if n.Attr[0].Key == "public" { + public := strings.ToLower(n.Attr[0].Val) + switch public { + case "-//w3o//dtd w3 html strict 3.0//en//", "-/w3d/dtd html 4.0 transitional/en", "html": + quirks = true + default: + for _, q := range quirkyIDs { + if strings.HasPrefix(public, q) { + quirks = true + break + } + } + } + // The following two public IDs only cause quirks mode if there is no system ID. + if len(n.Attr) == 1 && (strings.HasPrefix(public, "-//w3c//dtd html 4.01 frameset//") || + strings.HasPrefix(public, "-//w3c//dtd html 4.01 transitional//")) { + quirks = true + } + } + if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" && + strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" { + quirks = true + } + } + + return n, quirks +} + +// quirkyIDs is a list of public doctype identifiers that cause a document +// to be interpreted in quirks mode. The identifiers should be in lower case. +var quirkyIDs = []string{ + "+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//", +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/entity.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/entity.go new file mode 100644 index 000000000..b628880a0 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/entity.go @@ -0,0 +1,2253 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +// All entities that do not end with ';' are 6 or fewer bytes long. +const longestEntityWithoutSemicolon = 6 + +// entity is a map from HTML entity names to their values. The semicolon matters: +// https://html.spec.whatwg.org/multipage/syntax.html#named-character-references +// lists both "amp" and "amp;" as two separate entries. +// +// Note that the HTML5 list is larger than the HTML4 list at +// http://www.w3.org/TR/html4/sgml/entities.html +var entity = map[string]rune{ + "AElig;": '\U000000C6', + "AMP;": '\U00000026', + "Aacute;": '\U000000C1', + "Abreve;": '\U00000102', + "Acirc;": '\U000000C2', + "Acy;": '\U00000410', + "Afr;": '\U0001D504', + "Agrave;": '\U000000C0', + "Alpha;": '\U00000391', + "Amacr;": '\U00000100', + "And;": '\U00002A53', + "Aogon;": '\U00000104', + "Aopf;": '\U0001D538', + "ApplyFunction;": '\U00002061', + "Aring;": '\U000000C5', + "Ascr;": '\U0001D49C', + "Assign;": '\U00002254', + "Atilde;": '\U000000C3', + "Auml;": '\U000000C4', + "Backslash;": '\U00002216', + "Barv;": '\U00002AE7', + "Barwed;": '\U00002306', + "Bcy;": '\U00000411', + "Because;": '\U00002235', + "Bernoullis;": '\U0000212C', + "Beta;": '\U00000392', + "Bfr;": '\U0001D505', + "Bopf;": '\U0001D539', + "Breve;": '\U000002D8', + "Bscr;": '\U0000212C', + "Bumpeq;": '\U0000224E', + "CHcy;": '\U00000427', + "COPY;": '\U000000A9', + "Cacute;": '\U00000106', + "Cap;": '\U000022D2', + "CapitalDifferentialD;": '\U00002145', + "Cayleys;": '\U0000212D', + "Ccaron;": '\U0000010C', + "Ccedil;": '\U000000C7', + "Ccirc;": '\U00000108', + "Cconint;": '\U00002230', + "Cdot;": '\U0000010A', + "Cedilla;": '\U000000B8', + "CenterDot;": '\U000000B7', + "Cfr;": '\U0000212D', + "Chi;": '\U000003A7', + "CircleDot;": '\U00002299', + "CircleMinus;": '\U00002296', + "CirclePlus;": '\U00002295', + "CircleTimes;": '\U00002297', + "ClockwiseContourIntegral;": '\U00002232', + "CloseCurlyDoubleQuote;": '\U0000201D', + "CloseCurlyQuote;": '\U00002019', + "Colon;": '\U00002237', + "Colone;": '\U00002A74', + "Congruent;": '\U00002261', + "Conint;": '\U0000222F', + "ContourIntegral;": '\U0000222E', + "Copf;": '\U00002102', + "Coproduct;": '\U00002210', + "CounterClockwiseContourIntegral;": '\U00002233', + "Cross;": '\U00002A2F', + "Cscr;": '\U0001D49E', + "Cup;": '\U000022D3', + "CupCap;": '\U0000224D', + "DD;": '\U00002145', + "DDotrahd;": '\U00002911', + "DJcy;": '\U00000402', + "DScy;": '\U00000405', + "DZcy;": '\U0000040F', + "Dagger;": '\U00002021', + "Darr;": '\U000021A1', + "Dashv;": '\U00002AE4', + "Dcaron;": '\U0000010E', + "Dcy;": '\U00000414', + "Del;": '\U00002207', + "Delta;": '\U00000394', + "Dfr;": '\U0001D507', + "DiacriticalAcute;": '\U000000B4', + "DiacriticalDot;": '\U000002D9', + "DiacriticalDoubleAcute;": '\U000002DD', + "DiacriticalGrave;": '\U00000060', + "DiacriticalTilde;": '\U000002DC', + "Diamond;": '\U000022C4', + "DifferentialD;": '\U00002146', + "Dopf;": '\U0001D53B', + "Dot;": '\U000000A8', + "DotDot;": '\U000020DC', + "DotEqual;": '\U00002250', + "DoubleContourIntegral;": '\U0000222F', + "DoubleDot;": '\U000000A8', + "DoubleDownArrow;": '\U000021D3', + "DoubleLeftArrow;": '\U000021D0', + "DoubleLeftRightArrow;": '\U000021D4', + "DoubleLeftTee;": '\U00002AE4', + "DoubleLongLeftArrow;": '\U000027F8', + "DoubleLongLeftRightArrow;": '\U000027FA', + "DoubleLongRightArrow;": '\U000027F9', + "DoubleRightArrow;": '\U000021D2', + "DoubleRightTee;": '\U000022A8', + "DoubleUpArrow;": '\U000021D1', + "DoubleUpDownArrow;": '\U000021D5', + "DoubleVerticalBar;": '\U00002225', + "DownArrow;": '\U00002193', + "DownArrowBar;": '\U00002913', + "DownArrowUpArrow;": '\U000021F5', + "DownBreve;": '\U00000311', + "DownLeftRightVector;": '\U00002950', + "DownLeftTeeVector;": '\U0000295E', + "DownLeftVector;": '\U000021BD', + "DownLeftVectorBar;": '\U00002956', + "DownRightTeeVector;": '\U0000295F', + "DownRightVector;": '\U000021C1', + "DownRightVectorBar;": '\U00002957', + "DownTee;": '\U000022A4', + "DownTeeArrow;": '\U000021A7', + "Downarrow;": '\U000021D3', + "Dscr;": '\U0001D49F', + "Dstrok;": '\U00000110', + "ENG;": '\U0000014A', + "ETH;": '\U000000D0', + "Eacute;": '\U000000C9', + "Ecaron;": '\U0000011A', + "Ecirc;": '\U000000CA', + "Ecy;": '\U0000042D', + "Edot;": '\U00000116', + "Efr;": '\U0001D508', + "Egrave;": '\U000000C8', + "Element;": '\U00002208', + "Emacr;": '\U00000112', + "EmptySmallSquare;": '\U000025FB', + "EmptyVerySmallSquare;": '\U000025AB', + "Eogon;": '\U00000118', + "Eopf;": '\U0001D53C', + "Epsilon;": '\U00000395', + "Equal;": '\U00002A75', + "EqualTilde;": '\U00002242', + "Equilibrium;": '\U000021CC', + "Escr;": '\U00002130', + "Esim;": '\U00002A73', + "Eta;": '\U00000397', + "Euml;": '\U000000CB', + "Exists;": '\U00002203', + "ExponentialE;": '\U00002147', + "Fcy;": '\U00000424', + "Ffr;": '\U0001D509', + "FilledSmallSquare;": '\U000025FC', + "FilledVerySmallSquare;": '\U000025AA', + "Fopf;": '\U0001D53D', + "ForAll;": '\U00002200', + "Fouriertrf;": '\U00002131', + "Fscr;": '\U00002131', + "GJcy;": '\U00000403', + "GT;": '\U0000003E', + "Gamma;": '\U00000393', + "Gammad;": '\U000003DC', + "Gbreve;": '\U0000011E', + "Gcedil;": '\U00000122', + "Gcirc;": '\U0000011C', + "Gcy;": '\U00000413', + "Gdot;": '\U00000120', + "Gfr;": '\U0001D50A', + "Gg;": '\U000022D9', + "Gopf;": '\U0001D53E', + "GreaterEqual;": '\U00002265', + "GreaterEqualLess;": '\U000022DB', + "GreaterFullEqual;": '\U00002267', + "GreaterGreater;": '\U00002AA2', + "GreaterLess;": '\U00002277', + "GreaterSlantEqual;": '\U00002A7E', + "GreaterTilde;": '\U00002273', + "Gscr;": '\U0001D4A2', + "Gt;": '\U0000226B', + "HARDcy;": '\U0000042A', + "Hacek;": '\U000002C7', + "Hat;": '\U0000005E', + "Hcirc;": '\U00000124', + "Hfr;": '\U0000210C', + "HilbertSpace;": '\U0000210B', + "Hopf;": '\U0000210D', + "HorizontalLine;": '\U00002500', + "Hscr;": '\U0000210B', + "Hstrok;": '\U00000126', + "HumpDownHump;": '\U0000224E', + "HumpEqual;": '\U0000224F', + "IEcy;": '\U00000415', + "IJlig;": '\U00000132', + "IOcy;": '\U00000401', + "Iacute;": '\U000000CD', + "Icirc;": '\U000000CE', + "Icy;": '\U00000418', + "Idot;": '\U00000130', + "Ifr;": '\U00002111', + "Igrave;": '\U000000CC', + "Im;": '\U00002111', + "Imacr;": '\U0000012A', + "ImaginaryI;": '\U00002148', + "Implies;": '\U000021D2', + "Int;": '\U0000222C', + "Integral;": '\U0000222B', + "Intersection;": '\U000022C2', + "InvisibleComma;": '\U00002063', + "InvisibleTimes;": '\U00002062', + "Iogon;": '\U0000012E', + "Iopf;": '\U0001D540', + "Iota;": '\U00000399', + "Iscr;": '\U00002110', + "Itilde;": '\U00000128', + "Iukcy;": '\U00000406', + "Iuml;": '\U000000CF', + "Jcirc;": '\U00000134', + "Jcy;": '\U00000419', + "Jfr;": '\U0001D50D', + "Jopf;": '\U0001D541', + "Jscr;": '\U0001D4A5', + "Jsercy;": '\U00000408', + "Jukcy;": '\U00000404', + "KHcy;": '\U00000425', + "KJcy;": '\U0000040C', + "Kappa;": '\U0000039A', + "Kcedil;": '\U00000136', + "Kcy;": '\U0000041A', + "Kfr;": '\U0001D50E', + "Kopf;": '\U0001D542', + "Kscr;": '\U0001D4A6', + "LJcy;": '\U00000409', + "LT;": '\U0000003C', + "Lacute;": '\U00000139', + "Lambda;": '\U0000039B', + "Lang;": '\U000027EA', + "Laplacetrf;": '\U00002112', + "Larr;": '\U0000219E', + "Lcaron;": '\U0000013D', + "Lcedil;": '\U0000013B', + "Lcy;": '\U0000041B', + "LeftAngleBracket;": '\U000027E8', + "LeftArrow;": '\U00002190', + "LeftArrowBar;": '\U000021E4', + "LeftArrowRightArrow;": '\U000021C6', + "LeftCeiling;": '\U00002308', + "LeftDoubleBracket;": '\U000027E6', + "LeftDownTeeVector;": '\U00002961', + "LeftDownVector;": '\U000021C3', + "LeftDownVectorBar;": '\U00002959', + "LeftFloor;": '\U0000230A', + "LeftRightArrow;": '\U00002194', + "LeftRightVector;": '\U0000294E', + "LeftTee;": '\U000022A3', + "LeftTeeArrow;": '\U000021A4', + "LeftTeeVector;": '\U0000295A', + "LeftTriangle;": '\U000022B2', + "LeftTriangleBar;": '\U000029CF', + "LeftTriangleEqual;": '\U000022B4', + "LeftUpDownVector;": '\U00002951', + "LeftUpTeeVector;": '\U00002960', + "LeftUpVector;": '\U000021BF', + "LeftUpVectorBar;": '\U00002958', + "LeftVector;": '\U000021BC', + "LeftVectorBar;": '\U00002952', + "Leftarrow;": '\U000021D0', + "Leftrightarrow;": '\U000021D4', + "LessEqualGreater;": '\U000022DA', + "LessFullEqual;": '\U00002266', + "LessGreater;": '\U00002276', + "LessLess;": '\U00002AA1', + "LessSlantEqual;": '\U00002A7D', + "LessTilde;": '\U00002272', + "Lfr;": '\U0001D50F', + "Ll;": '\U000022D8', + "Lleftarrow;": '\U000021DA', + "Lmidot;": '\U0000013F', + "LongLeftArrow;": '\U000027F5', + "LongLeftRightArrow;": '\U000027F7', + "LongRightArrow;": '\U000027F6', + "Longleftarrow;": '\U000027F8', + "Longleftrightarrow;": '\U000027FA', + "Longrightarrow;": '\U000027F9', + "Lopf;": '\U0001D543', + "LowerLeftArrow;": '\U00002199', + "LowerRightArrow;": '\U00002198', + "Lscr;": '\U00002112', + "Lsh;": '\U000021B0', + "Lstrok;": '\U00000141', + "Lt;": '\U0000226A', + "Map;": '\U00002905', + "Mcy;": '\U0000041C', + "MediumSpace;": '\U0000205F', + "Mellintrf;": '\U00002133', + "Mfr;": '\U0001D510', + "MinusPlus;": '\U00002213', + "Mopf;": '\U0001D544', + "Mscr;": '\U00002133', + "Mu;": '\U0000039C', + "NJcy;": '\U0000040A', + "Nacute;": '\U00000143', + "Ncaron;": '\U00000147', + "Ncedil;": '\U00000145', + "Ncy;": '\U0000041D', + "NegativeMediumSpace;": '\U0000200B', + "NegativeThickSpace;": '\U0000200B', + "NegativeThinSpace;": '\U0000200B', + "NegativeVeryThinSpace;": '\U0000200B', + "NestedGreaterGreater;": '\U0000226B', + "NestedLessLess;": '\U0000226A', + "NewLine;": '\U0000000A', + "Nfr;": '\U0001D511', + "NoBreak;": '\U00002060', + "NonBreakingSpace;": '\U000000A0', + "Nopf;": '\U00002115', + "Not;": '\U00002AEC', + "NotCongruent;": '\U00002262', + "NotCupCap;": '\U0000226D', + "NotDoubleVerticalBar;": '\U00002226', + "NotElement;": '\U00002209', + "NotEqual;": '\U00002260', + "NotExists;": '\U00002204', + "NotGreater;": '\U0000226F', + "NotGreaterEqual;": '\U00002271', + "NotGreaterLess;": '\U00002279', + "NotGreaterTilde;": '\U00002275', + "NotLeftTriangle;": '\U000022EA', + "NotLeftTriangleEqual;": '\U000022EC', + "NotLess;": '\U0000226E', + "NotLessEqual;": '\U00002270', + "NotLessGreater;": '\U00002278', + "NotLessTilde;": '\U00002274', + "NotPrecedes;": '\U00002280', + "NotPrecedesSlantEqual;": '\U000022E0', + "NotReverseElement;": '\U0000220C', + "NotRightTriangle;": '\U000022EB', + "NotRightTriangleEqual;": '\U000022ED', + "NotSquareSubsetEqual;": '\U000022E2', + "NotSquareSupersetEqual;": '\U000022E3', + "NotSubsetEqual;": '\U00002288', + "NotSucceeds;": '\U00002281', + "NotSucceedsSlantEqual;": '\U000022E1', + "NotSupersetEqual;": '\U00002289', + "NotTilde;": '\U00002241', + "NotTildeEqual;": '\U00002244', + "NotTildeFullEqual;": '\U00002247', + "NotTildeTilde;": '\U00002249', + "NotVerticalBar;": '\U00002224', + "Nscr;": '\U0001D4A9', + "Ntilde;": '\U000000D1', + "Nu;": '\U0000039D', + "OElig;": '\U00000152', + "Oacute;": '\U000000D3', + "Ocirc;": '\U000000D4', + "Ocy;": '\U0000041E', + "Odblac;": '\U00000150', + "Ofr;": '\U0001D512', + "Ograve;": '\U000000D2', + "Omacr;": '\U0000014C', + "Omega;": '\U000003A9', + "Omicron;": '\U0000039F', + "Oopf;": '\U0001D546', + "OpenCurlyDoubleQuote;": '\U0000201C', + "OpenCurlyQuote;": '\U00002018', + "Or;": '\U00002A54', + "Oscr;": '\U0001D4AA', + "Oslash;": '\U000000D8', + "Otilde;": '\U000000D5', + "Otimes;": '\U00002A37', + "Ouml;": '\U000000D6', + "OverBar;": '\U0000203E', + "OverBrace;": '\U000023DE', + "OverBracket;": '\U000023B4', + "OverParenthesis;": '\U000023DC', + "PartialD;": '\U00002202', + "Pcy;": '\U0000041F', + "Pfr;": '\U0001D513', + "Phi;": '\U000003A6', + "Pi;": '\U000003A0', + "PlusMinus;": '\U000000B1', + "Poincareplane;": '\U0000210C', + "Popf;": '\U00002119', + "Pr;": '\U00002ABB', + "Precedes;": '\U0000227A', + "PrecedesEqual;": '\U00002AAF', + "PrecedesSlantEqual;": '\U0000227C', + "PrecedesTilde;": '\U0000227E', + "Prime;": '\U00002033', + "Product;": '\U0000220F', + "Proportion;": '\U00002237', + "Proportional;": '\U0000221D', + "Pscr;": '\U0001D4AB', + "Psi;": '\U000003A8', + "QUOT;": '\U00000022', + "Qfr;": '\U0001D514', + "Qopf;": '\U0000211A', + "Qscr;": '\U0001D4AC', + "RBarr;": '\U00002910', + "REG;": '\U000000AE', + "Racute;": '\U00000154', + "Rang;": '\U000027EB', + "Rarr;": '\U000021A0', + "Rarrtl;": '\U00002916', + "Rcaron;": '\U00000158', + "Rcedil;": '\U00000156', + "Rcy;": '\U00000420', + "Re;": '\U0000211C', + "ReverseElement;": '\U0000220B', + "ReverseEquilibrium;": '\U000021CB', + "ReverseUpEquilibrium;": '\U0000296F', + "Rfr;": '\U0000211C', + "Rho;": '\U000003A1', + "RightAngleBracket;": '\U000027E9', + "RightArrow;": '\U00002192', + "RightArrowBar;": '\U000021E5', + "RightArrowLeftArrow;": '\U000021C4', + "RightCeiling;": '\U00002309', + "RightDoubleBracket;": '\U000027E7', + "RightDownTeeVector;": '\U0000295D', + "RightDownVector;": '\U000021C2', + "RightDownVectorBar;": '\U00002955', + "RightFloor;": '\U0000230B', + "RightTee;": '\U000022A2', + "RightTeeArrow;": '\U000021A6', + "RightTeeVector;": '\U0000295B', + "RightTriangle;": '\U000022B3', + "RightTriangleBar;": '\U000029D0', + "RightTriangleEqual;": '\U000022B5', + "RightUpDownVector;": '\U0000294F', + "RightUpTeeVector;": '\U0000295C', + "RightUpVector;": '\U000021BE', + "RightUpVectorBar;": '\U00002954', + "RightVector;": '\U000021C0', + "RightVectorBar;": '\U00002953', + "Rightarrow;": '\U000021D2', + "Ropf;": '\U0000211D', + "RoundImplies;": '\U00002970', + "Rrightarrow;": '\U000021DB', + "Rscr;": '\U0000211B', + "Rsh;": '\U000021B1', + "RuleDelayed;": '\U000029F4', + "SHCHcy;": '\U00000429', + "SHcy;": '\U00000428', + "SOFTcy;": '\U0000042C', + "Sacute;": '\U0000015A', + "Sc;": '\U00002ABC', + "Scaron;": '\U00000160', + "Scedil;": '\U0000015E', + "Scirc;": '\U0000015C', + "Scy;": '\U00000421', + "Sfr;": '\U0001D516', + "ShortDownArrow;": '\U00002193', + "ShortLeftArrow;": '\U00002190', + "ShortRightArrow;": '\U00002192', + "ShortUpArrow;": '\U00002191', + "Sigma;": '\U000003A3', + "SmallCircle;": '\U00002218', + "Sopf;": '\U0001D54A', + "Sqrt;": '\U0000221A', + "Square;": '\U000025A1', + "SquareIntersection;": '\U00002293', + "SquareSubset;": '\U0000228F', + "SquareSubsetEqual;": '\U00002291', + "SquareSuperset;": '\U00002290', + "SquareSupersetEqual;": '\U00002292', + "SquareUnion;": '\U00002294', + "Sscr;": '\U0001D4AE', + "Star;": '\U000022C6', + "Sub;": '\U000022D0', + "Subset;": '\U000022D0', + "SubsetEqual;": '\U00002286', + "Succeeds;": '\U0000227B', + "SucceedsEqual;": '\U00002AB0', + "SucceedsSlantEqual;": '\U0000227D', + "SucceedsTilde;": '\U0000227F', + "SuchThat;": '\U0000220B', + "Sum;": '\U00002211', + "Sup;": '\U000022D1', + "Superset;": '\U00002283', + "SupersetEqual;": '\U00002287', + "Supset;": '\U000022D1', + "THORN;": '\U000000DE', + "TRADE;": '\U00002122', + "TSHcy;": '\U0000040B', + "TScy;": '\U00000426', + "Tab;": '\U00000009', + "Tau;": '\U000003A4', + "Tcaron;": '\U00000164', + "Tcedil;": '\U00000162', + "Tcy;": '\U00000422', + "Tfr;": '\U0001D517', + "Therefore;": '\U00002234', + "Theta;": '\U00000398', + "ThinSpace;": '\U00002009', + "Tilde;": '\U0000223C', + "TildeEqual;": '\U00002243', + "TildeFullEqual;": '\U00002245', + "TildeTilde;": '\U00002248', + "Topf;": '\U0001D54B', + "TripleDot;": '\U000020DB', + "Tscr;": '\U0001D4AF', + "Tstrok;": '\U00000166', + "Uacute;": '\U000000DA', + "Uarr;": '\U0000219F', + "Uarrocir;": '\U00002949', + "Ubrcy;": '\U0000040E', + "Ubreve;": '\U0000016C', + "Ucirc;": '\U000000DB', + "Ucy;": '\U00000423', + "Udblac;": '\U00000170', + "Ufr;": '\U0001D518', + "Ugrave;": '\U000000D9', + "Umacr;": '\U0000016A', + "UnderBar;": '\U0000005F', + "UnderBrace;": '\U000023DF', + "UnderBracket;": '\U000023B5', + "UnderParenthesis;": '\U000023DD', + "Union;": '\U000022C3', + "UnionPlus;": '\U0000228E', + "Uogon;": '\U00000172', + "Uopf;": '\U0001D54C', + "UpArrow;": '\U00002191', + "UpArrowBar;": '\U00002912', + "UpArrowDownArrow;": '\U000021C5', + "UpDownArrow;": '\U00002195', + "UpEquilibrium;": '\U0000296E', + "UpTee;": '\U000022A5', + "UpTeeArrow;": '\U000021A5', + "Uparrow;": '\U000021D1', + "Updownarrow;": '\U000021D5', + "UpperLeftArrow;": '\U00002196', + "UpperRightArrow;": '\U00002197', + "Upsi;": '\U000003D2', + "Upsilon;": '\U000003A5', + "Uring;": '\U0000016E', + "Uscr;": '\U0001D4B0', + "Utilde;": '\U00000168', + "Uuml;": '\U000000DC', + "VDash;": '\U000022AB', + "Vbar;": '\U00002AEB', + "Vcy;": '\U00000412', + "Vdash;": '\U000022A9', + "Vdashl;": '\U00002AE6', + "Vee;": '\U000022C1', + "Verbar;": '\U00002016', + "Vert;": '\U00002016', + "VerticalBar;": '\U00002223', + "VerticalLine;": '\U0000007C', + "VerticalSeparator;": '\U00002758', + "VerticalTilde;": '\U00002240', + "VeryThinSpace;": '\U0000200A', + "Vfr;": '\U0001D519', + "Vopf;": '\U0001D54D', + "Vscr;": '\U0001D4B1', + "Vvdash;": '\U000022AA', + "Wcirc;": '\U00000174', + "Wedge;": '\U000022C0', + "Wfr;": '\U0001D51A', + "Wopf;": '\U0001D54E', + "Wscr;": '\U0001D4B2', + "Xfr;": '\U0001D51B', + "Xi;": '\U0000039E', + "Xopf;": '\U0001D54F', + "Xscr;": '\U0001D4B3', + "YAcy;": '\U0000042F', + "YIcy;": '\U00000407', + "YUcy;": '\U0000042E', + "Yacute;": '\U000000DD', + "Ycirc;": '\U00000176', + "Ycy;": '\U0000042B', + "Yfr;": '\U0001D51C', + "Yopf;": '\U0001D550', + "Yscr;": '\U0001D4B4', + "Yuml;": '\U00000178', + "ZHcy;": '\U00000416', + "Zacute;": '\U00000179', + "Zcaron;": '\U0000017D', + "Zcy;": '\U00000417', + "Zdot;": '\U0000017B', + "ZeroWidthSpace;": '\U0000200B', + "Zeta;": '\U00000396', + "Zfr;": '\U00002128', + "Zopf;": '\U00002124', + "Zscr;": '\U0001D4B5', + "aacute;": '\U000000E1', + "abreve;": '\U00000103', + "ac;": '\U0000223E', + "acd;": '\U0000223F', + "acirc;": '\U000000E2', + "acute;": '\U000000B4', + "acy;": '\U00000430', + "aelig;": '\U000000E6', + "af;": '\U00002061', + "afr;": '\U0001D51E', + "agrave;": '\U000000E0', + "alefsym;": '\U00002135', + "aleph;": '\U00002135', + "alpha;": '\U000003B1', + "amacr;": '\U00000101', + "amalg;": '\U00002A3F', + "amp;": '\U00000026', + "and;": '\U00002227', + "andand;": '\U00002A55', + "andd;": '\U00002A5C', + "andslope;": '\U00002A58', + "andv;": '\U00002A5A', + "ang;": '\U00002220', + "ange;": '\U000029A4', + "angle;": '\U00002220', + "angmsd;": '\U00002221', + "angmsdaa;": '\U000029A8', + "angmsdab;": '\U000029A9', + "angmsdac;": '\U000029AA', + "angmsdad;": '\U000029AB', + "angmsdae;": '\U000029AC', + "angmsdaf;": '\U000029AD', + "angmsdag;": '\U000029AE', + "angmsdah;": '\U000029AF', + "angrt;": '\U0000221F', + "angrtvb;": '\U000022BE', + "angrtvbd;": '\U0000299D', + "angsph;": '\U00002222', + "angst;": '\U000000C5', + "angzarr;": '\U0000237C', + "aogon;": '\U00000105', + "aopf;": '\U0001D552', + "ap;": '\U00002248', + "apE;": '\U00002A70', + "apacir;": '\U00002A6F', + "ape;": '\U0000224A', + "apid;": '\U0000224B', + "apos;": '\U00000027', + "approx;": '\U00002248', + "approxeq;": '\U0000224A', + "aring;": '\U000000E5', + "ascr;": '\U0001D4B6', + "ast;": '\U0000002A', + "asymp;": '\U00002248', + "asympeq;": '\U0000224D', + "atilde;": '\U000000E3', + "auml;": '\U000000E4', + "awconint;": '\U00002233', + "awint;": '\U00002A11', + "bNot;": '\U00002AED', + "backcong;": '\U0000224C', + "backepsilon;": '\U000003F6', + "backprime;": '\U00002035', + "backsim;": '\U0000223D', + "backsimeq;": '\U000022CD', + "barvee;": '\U000022BD', + "barwed;": '\U00002305', + "barwedge;": '\U00002305', + "bbrk;": '\U000023B5', + "bbrktbrk;": '\U000023B6', + "bcong;": '\U0000224C', + "bcy;": '\U00000431', + "bdquo;": '\U0000201E', + "becaus;": '\U00002235', + "because;": '\U00002235', + "bemptyv;": '\U000029B0', + "bepsi;": '\U000003F6', + "bernou;": '\U0000212C', + "beta;": '\U000003B2', + "beth;": '\U00002136', + "between;": '\U0000226C', + "bfr;": '\U0001D51F', + "bigcap;": '\U000022C2', + "bigcirc;": '\U000025EF', + "bigcup;": '\U000022C3', + "bigodot;": '\U00002A00', + "bigoplus;": '\U00002A01', + "bigotimes;": '\U00002A02', + "bigsqcup;": '\U00002A06', + "bigstar;": '\U00002605', + "bigtriangledown;": '\U000025BD', + "bigtriangleup;": '\U000025B3', + "biguplus;": '\U00002A04', + "bigvee;": '\U000022C1', + "bigwedge;": '\U000022C0', + "bkarow;": '\U0000290D', + "blacklozenge;": '\U000029EB', + "blacksquare;": '\U000025AA', + "blacktriangle;": '\U000025B4', + "blacktriangledown;": '\U000025BE', + "blacktriangleleft;": '\U000025C2', + "blacktriangleright;": '\U000025B8', + "blank;": '\U00002423', + "blk12;": '\U00002592', + "blk14;": '\U00002591', + "blk34;": '\U00002593', + "block;": '\U00002588', + "bnot;": '\U00002310', + "bopf;": '\U0001D553', + "bot;": '\U000022A5', + "bottom;": '\U000022A5', + "bowtie;": '\U000022C8', + "boxDL;": '\U00002557', + "boxDR;": '\U00002554', + "boxDl;": '\U00002556', + "boxDr;": '\U00002553', + "boxH;": '\U00002550', + "boxHD;": '\U00002566', + "boxHU;": '\U00002569', + "boxHd;": '\U00002564', + "boxHu;": '\U00002567', + "boxUL;": '\U0000255D', + "boxUR;": '\U0000255A', + "boxUl;": '\U0000255C', + "boxUr;": '\U00002559', + "boxV;": '\U00002551', + "boxVH;": '\U0000256C', + "boxVL;": '\U00002563', + "boxVR;": '\U00002560', + "boxVh;": '\U0000256B', + "boxVl;": '\U00002562', + "boxVr;": '\U0000255F', + "boxbox;": '\U000029C9', + "boxdL;": '\U00002555', + "boxdR;": '\U00002552', + "boxdl;": '\U00002510', + "boxdr;": '\U0000250C', + "boxh;": '\U00002500', + "boxhD;": '\U00002565', + "boxhU;": '\U00002568', + "boxhd;": '\U0000252C', + "boxhu;": '\U00002534', + "boxminus;": '\U0000229F', + "boxplus;": '\U0000229E', + "boxtimes;": '\U000022A0', + "boxuL;": '\U0000255B', + "boxuR;": '\U00002558', + "boxul;": '\U00002518', + "boxur;": '\U00002514', + "boxv;": '\U00002502', + "boxvH;": '\U0000256A', + "boxvL;": '\U00002561', + "boxvR;": '\U0000255E', + "boxvh;": '\U0000253C', + "boxvl;": '\U00002524', + "boxvr;": '\U0000251C', + "bprime;": '\U00002035', + "breve;": '\U000002D8', + "brvbar;": '\U000000A6', + "bscr;": '\U0001D4B7', + "bsemi;": '\U0000204F', + "bsim;": '\U0000223D', + "bsime;": '\U000022CD', + "bsol;": '\U0000005C', + "bsolb;": '\U000029C5', + "bsolhsub;": '\U000027C8', + "bull;": '\U00002022', + "bullet;": '\U00002022', + "bump;": '\U0000224E', + "bumpE;": '\U00002AAE', + "bumpe;": '\U0000224F', + "bumpeq;": '\U0000224F', + "cacute;": '\U00000107', + "cap;": '\U00002229', + "capand;": '\U00002A44', + "capbrcup;": '\U00002A49', + "capcap;": '\U00002A4B', + "capcup;": '\U00002A47', + "capdot;": '\U00002A40', + "caret;": '\U00002041', + "caron;": '\U000002C7', + "ccaps;": '\U00002A4D', + "ccaron;": '\U0000010D', + "ccedil;": '\U000000E7', + "ccirc;": '\U00000109', + "ccups;": '\U00002A4C', + "ccupssm;": '\U00002A50', + "cdot;": '\U0000010B', + "cedil;": '\U000000B8', + "cemptyv;": '\U000029B2', + "cent;": '\U000000A2', + "centerdot;": '\U000000B7', + "cfr;": '\U0001D520', + "chcy;": '\U00000447', + "check;": '\U00002713', + "checkmark;": '\U00002713', + "chi;": '\U000003C7', + "cir;": '\U000025CB', + "cirE;": '\U000029C3', + "circ;": '\U000002C6', + "circeq;": '\U00002257', + "circlearrowleft;": '\U000021BA', + "circlearrowright;": '\U000021BB', + "circledR;": '\U000000AE', + "circledS;": '\U000024C8', + "circledast;": '\U0000229B', + "circledcirc;": '\U0000229A', + "circleddash;": '\U0000229D', + "cire;": '\U00002257', + "cirfnint;": '\U00002A10', + "cirmid;": '\U00002AEF', + "cirscir;": '\U000029C2', + "clubs;": '\U00002663', + "clubsuit;": '\U00002663', + "colon;": '\U0000003A', + "colone;": '\U00002254', + "coloneq;": '\U00002254', + "comma;": '\U0000002C', + "commat;": '\U00000040', + "comp;": '\U00002201', + "compfn;": '\U00002218', + "complement;": '\U00002201', + "complexes;": '\U00002102', + "cong;": '\U00002245', + "congdot;": '\U00002A6D', + "conint;": '\U0000222E', + "copf;": '\U0001D554', + "coprod;": '\U00002210', + "copy;": '\U000000A9', + "copysr;": '\U00002117', + "crarr;": '\U000021B5', + "cross;": '\U00002717', + "cscr;": '\U0001D4B8', + "csub;": '\U00002ACF', + "csube;": '\U00002AD1', + "csup;": '\U00002AD0', + "csupe;": '\U00002AD2', + "ctdot;": '\U000022EF', + "cudarrl;": '\U00002938', + "cudarrr;": '\U00002935', + "cuepr;": '\U000022DE', + "cuesc;": '\U000022DF', + "cularr;": '\U000021B6', + "cularrp;": '\U0000293D', + "cup;": '\U0000222A', + "cupbrcap;": '\U00002A48', + "cupcap;": '\U00002A46', + "cupcup;": '\U00002A4A', + "cupdot;": '\U0000228D', + "cupor;": '\U00002A45', + "curarr;": '\U000021B7', + "curarrm;": '\U0000293C', + "curlyeqprec;": '\U000022DE', + "curlyeqsucc;": '\U000022DF', + "curlyvee;": '\U000022CE', + "curlywedge;": '\U000022CF', + "curren;": '\U000000A4', + "curvearrowleft;": '\U000021B6', + "curvearrowright;": '\U000021B7', + "cuvee;": '\U000022CE', + "cuwed;": '\U000022CF', + "cwconint;": '\U00002232', + "cwint;": '\U00002231', + "cylcty;": '\U0000232D', + "dArr;": '\U000021D3', + "dHar;": '\U00002965', + "dagger;": '\U00002020', + "daleth;": '\U00002138', + "darr;": '\U00002193', + "dash;": '\U00002010', + "dashv;": '\U000022A3', + "dbkarow;": '\U0000290F', + "dblac;": '\U000002DD', + "dcaron;": '\U0000010F', + "dcy;": '\U00000434', + "dd;": '\U00002146', + "ddagger;": '\U00002021', + "ddarr;": '\U000021CA', + "ddotseq;": '\U00002A77', + "deg;": '\U000000B0', + "delta;": '\U000003B4', + "demptyv;": '\U000029B1', + "dfisht;": '\U0000297F', + "dfr;": '\U0001D521', + "dharl;": '\U000021C3', + "dharr;": '\U000021C2', + "diam;": '\U000022C4', + "diamond;": '\U000022C4', + "diamondsuit;": '\U00002666', + "diams;": '\U00002666', + "die;": '\U000000A8', + "digamma;": '\U000003DD', + "disin;": '\U000022F2', + "div;": '\U000000F7', + "divide;": '\U000000F7', + "divideontimes;": '\U000022C7', + "divonx;": '\U000022C7', + "djcy;": '\U00000452', + "dlcorn;": '\U0000231E', + "dlcrop;": '\U0000230D', + "dollar;": '\U00000024', + "dopf;": '\U0001D555', + "dot;": '\U000002D9', + "doteq;": '\U00002250', + "doteqdot;": '\U00002251', + "dotminus;": '\U00002238', + "dotplus;": '\U00002214', + "dotsquare;": '\U000022A1', + "doublebarwedge;": '\U00002306', + "downarrow;": '\U00002193', + "downdownarrows;": '\U000021CA', + "downharpoonleft;": '\U000021C3', + "downharpoonright;": '\U000021C2', + "drbkarow;": '\U00002910', + "drcorn;": '\U0000231F', + "drcrop;": '\U0000230C', + "dscr;": '\U0001D4B9', + "dscy;": '\U00000455', + "dsol;": '\U000029F6', + "dstrok;": '\U00000111', + "dtdot;": '\U000022F1', + "dtri;": '\U000025BF', + "dtrif;": '\U000025BE', + "duarr;": '\U000021F5', + "duhar;": '\U0000296F', + "dwangle;": '\U000029A6', + "dzcy;": '\U0000045F', + "dzigrarr;": '\U000027FF', + "eDDot;": '\U00002A77', + "eDot;": '\U00002251', + "eacute;": '\U000000E9', + "easter;": '\U00002A6E', + "ecaron;": '\U0000011B', + "ecir;": '\U00002256', + "ecirc;": '\U000000EA', + "ecolon;": '\U00002255', + "ecy;": '\U0000044D', + "edot;": '\U00000117', + "ee;": '\U00002147', + "efDot;": '\U00002252', + "efr;": '\U0001D522', + "eg;": '\U00002A9A', + "egrave;": '\U000000E8', + "egs;": '\U00002A96', + "egsdot;": '\U00002A98', + "el;": '\U00002A99', + "elinters;": '\U000023E7', + "ell;": '\U00002113', + "els;": '\U00002A95', + "elsdot;": '\U00002A97', + "emacr;": '\U00000113', + "empty;": '\U00002205', + "emptyset;": '\U00002205', + "emptyv;": '\U00002205', + "emsp;": '\U00002003', + "emsp13;": '\U00002004', + "emsp14;": '\U00002005', + "eng;": '\U0000014B', + "ensp;": '\U00002002', + "eogon;": '\U00000119', + "eopf;": '\U0001D556', + "epar;": '\U000022D5', + "eparsl;": '\U000029E3', + "eplus;": '\U00002A71', + "epsi;": '\U000003B5', + "epsilon;": '\U000003B5', + "epsiv;": '\U000003F5', + "eqcirc;": '\U00002256', + "eqcolon;": '\U00002255', + "eqsim;": '\U00002242', + "eqslantgtr;": '\U00002A96', + "eqslantless;": '\U00002A95', + "equals;": '\U0000003D', + "equest;": '\U0000225F', + "equiv;": '\U00002261', + "equivDD;": '\U00002A78', + "eqvparsl;": '\U000029E5', + "erDot;": '\U00002253', + "erarr;": '\U00002971', + "escr;": '\U0000212F', + "esdot;": '\U00002250', + "esim;": '\U00002242', + "eta;": '\U000003B7', + "eth;": '\U000000F0', + "euml;": '\U000000EB', + "euro;": '\U000020AC', + "excl;": '\U00000021', + "exist;": '\U00002203', + "expectation;": '\U00002130', + "exponentiale;": '\U00002147', + "fallingdotseq;": '\U00002252', + "fcy;": '\U00000444', + "female;": '\U00002640', + "ffilig;": '\U0000FB03', + "fflig;": '\U0000FB00', + "ffllig;": '\U0000FB04', + "ffr;": '\U0001D523', + "filig;": '\U0000FB01', + "flat;": '\U0000266D', + "fllig;": '\U0000FB02', + "fltns;": '\U000025B1', + "fnof;": '\U00000192', + "fopf;": '\U0001D557', + "forall;": '\U00002200', + "fork;": '\U000022D4', + "forkv;": '\U00002AD9', + "fpartint;": '\U00002A0D', + "frac12;": '\U000000BD', + "frac13;": '\U00002153', + "frac14;": '\U000000BC', + "frac15;": '\U00002155', + "frac16;": '\U00002159', + "frac18;": '\U0000215B', + "frac23;": '\U00002154', + "frac25;": '\U00002156', + "frac34;": '\U000000BE', + "frac35;": '\U00002157', + "frac38;": '\U0000215C', + "frac45;": '\U00002158', + "frac56;": '\U0000215A', + "frac58;": '\U0000215D', + "frac78;": '\U0000215E', + "frasl;": '\U00002044', + "frown;": '\U00002322', + "fscr;": '\U0001D4BB', + "gE;": '\U00002267', + "gEl;": '\U00002A8C', + "gacute;": '\U000001F5', + "gamma;": '\U000003B3', + "gammad;": '\U000003DD', + "gap;": '\U00002A86', + "gbreve;": '\U0000011F', + "gcirc;": '\U0000011D', + "gcy;": '\U00000433', + "gdot;": '\U00000121', + "ge;": '\U00002265', + "gel;": '\U000022DB', + "geq;": '\U00002265', + "geqq;": '\U00002267', + "geqslant;": '\U00002A7E', + "ges;": '\U00002A7E', + "gescc;": '\U00002AA9', + "gesdot;": '\U00002A80', + "gesdoto;": '\U00002A82', + "gesdotol;": '\U00002A84', + "gesles;": '\U00002A94', + "gfr;": '\U0001D524', + "gg;": '\U0000226B', + "ggg;": '\U000022D9', + "gimel;": '\U00002137', + "gjcy;": '\U00000453', + "gl;": '\U00002277', + "glE;": '\U00002A92', + "gla;": '\U00002AA5', + "glj;": '\U00002AA4', + "gnE;": '\U00002269', + "gnap;": '\U00002A8A', + "gnapprox;": '\U00002A8A', + "gne;": '\U00002A88', + "gneq;": '\U00002A88', + "gneqq;": '\U00002269', + "gnsim;": '\U000022E7', + "gopf;": '\U0001D558', + "grave;": '\U00000060', + "gscr;": '\U0000210A', + "gsim;": '\U00002273', + "gsime;": '\U00002A8E', + "gsiml;": '\U00002A90', + "gt;": '\U0000003E', + "gtcc;": '\U00002AA7', + "gtcir;": '\U00002A7A', + "gtdot;": '\U000022D7', + "gtlPar;": '\U00002995', + "gtquest;": '\U00002A7C', + "gtrapprox;": '\U00002A86', + "gtrarr;": '\U00002978', + "gtrdot;": '\U000022D7', + "gtreqless;": '\U000022DB', + "gtreqqless;": '\U00002A8C', + "gtrless;": '\U00002277', + "gtrsim;": '\U00002273', + "hArr;": '\U000021D4', + "hairsp;": '\U0000200A', + "half;": '\U000000BD', + "hamilt;": '\U0000210B', + "hardcy;": '\U0000044A', + "harr;": '\U00002194', + "harrcir;": '\U00002948', + "harrw;": '\U000021AD', + "hbar;": '\U0000210F', + "hcirc;": '\U00000125', + "hearts;": '\U00002665', + "heartsuit;": '\U00002665', + "hellip;": '\U00002026', + "hercon;": '\U000022B9', + "hfr;": '\U0001D525', + "hksearow;": '\U00002925', + "hkswarow;": '\U00002926', + "hoarr;": '\U000021FF', + "homtht;": '\U0000223B', + "hookleftarrow;": '\U000021A9', + "hookrightarrow;": '\U000021AA', + "hopf;": '\U0001D559', + "horbar;": '\U00002015', + "hscr;": '\U0001D4BD', + "hslash;": '\U0000210F', + "hstrok;": '\U00000127', + "hybull;": '\U00002043', + "hyphen;": '\U00002010', + "iacute;": '\U000000ED', + "ic;": '\U00002063', + "icirc;": '\U000000EE', + "icy;": '\U00000438', + "iecy;": '\U00000435', + "iexcl;": '\U000000A1', + "iff;": '\U000021D4', + "ifr;": '\U0001D526', + "igrave;": '\U000000EC', + "ii;": '\U00002148', + "iiiint;": '\U00002A0C', + "iiint;": '\U0000222D', + "iinfin;": '\U000029DC', + "iiota;": '\U00002129', + "ijlig;": '\U00000133', + "imacr;": '\U0000012B', + "image;": '\U00002111', + "imagline;": '\U00002110', + "imagpart;": '\U00002111', + "imath;": '\U00000131', + "imof;": '\U000022B7', + "imped;": '\U000001B5', + "in;": '\U00002208', + "incare;": '\U00002105', + "infin;": '\U0000221E', + "infintie;": '\U000029DD', + "inodot;": '\U00000131', + "int;": '\U0000222B', + "intcal;": '\U000022BA', + "integers;": '\U00002124', + "intercal;": '\U000022BA', + "intlarhk;": '\U00002A17', + "intprod;": '\U00002A3C', + "iocy;": '\U00000451', + "iogon;": '\U0000012F', + "iopf;": '\U0001D55A', + "iota;": '\U000003B9', + "iprod;": '\U00002A3C', + "iquest;": '\U000000BF', + "iscr;": '\U0001D4BE', + "isin;": '\U00002208', + "isinE;": '\U000022F9', + "isindot;": '\U000022F5', + "isins;": '\U000022F4', + "isinsv;": '\U000022F3', + "isinv;": '\U00002208', + "it;": '\U00002062', + "itilde;": '\U00000129', + "iukcy;": '\U00000456', + "iuml;": '\U000000EF', + "jcirc;": '\U00000135', + "jcy;": '\U00000439', + "jfr;": '\U0001D527', + "jmath;": '\U00000237', + "jopf;": '\U0001D55B', + "jscr;": '\U0001D4BF', + "jsercy;": '\U00000458', + "jukcy;": '\U00000454', + "kappa;": '\U000003BA', + "kappav;": '\U000003F0', + "kcedil;": '\U00000137', + "kcy;": '\U0000043A', + "kfr;": '\U0001D528', + "kgreen;": '\U00000138', + "khcy;": '\U00000445', + "kjcy;": '\U0000045C', + "kopf;": '\U0001D55C', + "kscr;": '\U0001D4C0', + "lAarr;": '\U000021DA', + "lArr;": '\U000021D0', + "lAtail;": '\U0000291B', + "lBarr;": '\U0000290E', + "lE;": '\U00002266', + "lEg;": '\U00002A8B', + "lHar;": '\U00002962', + "lacute;": '\U0000013A', + "laemptyv;": '\U000029B4', + "lagran;": '\U00002112', + "lambda;": '\U000003BB', + "lang;": '\U000027E8', + "langd;": '\U00002991', + "langle;": '\U000027E8', + "lap;": '\U00002A85', + "laquo;": '\U000000AB', + "larr;": '\U00002190', + "larrb;": '\U000021E4', + "larrbfs;": '\U0000291F', + "larrfs;": '\U0000291D', + "larrhk;": '\U000021A9', + "larrlp;": '\U000021AB', + "larrpl;": '\U00002939', + "larrsim;": '\U00002973', + "larrtl;": '\U000021A2', + "lat;": '\U00002AAB', + "latail;": '\U00002919', + "late;": '\U00002AAD', + "lbarr;": '\U0000290C', + "lbbrk;": '\U00002772', + "lbrace;": '\U0000007B', + "lbrack;": '\U0000005B', + "lbrke;": '\U0000298B', + "lbrksld;": '\U0000298F', + "lbrkslu;": '\U0000298D', + "lcaron;": '\U0000013E', + "lcedil;": '\U0000013C', + "lceil;": '\U00002308', + "lcub;": '\U0000007B', + "lcy;": '\U0000043B', + "ldca;": '\U00002936', + "ldquo;": '\U0000201C', + "ldquor;": '\U0000201E', + "ldrdhar;": '\U00002967', + "ldrushar;": '\U0000294B', + "ldsh;": '\U000021B2', + "le;": '\U00002264', + "leftarrow;": '\U00002190', + "leftarrowtail;": '\U000021A2', + "leftharpoondown;": '\U000021BD', + "leftharpoonup;": '\U000021BC', + "leftleftarrows;": '\U000021C7', + "leftrightarrow;": '\U00002194', + "leftrightarrows;": '\U000021C6', + "leftrightharpoons;": '\U000021CB', + "leftrightsquigarrow;": '\U000021AD', + "leftthreetimes;": '\U000022CB', + "leg;": '\U000022DA', + "leq;": '\U00002264', + "leqq;": '\U00002266', + "leqslant;": '\U00002A7D', + "les;": '\U00002A7D', + "lescc;": '\U00002AA8', + "lesdot;": '\U00002A7F', + "lesdoto;": '\U00002A81', + "lesdotor;": '\U00002A83', + "lesges;": '\U00002A93', + "lessapprox;": '\U00002A85', + "lessdot;": '\U000022D6', + "lesseqgtr;": '\U000022DA', + "lesseqqgtr;": '\U00002A8B', + "lessgtr;": '\U00002276', + "lesssim;": '\U00002272', + "lfisht;": '\U0000297C', + "lfloor;": '\U0000230A', + "lfr;": '\U0001D529', + "lg;": '\U00002276', + "lgE;": '\U00002A91', + "lhard;": '\U000021BD', + "lharu;": '\U000021BC', + "lharul;": '\U0000296A', + "lhblk;": '\U00002584', + "ljcy;": '\U00000459', + "ll;": '\U0000226A', + "llarr;": '\U000021C7', + "llcorner;": '\U0000231E', + "llhard;": '\U0000296B', + "lltri;": '\U000025FA', + "lmidot;": '\U00000140', + "lmoust;": '\U000023B0', + "lmoustache;": '\U000023B0', + "lnE;": '\U00002268', + "lnap;": '\U00002A89', + "lnapprox;": '\U00002A89', + "lne;": '\U00002A87', + "lneq;": '\U00002A87', + "lneqq;": '\U00002268', + "lnsim;": '\U000022E6', + "loang;": '\U000027EC', + "loarr;": '\U000021FD', + "lobrk;": '\U000027E6', + "longleftarrow;": '\U000027F5', + "longleftrightarrow;": '\U000027F7', + "longmapsto;": '\U000027FC', + "longrightarrow;": '\U000027F6', + "looparrowleft;": '\U000021AB', + "looparrowright;": '\U000021AC', + "lopar;": '\U00002985', + "lopf;": '\U0001D55D', + "loplus;": '\U00002A2D', + "lotimes;": '\U00002A34', + "lowast;": '\U00002217', + "lowbar;": '\U0000005F', + "loz;": '\U000025CA', + "lozenge;": '\U000025CA', + "lozf;": '\U000029EB', + "lpar;": '\U00000028', + "lparlt;": '\U00002993', + "lrarr;": '\U000021C6', + "lrcorner;": '\U0000231F', + "lrhar;": '\U000021CB', + "lrhard;": '\U0000296D', + "lrm;": '\U0000200E', + "lrtri;": '\U000022BF', + "lsaquo;": '\U00002039', + "lscr;": '\U0001D4C1', + "lsh;": '\U000021B0', + "lsim;": '\U00002272', + "lsime;": '\U00002A8D', + "lsimg;": '\U00002A8F', + "lsqb;": '\U0000005B', + "lsquo;": '\U00002018', + "lsquor;": '\U0000201A', + "lstrok;": '\U00000142', + "lt;": '\U0000003C', + "ltcc;": '\U00002AA6', + "ltcir;": '\U00002A79', + "ltdot;": '\U000022D6', + "lthree;": '\U000022CB', + "ltimes;": '\U000022C9', + "ltlarr;": '\U00002976', + "ltquest;": '\U00002A7B', + "ltrPar;": '\U00002996', + "ltri;": '\U000025C3', + "ltrie;": '\U000022B4', + "ltrif;": '\U000025C2', + "lurdshar;": '\U0000294A', + "luruhar;": '\U00002966', + "mDDot;": '\U0000223A', + "macr;": '\U000000AF', + "male;": '\U00002642', + "malt;": '\U00002720', + "maltese;": '\U00002720', + "map;": '\U000021A6', + "mapsto;": '\U000021A6', + "mapstodown;": '\U000021A7', + "mapstoleft;": '\U000021A4', + "mapstoup;": '\U000021A5', + "marker;": '\U000025AE', + "mcomma;": '\U00002A29', + "mcy;": '\U0000043C', + "mdash;": '\U00002014', + "measuredangle;": '\U00002221', + "mfr;": '\U0001D52A', + "mho;": '\U00002127', + "micro;": '\U000000B5', + "mid;": '\U00002223', + "midast;": '\U0000002A', + "midcir;": '\U00002AF0', + "middot;": '\U000000B7', + "minus;": '\U00002212', + "minusb;": '\U0000229F', + "minusd;": '\U00002238', + "minusdu;": '\U00002A2A', + "mlcp;": '\U00002ADB', + "mldr;": '\U00002026', + "mnplus;": '\U00002213', + "models;": '\U000022A7', + "mopf;": '\U0001D55E', + "mp;": '\U00002213', + "mscr;": '\U0001D4C2', + "mstpos;": '\U0000223E', + "mu;": '\U000003BC', + "multimap;": '\U000022B8', + "mumap;": '\U000022B8', + "nLeftarrow;": '\U000021CD', + "nLeftrightarrow;": '\U000021CE', + "nRightarrow;": '\U000021CF', + "nVDash;": '\U000022AF', + "nVdash;": '\U000022AE', + "nabla;": '\U00002207', + "nacute;": '\U00000144', + "nap;": '\U00002249', + "napos;": '\U00000149', + "napprox;": '\U00002249', + "natur;": '\U0000266E', + "natural;": '\U0000266E', + "naturals;": '\U00002115', + "nbsp;": '\U000000A0', + "ncap;": '\U00002A43', + "ncaron;": '\U00000148', + "ncedil;": '\U00000146', + "ncong;": '\U00002247', + "ncup;": '\U00002A42', + "ncy;": '\U0000043D', + "ndash;": '\U00002013', + "ne;": '\U00002260', + "neArr;": '\U000021D7', + "nearhk;": '\U00002924', + "nearr;": '\U00002197', + "nearrow;": '\U00002197', + "nequiv;": '\U00002262', + "nesear;": '\U00002928', + "nexist;": '\U00002204', + "nexists;": '\U00002204', + "nfr;": '\U0001D52B', + "nge;": '\U00002271', + "ngeq;": '\U00002271', + "ngsim;": '\U00002275', + "ngt;": '\U0000226F', + "ngtr;": '\U0000226F', + "nhArr;": '\U000021CE', + "nharr;": '\U000021AE', + "nhpar;": '\U00002AF2', + "ni;": '\U0000220B', + "nis;": '\U000022FC', + "nisd;": '\U000022FA', + "niv;": '\U0000220B', + "njcy;": '\U0000045A', + "nlArr;": '\U000021CD', + "nlarr;": '\U0000219A', + "nldr;": '\U00002025', + "nle;": '\U00002270', + "nleftarrow;": '\U0000219A', + "nleftrightarrow;": '\U000021AE', + "nleq;": '\U00002270', + "nless;": '\U0000226E', + "nlsim;": '\U00002274', + "nlt;": '\U0000226E', + "nltri;": '\U000022EA', + "nltrie;": '\U000022EC', + "nmid;": '\U00002224', + "nopf;": '\U0001D55F', + "not;": '\U000000AC', + "notin;": '\U00002209', + "notinva;": '\U00002209', + "notinvb;": '\U000022F7', + "notinvc;": '\U000022F6', + "notni;": '\U0000220C', + "notniva;": '\U0000220C', + "notnivb;": '\U000022FE', + "notnivc;": '\U000022FD', + "npar;": '\U00002226', + "nparallel;": '\U00002226', + "npolint;": '\U00002A14', + "npr;": '\U00002280', + "nprcue;": '\U000022E0', + "nprec;": '\U00002280', + "nrArr;": '\U000021CF', + "nrarr;": '\U0000219B', + "nrightarrow;": '\U0000219B', + "nrtri;": '\U000022EB', + "nrtrie;": '\U000022ED', + "nsc;": '\U00002281', + "nsccue;": '\U000022E1', + "nscr;": '\U0001D4C3', + "nshortmid;": '\U00002224', + "nshortparallel;": '\U00002226', + "nsim;": '\U00002241', + "nsime;": '\U00002244', + "nsimeq;": '\U00002244', + "nsmid;": '\U00002224', + "nspar;": '\U00002226', + "nsqsube;": '\U000022E2', + "nsqsupe;": '\U000022E3', + "nsub;": '\U00002284', + "nsube;": '\U00002288', + "nsubseteq;": '\U00002288', + "nsucc;": '\U00002281', + "nsup;": '\U00002285', + "nsupe;": '\U00002289', + "nsupseteq;": '\U00002289', + "ntgl;": '\U00002279', + "ntilde;": '\U000000F1', + "ntlg;": '\U00002278', + "ntriangleleft;": '\U000022EA', + "ntrianglelefteq;": '\U000022EC', + "ntriangleright;": '\U000022EB', + "ntrianglerighteq;": '\U000022ED', + "nu;": '\U000003BD', + "num;": '\U00000023', + "numero;": '\U00002116', + "numsp;": '\U00002007', + "nvDash;": '\U000022AD', + "nvHarr;": '\U00002904', + "nvdash;": '\U000022AC', + "nvinfin;": '\U000029DE', + "nvlArr;": '\U00002902', + "nvrArr;": '\U00002903', + "nwArr;": '\U000021D6', + "nwarhk;": '\U00002923', + "nwarr;": '\U00002196', + "nwarrow;": '\U00002196', + "nwnear;": '\U00002927', + "oS;": '\U000024C8', + "oacute;": '\U000000F3', + "oast;": '\U0000229B', + "ocir;": '\U0000229A', + "ocirc;": '\U000000F4', + "ocy;": '\U0000043E', + "odash;": '\U0000229D', + "odblac;": '\U00000151', + "odiv;": '\U00002A38', + "odot;": '\U00002299', + "odsold;": '\U000029BC', + "oelig;": '\U00000153', + "ofcir;": '\U000029BF', + "ofr;": '\U0001D52C', + "ogon;": '\U000002DB', + "ograve;": '\U000000F2', + "ogt;": '\U000029C1', + "ohbar;": '\U000029B5', + "ohm;": '\U000003A9', + "oint;": '\U0000222E', + "olarr;": '\U000021BA', + "olcir;": '\U000029BE', + "olcross;": '\U000029BB', + "oline;": '\U0000203E', + "olt;": '\U000029C0', + "omacr;": '\U0000014D', + "omega;": '\U000003C9', + "omicron;": '\U000003BF', + "omid;": '\U000029B6', + "ominus;": '\U00002296', + "oopf;": '\U0001D560', + "opar;": '\U000029B7', + "operp;": '\U000029B9', + "oplus;": '\U00002295', + "or;": '\U00002228', + "orarr;": '\U000021BB', + "ord;": '\U00002A5D', + "order;": '\U00002134', + "orderof;": '\U00002134', + "ordf;": '\U000000AA', + "ordm;": '\U000000BA', + "origof;": '\U000022B6', + "oror;": '\U00002A56', + "orslope;": '\U00002A57', + "orv;": '\U00002A5B', + "oscr;": '\U00002134', + "oslash;": '\U000000F8', + "osol;": '\U00002298', + "otilde;": '\U000000F5', + "otimes;": '\U00002297', + "otimesas;": '\U00002A36', + "ouml;": '\U000000F6', + "ovbar;": '\U0000233D', + "par;": '\U00002225', + "para;": '\U000000B6', + "parallel;": '\U00002225', + "parsim;": '\U00002AF3', + "parsl;": '\U00002AFD', + "part;": '\U00002202', + "pcy;": '\U0000043F', + "percnt;": '\U00000025', + "period;": '\U0000002E', + "permil;": '\U00002030', + "perp;": '\U000022A5', + "pertenk;": '\U00002031', + "pfr;": '\U0001D52D', + "phi;": '\U000003C6', + "phiv;": '\U000003D5', + "phmmat;": '\U00002133', + "phone;": '\U0000260E', + "pi;": '\U000003C0', + "pitchfork;": '\U000022D4', + "piv;": '\U000003D6', + "planck;": '\U0000210F', + "planckh;": '\U0000210E', + "plankv;": '\U0000210F', + "plus;": '\U0000002B', + "plusacir;": '\U00002A23', + "plusb;": '\U0000229E', + "pluscir;": '\U00002A22', + "plusdo;": '\U00002214', + "plusdu;": '\U00002A25', + "pluse;": '\U00002A72', + "plusmn;": '\U000000B1', + "plussim;": '\U00002A26', + "plustwo;": '\U00002A27', + "pm;": '\U000000B1', + "pointint;": '\U00002A15', + "popf;": '\U0001D561', + "pound;": '\U000000A3', + "pr;": '\U0000227A', + "prE;": '\U00002AB3', + "prap;": '\U00002AB7', + "prcue;": '\U0000227C', + "pre;": '\U00002AAF', + "prec;": '\U0000227A', + "precapprox;": '\U00002AB7', + "preccurlyeq;": '\U0000227C', + "preceq;": '\U00002AAF', + "precnapprox;": '\U00002AB9', + "precneqq;": '\U00002AB5', + "precnsim;": '\U000022E8', + "precsim;": '\U0000227E', + "prime;": '\U00002032', + "primes;": '\U00002119', + "prnE;": '\U00002AB5', + "prnap;": '\U00002AB9', + "prnsim;": '\U000022E8', + "prod;": '\U0000220F', + "profalar;": '\U0000232E', + "profline;": '\U00002312', + "profsurf;": '\U00002313', + "prop;": '\U0000221D', + "propto;": '\U0000221D', + "prsim;": '\U0000227E', + "prurel;": '\U000022B0', + "pscr;": '\U0001D4C5', + "psi;": '\U000003C8', + "puncsp;": '\U00002008', + "qfr;": '\U0001D52E', + "qint;": '\U00002A0C', + "qopf;": '\U0001D562', + "qprime;": '\U00002057', + "qscr;": '\U0001D4C6', + "quaternions;": '\U0000210D', + "quatint;": '\U00002A16', + "quest;": '\U0000003F', + "questeq;": '\U0000225F', + "quot;": '\U00000022', + "rAarr;": '\U000021DB', + "rArr;": '\U000021D2', + "rAtail;": '\U0000291C', + "rBarr;": '\U0000290F', + "rHar;": '\U00002964', + "racute;": '\U00000155', + "radic;": '\U0000221A', + "raemptyv;": '\U000029B3', + "rang;": '\U000027E9', + "rangd;": '\U00002992', + "range;": '\U000029A5', + "rangle;": '\U000027E9', + "raquo;": '\U000000BB', + "rarr;": '\U00002192', + "rarrap;": '\U00002975', + "rarrb;": '\U000021E5', + "rarrbfs;": '\U00002920', + "rarrc;": '\U00002933', + "rarrfs;": '\U0000291E', + "rarrhk;": '\U000021AA', + "rarrlp;": '\U000021AC', + "rarrpl;": '\U00002945', + "rarrsim;": '\U00002974', + "rarrtl;": '\U000021A3', + "rarrw;": '\U0000219D', + "ratail;": '\U0000291A', + "ratio;": '\U00002236', + "rationals;": '\U0000211A', + "rbarr;": '\U0000290D', + "rbbrk;": '\U00002773', + "rbrace;": '\U0000007D', + "rbrack;": '\U0000005D', + "rbrke;": '\U0000298C', + "rbrksld;": '\U0000298E', + "rbrkslu;": '\U00002990', + "rcaron;": '\U00000159', + "rcedil;": '\U00000157', + "rceil;": '\U00002309', + "rcub;": '\U0000007D', + "rcy;": '\U00000440', + "rdca;": '\U00002937', + "rdldhar;": '\U00002969', + "rdquo;": '\U0000201D', + "rdquor;": '\U0000201D', + "rdsh;": '\U000021B3', + "real;": '\U0000211C', + "realine;": '\U0000211B', + "realpart;": '\U0000211C', + "reals;": '\U0000211D', + "rect;": '\U000025AD', + "reg;": '\U000000AE', + "rfisht;": '\U0000297D', + "rfloor;": '\U0000230B', + "rfr;": '\U0001D52F', + "rhard;": '\U000021C1', + "rharu;": '\U000021C0', + "rharul;": '\U0000296C', + "rho;": '\U000003C1', + "rhov;": '\U000003F1', + "rightarrow;": '\U00002192', + "rightarrowtail;": '\U000021A3', + "rightharpoondown;": '\U000021C1', + "rightharpoonup;": '\U000021C0', + "rightleftarrows;": '\U000021C4', + "rightleftharpoons;": '\U000021CC', + "rightrightarrows;": '\U000021C9', + "rightsquigarrow;": '\U0000219D', + "rightthreetimes;": '\U000022CC', + "ring;": '\U000002DA', + "risingdotseq;": '\U00002253', + "rlarr;": '\U000021C4', + "rlhar;": '\U000021CC', + "rlm;": '\U0000200F', + "rmoust;": '\U000023B1', + "rmoustache;": '\U000023B1', + "rnmid;": '\U00002AEE', + "roang;": '\U000027ED', + "roarr;": '\U000021FE', + "robrk;": '\U000027E7', + "ropar;": '\U00002986', + "ropf;": '\U0001D563', + "roplus;": '\U00002A2E', + "rotimes;": '\U00002A35', + "rpar;": '\U00000029', + "rpargt;": '\U00002994', + "rppolint;": '\U00002A12', + "rrarr;": '\U000021C9', + "rsaquo;": '\U0000203A', + "rscr;": '\U0001D4C7', + "rsh;": '\U000021B1', + "rsqb;": '\U0000005D', + "rsquo;": '\U00002019', + "rsquor;": '\U00002019', + "rthree;": '\U000022CC', + "rtimes;": '\U000022CA', + "rtri;": '\U000025B9', + "rtrie;": '\U000022B5', + "rtrif;": '\U000025B8', + "rtriltri;": '\U000029CE', + "ruluhar;": '\U00002968', + "rx;": '\U0000211E', + "sacute;": '\U0000015B', + "sbquo;": '\U0000201A', + "sc;": '\U0000227B', + "scE;": '\U00002AB4', + "scap;": '\U00002AB8', + "scaron;": '\U00000161', + "sccue;": '\U0000227D', + "sce;": '\U00002AB0', + "scedil;": '\U0000015F', + "scirc;": '\U0000015D', + "scnE;": '\U00002AB6', + "scnap;": '\U00002ABA', + "scnsim;": '\U000022E9', + "scpolint;": '\U00002A13', + "scsim;": '\U0000227F', + "scy;": '\U00000441', + "sdot;": '\U000022C5', + "sdotb;": '\U000022A1', + "sdote;": '\U00002A66', + "seArr;": '\U000021D8', + "searhk;": '\U00002925', + "searr;": '\U00002198', + "searrow;": '\U00002198', + "sect;": '\U000000A7', + "semi;": '\U0000003B', + "seswar;": '\U00002929', + "setminus;": '\U00002216', + "setmn;": '\U00002216', + "sext;": '\U00002736', + "sfr;": '\U0001D530', + "sfrown;": '\U00002322', + "sharp;": '\U0000266F', + "shchcy;": '\U00000449', + "shcy;": '\U00000448', + "shortmid;": '\U00002223', + "shortparallel;": '\U00002225', + "shy;": '\U000000AD', + "sigma;": '\U000003C3', + "sigmaf;": '\U000003C2', + "sigmav;": '\U000003C2', + "sim;": '\U0000223C', + "simdot;": '\U00002A6A', + "sime;": '\U00002243', + "simeq;": '\U00002243', + "simg;": '\U00002A9E', + "simgE;": '\U00002AA0', + "siml;": '\U00002A9D', + "simlE;": '\U00002A9F', + "simne;": '\U00002246', + "simplus;": '\U00002A24', + "simrarr;": '\U00002972', + "slarr;": '\U00002190', + "smallsetminus;": '\U00002216', + "smashp;": '\U00002A33', + "smeparsl;": '\U000029E4', + "smid;": '\U00002223', + "smile;": '\U00002323', + "smt;": '\U00002AAA', + "smte;": '\U00002AAC', + "softcy;": '\U0000044C', + "sol;": '\U0000002F', + "solb;": '\U000029C4', + "solbar;": '\U0000233F', + "sopf;": '\U0001D564', + "spades;": '\U00002660', + "spadesuit;": '\U00002660', + "spar;": '\U00002225', + "sqcap;": '\U00002293', + "sqcup;": '\U00002294', + "sqsub;": '\U0000228F', + "sqsube;": '\U00002291', + "sqsubset;": '\U0000228F', + "sqsubseteq;": '\U00002291', + "sqsup;": '\U00002290', + "sqsupe;": '\U00002292', + "sqsupset;": '\U00002290', + "sqsupseteq;": '\U00002292', + "squ;": '\U000025A1', + "square;": '\U000025A1', + "squarf;": '\U000025AA', + "squf;": '\U000025AA', + "srarr;": '\U00002192', + "sscr;": '\U0001D4C8', + "ssetmn;": '\U00002216', + "ssmile;": '\U00002323', + "sstarf;": '\U000022C6', + "star;": '\U00002606', + "starf;": '\U00002605', + "straightepsilon;": '\U000003F5', + "straightphi;": '\U000003D5', + "strns;": '\U000000AF', + "sub;": '\U00002282', + "subE;": '\U00002AC5', + "subdot;": '\U00002ABD', + "sube;": '\U00002286', + "subedot;": '\U00002AC3', + "submult;": '\U00002AC1', + "subnE;": '\U00002ACB', + "subne;": '\U0000228A', + "subplus;": '\U00002ABF', + "subrarr;": '\U00002979', + "subset;": '\U00002282', + "subseteq;": '\U00002286', + "subseteqq;": '\U00002AC5', + "subsetneq;": '\U0000228A', + "subsetneqq;": '\U00002ACB', + "subsim;": '\U00002AC7', + "subsub;": '\U00002AD5', + "subsup;": '\U00002AD3', + "succ;": '\U0000227B', + "succapprox;": '\U00002AB8', + "succcurlyeq;": '\U0000227D', + "succeq;": '\U00002AB0', + "succnapprox;": '\U00002ABA', + "succneqq;": '\U00002AB6', + "succnsim;": '\U000022E9', + "succsim;": '\U0000227F', + "sum;": '\U00002211', + "sung;": '\U0000266A', + "sup;": '\U00002283', + "sup1;": '\U000000B9', + "sup2;": '\U000000B2', + "sup3;": '\U000000B3', + "supE;": '\U00002AC6', + "supdot;": '\U00002ABE', + "supdsub;": '\U00002AD8', + "supe;": '\U00002287', + "supedot;": '\U00002AC4', + "suphsol;": '\U000027C9', + "suphsub;": '\U00002AD7', + "suplarr;": '\U0000297B', + "supmult;": '\U00002AC2', + "supnE;": '\U00002ACC', + "supne;": '\U0000228B', + "supplus;": '\U00002AC0', + "supset;": '\U00002283', + "supseteq;": '\U00002287', + "supseteqq;": '\U00002AC6', + "supsetneq;": '\U0000228B', + "supsetneqq;": '\U00002ACC', + "supsim;": '\U00002AC8', + "supsub;": '\U00002AD4', + "supsup;": '\U00002AD6', + "swArr;": '\U000021D9', + "swarhk;": '\U00002926', + "swarr;": '\U00002199', + "swarrow;": '\U00002199', + "swnwar;": '\U0000292A', + "szlig;": '\U000000DF', + "target;": '\U00002316', + "tau;": '\U000003C4', + "tbrk;": '\U000023B4', + "tcaron;": '\U00000165', + "tcedil;": '\U00000163', + "tcy;": '\U00000442', + "tdot;": '\U000020DB', + "telrec;": '\U00002315', + "tfr;": '\U0001D531', + "there4;": '\U00002234', + "therefore;": '\U00002234', + "theta;": '\U000003B8', + "thetasym;": '\U000003D1', + "thetav;": '\U000003D1', + "thickapprox;": '\U00002248', + "thicksim;": '\U0000223C', + "thinsp;": '\U00002009', + "thkap;": '\U00002248', + "thksim;": '\U0000223C', + "thorn;": '\U000000FE', + "tilde;": '\U000002DC', + "times;": '\U000000D7', + "timesb;": '\U000022A0', + "timesbar;": '\U00002A31', + "timesd;": '\U00002A30', + "tint;": '\U0000222D', + "toea;": '\U00002928', + "top;": '\U000022A4', + "topbot;": '\U00002336', + "topcir;": '\U00002AF1', + "topf;": '\U0001D565', + "topfork;": '\U00002ADA', + "tosa;": '\U00002929', + "tprime;": '\U00002034', + "trade;": '\U00002122', + "triangle;": '\U000025B5', + "triangledown;": '\U000025BF', + "triangleleft;": '\U000025C3', + "trianglelefteq;": '\U000022B4', + "triangleq;": '\U0000225C', + "triangleright;": '\U000025B9', + "trianglerighteq;": '\U000022B5', + "tridot;": '\U000025EC', + "trie;": '\U0000225C', + "triminus;": '\U00002A3A', + "triplus;": '\U00002A39', + "trisb;": '\U000029CD', + "tritime;": '\U00002A3B', + "trpezium;": '\U000023E2', + "tscr;": '\U0001D4C9', + "tscy;": '\U00000446', + "tshcy;": '\U0000045B', + "tstrok;": '\U00000167', + "twixt;": '\U0000226C', + "twoheadleftarrow;": '\U0000219E', + "twoheadrightarrow;": '\U000021A0', + "uArr;": '\U000021D1', + "uHar;": '\U00002963', + "uacute;": '\U000000FA', + "uarr;": '\U00002191', + "ubrcy;": '\U0000045E', + "ubreve;": '\U0000016D', + "ucirc;": '\U000000FB', + "ucy;": '\U00000443', + "udarr;": '\U000021C5', + "udblac;": '\U00000171', + "udhar;": '\U0000296E', + "ufisht;": '\U0000297E', + "ufr;": '\U0001D532', + "ugrave;": '\U000000F9', + "uharl;": '\U000021BF', + "uharr;": '\U000021BE', + "uhblk;": '\U00002580', + "ulcorn;": '\U0000231C', + "ulcorner;": '\U0000231C', + "ulcrop;": '\U0000230F', + "ultri;": '\U000025F8', + "umacr;": '\U0000016B', + "uml;": '\U000000A8', + "uogon;": '\U00000173', + "uopf;": '\U0001D566', + "uparrow;": '\U00002191', + "updownarrow;": '\U00002195', + "upharpoonleft;": '\U000021BF', + "upharpoonright;": '\U000021BE', + "uplus;": '\U0000228E', + "upsi;": '\U000003C5', + "upsih;": '\U000003D2', + "upsilon;": '\U000003C5', + "upuparrows;": '\U000021C8', + "urcorn;": '\U0000231D', + "urcorner;": '\U0000231D', + "urcrop;": '\U0000230E', + "uring;": '\U0000016F', + "urtri;": '\U000025F9', + "uscr;": '\U0001D4CA', + "utdot;": '\U000022F0', + "utilde;": '\U00000169', + "utri;": '\U000025B5', + "utrif;": '\U000025B4', + "uuarr;": '\U000021C8', + "uuml;": '\U000000FC', + "uwangle;": '\U000029A7', + "vArr;": '\U000021D5', + "vBar;": '\U00002AE8', + "vBarv;": '\U00002AE9', + "vDash;": '\U000022A8', + "vangrt;": '\U0000299C', + "varepsilon;": '\U000003F5', + "varkappa;": '\U000003F0', + "varnothing;": '\U00002205', + "varphi;": '\U000003D5', + "varpi;": '\U000003D6', + "varpropto;": '\U0000221D', + "varr;": '\U00002195', + "varrho;": '\U000003F1', + "varsigma;": '\U000003C2', + "vartheta;": '\U000003D1', + "vartriangleleft;": '\U000022B2', + "vartriangleright;": '\U000022B3', + "vcy;": '\U00000432', + "vdash;": '\U000022A2', + "vee;": '\U00002228', + "veebar;": '\U000022BB', + "veeeq;": '\U0000225A', + "vellip;": '\U000022EE', + "verbar;": '\U0000007C', + "vert;": '\U0000007C', + "vfr;": '\U0001D533', + "vltri;": '\U000022B2', + "vopf;": '\U0001D567', + "vprop;": '\U0000221D', + "vrtri;": '\U000022B3', + "vscr;": '\U0001D4CB', + "vzigzag;": '\U0000299A', + "wcirc;": '\U00000175', + "wedbar;": '\U00002A5F', + "wedge;": '\U00002227', + "wedgeq;": '\U00002259', + "weierp;": '\U00002118', + "wfr;": '\U0001D534', + "wopf;": '\U0001D568', + "wp;": '\U00002118', + "wr;": '\U00002240', + "wreath;": '\U00002240', + "wscr;": '\U0001D4CC', + "xcap;": '\U000022C2', + "xcirc;": '\U000025EF', + "xcup;": '\U000022C3', + "xdtri;": '\U000025BD', + "xfr;": '\U0001D535', + "xhArr;": '\U000027FA', + "xharr;": '\U000027F7', + "xi;": '\U000003BE', + "xlArr;": '\U000027F8', + "xlarr;": '\U000027F5', + "xmap;": '\U000027FC', + "xnis;": '\U000022FB', + "xodot;": '\U00002A00', + "xopf;": '\U0001D569', + "xoplus;": '\U00002A01', + "xotime;": '\U00002A02', + "xrArr;": '\U000027F9', + "xrarr;": '\U000027F6', + "xscr;": '\U0001D4CD', + "xsqcup;": '\U00002A06', + "xuplus;": '\U00002A04', + "xutri;": '\U000025B3', + "xvee;": '\U000022C1', + "xwedge;": '\U000022C0', + "yacute;": '\U000000FD', + "yacy;": '\U0000044F', + "ycirc;": '\U00000177', + "ycy;": '\U0000044B', + "yen;": '\U000000A5', + "yfr;": '\U0001D536', + "yicy;": '\U00000457', + "yopf;": '\U0001D56A', + "yscr;": '\U0001D4CE', + "yucy;": '\U0000044E', + "yuml;": '\U000000FF', + "zacute;": '\U0000017A', + "zcaron;": '\U0000017E', + "zcy;": '\U00000437', + "zdot;": '\U0000017C', + "zeetrf;": '\U00002128', + "zeta;": '\U000003B6', + "zfr;": '\U0001D537', + "zhcy;": '\U00000436', + "zigrarr;": '\U000021DD', + "zopf;": '\U0001D56B', + "zscr;": '\U0001D4CF', + "zwj;": '\U0000200D', + "zwnj;": '\U0000200C', + "AElig": '\U000000C6', + "AMP": '\U00000026', + "Aacute": '\U000000C1', + "Acirc": '\U000000C2', + "Agrave": '\U000000C0', + "Aring": '\U000000C5', + "Atilde": '\U000000C3', + "Auml": '\U000000C4', + "COPY": '\U000000A9', + "Ccedil": '\U000000C7', + "ETH": '\U000000D0', + "Eacute": '\U000000C9', + "Ecirc": '\U000000CA', + "Egrave": '\U000000C8', + "Euml": '\U000000CB', + "GT": '\U0000003E', + "Iacute": '\U000000CD', + "Icirc": '\U000000CE', + "Igrave": '\U000000CC', + "Iuml": '\U000000CF', + "LT": '\U0000003C', + "Ntilde": '\U000000D1', + "Oacute": '\U000000D3', + "Ocirc": '\U000000D4', + "Ograve": '\U000000D2', + "Oslash": '\U000000D8', + "Otilde": '\U000000D5', + "Ouml": '\U000000D6', + "QUOT": '\U00000022', + "REG": '\U000000AE', + "THORN": '\U000000DE', + "Uacute": '\U000000DA', + "Ucirc": '\U000000DB', + "Ugrave": '\U000000D9', + "Uuml": '\U000000DC', + "Yacute": '\U000000DD', + "aacute": '\U000000E1', + "acirc": '\U000000E2', + "acute": '\U000000B4', + "aelig": '\U000000E6', + "agrave": '\U000000E0', + "amp": '\U00000026', + "aring": '\U000000E5', + "atilde": '\U000000E3', + "auml": '\U000000E4', + "brvbar": '\U000000A6', + "ccedil": '\U000000E7', + "cedil": '\U000000B8', + "cent": '\U000000A2', + "copy": '\U000000A9', + "curren": '\U000000A4', + "deg": '\U000000B0', + "divide": '\U000000F7', + "eacute": '\U000000E9', + "ecirc": '\U000000EA', + "egrave": '\U000000E8', + "eth": '\U000000F0', + "euml": '\U000000EB', + "frac12": '\U000000BD', + "frac14": '\U000000BC', + "frac34": '\U000000BE', + "gt": '\U0000003E', + "iacute": '\U000000ED', + "icirc": '\U000000EE', + "iexcl": '\U000000A1', + "igrave": '\U000000EC', + "iquest": '\U000000BF', + "iuml": '\U000000EF', + "laquo": '\U000000AB', + "lt": '\U0000003C', + "macr": '\U000000AF', + "micro": '\U000000B5', + "middot": '\U000000B7', + "nbsp": '\U000000A0', + "not": '\U000000AC', + "ntilde": '\U000000F1', + "oacute": '\U000000F3', + "ocirc": '\U000000F4', + "ograve": '\U000000F2', + "ordf": '\U000000AA', + "ordm": '\U000000BA', + "oslash": '\U000000F8', + "otilde": '\U000000F5', + "ouml": '\U000000F6', + "para": '\U000000B6', + "plusmn": '\U000000B1', + "pound": '\U000000A3', + "quot": '\U00000022', + "raquo": '\U000000BB', + "reg": '\U000000AE', + "sect": '\U000000A7', + "shy": '\U000000AD', + "sup1": '\U000000B9', + "sup2": '\U000000B2', + "sup3": '\U000000B3', + "szlig": '\U000000DF', + "thorn": '\U000000FE', + "times": '\U000000D7', + "uacute": '\U000000FA', + "ucirc": '\U000000FB', + "ugrave": '\U000000F9', + "uml": '\U000000A8', + "uuml": '\U000000FC', + "yacute": '\U000000FD', + "yen": '\U000000A5', + "yuml": '\U000000FF', +} + +// HTML entities that are two unicode codepoints. +var entity2 = map[string][2]rune{ + // TODO(nigeltao): Handle replacements that are wider than their names. + // "nLt;": {'\u226A', '\u20D2'}, + // "nGt;": {'\u226B', '\u20D2'}, + "NotEqualTilde;": {'\u2242', '\u0338'}, + "NotGreaterFullEqual;": {'\u2267', '\u0338'}, + "NotGreaterGreater;": {'\u226B', '\u0338'}, + "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'}, + "NotHumpDownHump;": {'\u224E', '\u0338'}, + "NotHumpEqual;": {'\u224F', '\u0338'}, + "NotLeftTriangleBar;": {'\u29CF', '\u0338'}, + "NotLessLess;": {'\u226A', '\u0338'}, + "NotLessSlantEqual;": {'\u2A7D', '\u0338'}, + "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'}, + "NotNestedLessLess;": {'\u2AA1', '\u0338'}, + "NotPrecedesEqual;": {'\u2AAF', '\u0338'}, + "NotRightTriangleBar;": {'\u29D0', '\u0338'}, + "NotSquareSubset;": {'\u228F', '\u0338'}, + "NotSquareSuperset;": {'\u2290', '\u0338'}, + "NotSubset;": {'\u2282', '\u20D2'}, + "NotSucceedsEqual;": {'\u2AB0', '\u0338'}, + "NotSucceedsTilde;": {'\u227F', '\u0338'}, + "NotSuperset;": {'\u2283', '\u20D2'}, + "ThickSpace;": {'\u205F', '\u200A'}, + "acE;": {'\u223E', '\u0333'}, + "bne;": {'\u003D', '\u20E5'}, + "bnequiv;": {'\u2261', '\u20E5'}, + "caps;": {'\u2229', '\uFE00'}, + "cups;": {'\u222A', '\uFE00'}, + "fjlig;": {'\u0066', '\u006A'}, + "gesl;": {'\u22DB', '\uFE00'}, + "gvertneqq;": {'\u2269', '\uFE00'}, + "gvnE;": {'\u2269', '\uFE00'}, + "lates;": {'\u2AAD', '\uFE00'}, + "lesg;": {'\u22DA', '\uFE00'}, + "lvertneqq;": {'\u2268', '\uFE00'}, + "lvnE;": {'\u2268', '\uFE00'}, + "nGg;": {'\u22D9', '\u0338'}, + "nGtv;": {'\u226B', '\u0338'}, + "nLl;": {'\u22D8', '\u0338'}, + "nLtv;": {'\u226A', '\u0338'}, + "nang;": {'\u2220', '\u20D2'}, + "napE;": {'\u2A70', '\u0338'}, + "napid;": {'\u224B', '\u0338'}, + "nbump;": {'\u224E', '\u0338'}, + "nbumpe;": {'\u224F', '\u0338'}, + "ncongdot;": {'\u2A6D', '\u0338'}, + "nedot;": {'\u2250', '\u0338'}, + "nesim;": {'\u2242', '\u0338'}, + "ngE;": {'\u2267', '\u0338'}, + "ngeqq;": {'\u2267', '\u0338'}, + "ngeqslant;": {'\u2A7E', '\u0338'}, + "nges;": {'\u2A7E', '\u0338'}, + "nlE;": {'\u2266', '\u0338'}, + "nleqq;": {'\u2266', '\u0338'}, + "nleqslant;": {'\u2A7D', '\u0338'}, + "nles;": {'\u2A7D', '\u0338'}, + "notinE;": {'\u22F9', '\u0338'}, + "notindot;": {'\u22F5', '\u0338'}, + "nparsl;": {'\u2AFD', '\u20E5'}, + "npart;": {'\u2202', '\u0338'}, + "npre;": {'\u2AAF', '\u0338'}, + "npreceq;": {'\u2AAF', '\u0338'}, + "nrarrc;": {'\u2933', '\u0338'}, + "nrarrw;": {'\u219D', '\u0338'}, + "nsce;": {'\u2AB0', '\u0338'}, + "nsubE;": {'\u2AC5', '\u0338'}, + "nsubset;": {'\u2282', '\u20D2'}, + "nsubseteqq;": {'\u2AC5', '\u0338'}, + "nsucceq;": {'\u2AB0', '\u0338'}, + "nsupE;": {'\u2AC6', '\u0338'}, + "nsupset;": {'\u2283', '\u20D2'}, + "nsupseteqq;": {'\u2AC6', '\u0338'}, + "nvap;": {'\u224D', '\u20D2'}, + "nvge;": {'\u2265', '\u20D2'}, + "nvgt;": {'\u003E', '\u20D2'}, + "nvle;": {'\u2264', '\u20D2'}, + "nvlt;": {'\u003C', '\u20D2'}, + "nvltrie;": {'\u22B4', '\u20D2'}, + "nvrtrie;": {'\u22B5', '\u20D2'}, + "nvsim;": {'\u223C', '\u20D2'}, + "race;": {'\u223D', '\u0331'}, + "smtes;": {'\u2AAC', '\uFE00'}, + "sqcaps;": {'\u2293', '\uFE00'}, + "sqcups;": {'\u2294', '\uFE00'}, + "varsubsetneq;": {'\u228A', '\uFE00'}, + "varsubsetneqq;": {'\u2ACB', '\uFE00'}, + "varsupsetneq;": {'\u228B', '\uFE00'}, + "varsupsetneqq;": {'\u2ACC', '\uFE00'}, + "vnsub;": {'\u2282', '\u20D2'}, + "vnsup;": {'\u2283', '\u20D2'}, + "vsubnE;": {'\u2ACB', '\uFE00'}, + "vsubne;": {'\u228A', '\uFE00'}, + "vsupnE;": {'\u2ACC', '\uFE00'}, + "vsupne;": {'\u228B', '\uFE00'}, +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/escape.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/escape.go new file mode 100644 index 000000000..d85613962 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/escape.go @@ -0,0 +1,258 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "bytes" + "strings" + "unicode/utf8" +) + +// These replacements permit compatibility with old numeric entities that +// assumed Windows-1252 encoding. +// https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference +var replacementTable = [...]rune{ + '\u20AC', // First entry is what 0x80 should be replaced with. + '\u0081', + '\u201A', + '\u0192', + '\u201E', + '\u2026', + '\u2020', + '\u2021', + '\u02C6', + '\u2030', + '\u0160', + '\u2039', + '\u0152', + '\u008D', + '\u017D', + '\u008F', + '\u0090', + '\u2018', + '\u2019', + '\u201C', + '\u201D', + '\u2022', + '\u2013', + '\u2014', + '\u02DC', + '\u2122', + '\u0161', + '\u203A', + '\u0153', + '\u009D', + '\u017E', + '\u0178', // Last entry is 0x9F. + // 0x00->'\uFFFD' is handled programmatically. + // 0x0D->'\u000D' is a no-op. +} + +// unescapeEntity reads an entity like "<" from b[src:] and writes the +// corresponding "<" to b[dst:], returning the incremented dst and src cursors. +// Precondition: b[src] == '&' && dst <= src. +// attribute should be true if parsing an attribute value. +func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) { + // https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference + + // i starts at 1 because we already know that s[0] == '&'. + i, s := 1, b[src:] + + if len(s) <= 1 { + b[dst] = b[src] + return dst + 1, src + 1 + } + + if s[i] == '#' { + if len(s) <= 3 { // We need to have at least "&#.". + b[dst] = b[src] + return dst + 1, src + 1 + } + i++ + c := s[i] + hex := false + if c == 'x' || c == 'X' { + hex = true + i++ + } + + x := '\x00' + for i < len(s) { + c = s[i] + i++ + if hex { + if '0' <= c && c <= '9' { + x = 16*x + rune(c) - '0' + continue + } else if 'a' <= c && c <= 'f' { + x = 16*x + rune(c) - 'a' + 10 + continue + } else if 'A' <= c && c <= 'F' { + x = 16*x + rune(c) - 'A' + 10 + continue + } + } else if '0' <= c && c <= '9' { + x = 10*x + rune(c) - '0' + continue + } + if c != ';' { + i-- + } + break + } + + if i <= 3 { // No characters matched. + b[dst] = b[src] + return dst + 1, src + 1 + } + + if 0x80 <= x && x <= 0x9F { + // Replace characters from Windows-1252 with UTF-8 equivalents. + x = replacementTable[x-0x80] + } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF { + // Replace invalid characters with the replacement character. + x = '\uFFFD' + } + + return dst + utf8.EncodeRune(b[dst:], x), src + i + } + + // Consume the maximum number of characters possible, with the + // consumed characters matching one of the named references. + + for i < len(s) { + c := s[i] + i++ + // Lower-cased characters are more common in entities, so we check for them first. + if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { + continue + } + if c != ';' { + i-- + } + break + } + + entityName := string(s[1:i]) + if entityName == "" { + // No-op. + } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > i && s[i] == '=' { + // No-op. + } else if x := entity[entityName]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + i + } else if x := entity2[entityName]; x[0] != 0 { + dst1 := dst + utf8.EncodeRune(b[dst:], x[0]) + return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i + } else if !attribute { + maxLen := len(entityName) - 1 + if maxLen > longestEntityWithoutSemicolon { + maxLen = longestEntityWithoutSemicolon + } + for j := maxLen; j > 1; j-- { + if x := entity[entityName[:j]]; x != 0 { + return dst + utf8.EncodeRune(b[dst:], x), src + j + 1 + } + } + } + + dst1, src1 = dst+i, src+i + copy(b[dst:dst1], b[src:src1]) + return dst1, src1 +} + +// unescape unescapes b's entities in-place, so that "a<b" becomes "a': + esc = ">" + case '"': + // """ is shorter than """. + esc = """ + case '\r': + esc = " " + default: + panic("unrecognized escape character") + } + s = s[i+1:] + if _, err := w.WriteString(esc); err != nil { + return err + } + i = strings.IndexAny(s, escapedChars) + } + _, err := w.WriteString(s) + return err +} + +// EscapeString escapes special characters like "<" to become "<". It +// escapes only five such characters: <, >, &, ' and ". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func EscapeString(s string) string { + if strings.IndexAny(s, escapedChars) == -1 { + return s + } + var buf bytes.Buffer + escape(&buf, s) + return buf.String() +} + +// UnescapeString unescapes entities like "<" to become "<". It unescapes a +// larger range of entities than EscapeString escapes. For example, "á" +// unescapes to "á", as does "á" and "&xE1;". +// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't +// always true. +func UnescapeString(s string) string { + for _, c := range s { + if c == '&' { + return string(unescape([]byte(s), false)) + } + } + return s +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/foreign.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/foreign.go new file mode 100644 index 000000000..74774c458 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/foreign.go @@ -0,0 +1,225 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "strings" +) + +func adjustAttributeNames(aa []Attribute, nameMap map[string]string) { + for i := range aa { + if newName, ok := nameMap[aa[i].Key]; ok { + aa[i].Key = newName + } + } +} + +func adjustForeignAttributes(aa []Attribute) { + for i, a := range aa { + if a.Key == "" || a.Key[0] != 'x' { + continue + } + switch a.Key { + case "xlink:actuate", "xlink:arcrole", "xlink:href", "xlink:role", "xlink:show", + "xlink:title", "xlink:type", "xml:base", "xml:lang", "xml:space", "xmlns:xlink": + j := strings.Index(a.Key, ":") + aa[i].Namespace = a.Key[:j] + aa[i].Key = a.Key[j+1:] + } + } +} + +func htmlIntegrationPoint(n *Node) bool { + if n.Type != ElementNode { + return false + } + switch n.Namespace { + case "math": + if n.Data == "annotation-xml" { + for _, a := range n.Attr { + if a.Key == "encoding" { + val := strings.ToLower(a.Val) + if val == "text/html" || val == "application/xhtml+xml" { + return true + } + } + } + } + case "svg": + switch n.Data { + case "desc", "foreignObject", "title": + return true + } + } + return false +} + +func mathMLTextIntegrationPoint(n *Node) bool { + if n.Namespace != "math" { + return false + } + switch n.Data { + case "mi", "mo", "mn", "ms", "mtext": + return true + } + return false +} + +// Section 12.2.6.5. +var breakout = map[string]bool{ + "b": true, + "big": true, + "blockquote": true, + "body": true, + "br": true, + "center": true, + "code": true, + "dd": true, + "div": true, + "dl": true, + "dt": true, + "em": true, + "embed": true, + "h1": true, + "h2": true, + "h3": true, + "h4": true, + "h5": true, + "h6": true, + "head": true, + "hr": true, + "i": true, + "img": true, + "li": true, + "listing": true, + "menu": true, + "meta": true, + "nobr": true, + "ol": true, + "p": true, + "pre": true, + "ruby": true, + "s": true, + "small": true, + "span": true, + "strong": true, + "strike": true, + "sub": true, + "sup": true, + "table": true, + "tt": true, + "u": true, + "ul": true, + "var": true, +} + +// Section 12.2.6.5. +var svgTagNameAdjustments = map[string]string{ + "altglyph": "altGlyph", + "altglyphdef": "altGlyphDef", + "altglyphitem": "altGlyphItem", + "animatecolor": "animateColor", + "animatemotion": "animateMotion", + "animatetransform": "animateTransform", + "clippath": "clipPath", + "feblend": "feBlend", + "fecolormatrix": "feColorMatrix", + "fecomponenttransfer": "feComponentTransfer", + "fecomposite": "feComposite", + "feconvolvematrix": "feConvolveMatrix", + "fediffuselighting": "feDiffuseLighting", + "fedisplacementmap": "feDisplacementMap", + "fedistantlight": "feDistantLight", + "feflood": "feFlood", + "fefunca": "feFuncA", + "fefuncb": "feFuncB", + "fefuncg": "feFuncG", + "fefuncr": "feFuncR", + "fegaussianblur": "feGaussianBlur", + "feimage": "feImage", + "femerge": "feMerge", + "femergenode": "feMergeNode", + "femorphology": "feMorphology", + "feoffset": "feOffset", + "fepointlight": "fePointLight", + "fespecularlighting": "feSpecularLighting", + "fespotlight": "feSpotLight", + "fetile": "feTile", + "feturbulence": "feTurbulence", + "foreignobject": "foreignObject", + "glyphref": "glyphRef", + "lineargradient": "linearGradient", + "radialgradient": "radialGradient", + "textpath": "textPath", +} + +// Section 12.2.6.1 +var mathMLAttributeAdjustments = map[string]string{ + "definitionurl": "definitionURL", +} + +var svgAttributeAdjustments = map[string]string{ + "attributename": "attributeName", + "attributetype": "attributeType", + "basefrequency": "baseFrequency", + "baseprofile": "baseProfile", + "calcmode": "calcMode", + "clippathunits": "clipPathUnits", + "contentscripttype": "contentScriptType", + "contentstyletype": "contentStyleType", + "diffuseconstant": "diffuseConstant", + "edgemode": "edgeMode", + "externalresourcesrequired": "externalResourcesRequired", + "filterunits": "filterUnits", + "glyphref": "glyphRef", + "gradienttransform": "gradientTransform", + "gradientunits": "gradientUnits", + "kernelmatrix": "kernelMatrix", + "kernelunitlength": "kernelUnitLength", + "keypoints": "keyPoints", + "keysplines": "keySplines", + "keytimes": "keyTimes", + "lengthadjust": "lengthAdjust", + "limitingconeangle": "limitingConeAngle", + "markerheight": "markerHeight", + "markerunits": "markerUnits", + "markerwidth": "markerWidth", + "maskcontentunits": "maskContentUnits", + "maskunits": "maskUnits", + "numoctaves": "numOctaves", + "pathlength": "pathLength", + "patterncontentunits": "patternContentUnits", + "patterntransform": "patternTransform", + "patternunits": "patternUnits", + "pointsatx": "pointsAtX", + "pointsaty": "pointsAtY", + "pointsatz": "pointsAtZ", + "preservealpha": "preserveAlpha", + "preserveaspectratio": "preserveAspectRatio", + "primitiveunits": "primitiveUnits", + "refx": "refX", + "refy": "refY", + "repeatcount": "repeatCount", + "repeatdur": "repeatDur", + "requiredextensions": "requiredExtensions", + "requiredfeatures": "requiredFeatures", + "specularconstant": "specularConstant", + "specularexponent": "specularExponent", + "spreadmethod": "spreadMethod", + "startoffset": "startOffset", + "stddeviation": "stdDeviation", + "stitchtiles": "stitchTiles", + "surfacescale": "surfaceScale", + "systemlanguage": "systemLanguage", + "tablevalues": "tableValues", + "targetx": "targetX", + "targety": "targetY", + "textlength": "textLength", + "viewbox": "viewBox", + "viewtarget": "viewTarget", + "xchannelselector": "xChannelSelector", + "ychannelselector": "yChannelSelector", + "zoomandpan": "zoomAndPan", +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/node.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/node.go new file mode 100644 index 000000000..1350eef22 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/node.go @@ -0,0 +1,225 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "golang.org/x/net/html/atom" +) + +// A NodeType is the type of a Node. +type NodeType uint32 + +const ( + ErrorNode NodeType = iota + TextNode + DocumentNode + ElementNode + CommentNode + DoctypeNode + // RawNode nodes are not returned by the parser, but can be part of the + // Node tree passed to func Render to insert raw HTML (without escaping). + // If so, this package makes no guarantee that the rendered HTML is secure + // (from e.g. Cross Site Scripting attacks) or well-formed. + RawNode + scopeMarkerNode +) + +// Section 12.2.4.3 says "The markers are inserted when entering applet, +// object, marquee, template, td, th, and caption elements, and are used +// to prevent formatting from "leaking" into applet, object, marquee, +// template, td, th, and caption elements". +var scopeMarker = Node{Type: scopeMarkerNode} + +// A Node consists of a NodeType and some Data (tag name for element nodes, +// content for text) and are part of a tree of Nodes. Element nodes may also +// have a Namespace and contain a slice of Attributes. Data is unescaped, so +// that it looks like "a 0 { + return (*s)[i-1] + } + return nil +} + +// index returns the index of the top-most occurrence of n in the stack, or -1 +// if n is not present. +func (s *nodeStack) index(n *Node) int { + for i := len(*s) - 1; i >= 0; i-- { + if (*s)[i] == n { + return i + } + } + return -1 +} + +// contains returns whether a is within s. +func (s *nodeStack) contains(a atom.Atom) bool { + for _, n := range *s { + if n.DataAtom == a && n.Namespace == "" { + return true + } + } + return false +} + +// insert inserts a node at the given index. +func (s *nodeStack) insert(i int, n *Node) { + (*s) = append(*s, nil) + copy((*s)[i+1:], (*s)[i:]) + (*s)[i] = n +} + +// remove removes a node from the stack. It is a no-op if n is not present. +func (s *nodeStack) remove(n *Node) { + i := s.index(n) + if i == -1 { + return + } + copy((*s)[i:], (*s)[i+1:]) + j := len(*s) - 1 + (*s)[j] = nil + *s = (*s)[:j] +} + +type insertionModeStack []insertionMode + +func (s *insertionModeStack) pop() (im insertionMode) { + i := len(*s) + im = (*s)[i-1] + *s = (*s)[:i-1] + return im +} + +func (s *insertionModeStack) top() insertionMode { + if i := len(*s); i > 0 { + return (*s)[i-1] + } + return nil +} diff --git a/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/parse.go b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/parse.go new file mode 100644 index 000000000..2cd12fc81 --- /dev/null +++ b/ql/test/query-tests/Security/CWE-643/vendor/golang.org/x/net/html/parse.go @@ -0,0 +1,2425 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package html + +import ( + "errors" + "fmt" + "io" + "strings" + + a "golang.org/x/net/html/atom" +) + +// A parser implements the HTML5 parsing algorithm: +// https://html.spec.whatwg.org/multipage/syntax.html#tree-construction +type parser struct { + // tokenizer provides the tokens for the parser. + tokenizer *Tokenizer + // tok is the most recently read token. + tok Token + // Self-closing tags like
are treated as start tags, except that + // hasSelfClosingToken is set while they are being processed. + hasSelfClosingToken bool + // doc is the document root element. + doc *Node + // The stack of open elements (section 12.2.4.2) and active formatting + // elements (section 12.2.4.3). + oe, afe nodeStack + // Element pointers (section 12.2.4.4). + head, form *Node + // Other parsing state flags (section 12.2.4.5). + scripting, framesetOK bool + // The stack of template insertion modes + templateStack insertionModeStack + // im is the current insertion mode. + im insertionMode + // originalIM is the insertion mode to go back to after completing a text + // or inTableText insertion mode. + originalIM insertionMode + // fosterParenting is whether new elements should be inserted according to + // the foster parenting rules (section 12.2.6.1). + fosterParenting bool + // quirks is whether the parser is operating in "quirks mode." + quirks bool + // fragment is whether the parser is parsing an HTML fragment. + fragment bool + // context is the context element when parsing an HTML fragment + // (section 12.4). + context *Node +} + +func (p *parser) top() *Node { + if n := p.oe.top(); n != nil { + return n + } + return p.doc +} + +// Stop tags for use in popUntil. These come from section 12.2.4.2. +var ( + defaultScopeStopTags = map[string][]a.Atom{ + "": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template}, + "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext}, + "svg": {a.Desc, a.ForeignObject, a.Title}, + } +) + +type scope int + +const ( + defaultScope scope = iota + listItemScope + buttonScope + tableScope + tableRowScope + tableBodyScope + selectScope +) + +// popUntil pops the stack of open elements at the highest element whose tag +// is in matchTags, provided there is no higher element in the scope's stop +// tags (as defined in section 12.2.4.2). It returns whether or not there was +// such an element. If there was not, popUntil leaves the stack unchanged. +// +// For example, the set of stop tags for table scope is: "html", "table". If +// the stack was: +// ["html", "body", "font", "table", "b", "i", "u"] +// then popUntil(tableScope, "font") would return false, but +// popUntil(tableScope, "i") would return true and the stack would become: +// ["html", "body", "font", "table", "b"] +// +// If an element's tag is in both the stop tags and matchTags, then the stack +// will be popped and the function returns true (provided, of course, there was +// no higher element in the stack that was also in the stop tags). For example, +// popUntil(tableScope, "table") returns true and leaves: +// ["html", "body", "font"] +func (p *parser) popUntil(s scope, matchTags ...a.Atom) bool { + if i := p.indexOfElementInScope(s, matchTags...); i != -1 { + p.oe = p.oe[:i] + return true + } + return false +} + +// indexOfElementInScope returns the index in p.oe of the highest element whose +// tag is in matchTags that is in scope. If no matching element is in scope, it +// returns -1. +func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int { + for i := len(p.oe) - 1; i >= 0; i-- { + tagAtom := p.oe[i].DataAtom + if p.oe[i].Namespace == "" { + for _, t := range matchTags { + if t == tagAtom { + return i + } + } + switch s { + case defaultScope: + // No-op. + case listItemScope: + if tagAtom == a.Ol || tagAtom == a.Ul { + return -1 + } + case buttonScope: + if tagAtom == a.Button { + return -1 + } + case tableScope: + if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { + return -1 + } + case selectScope: + if tagAtom != a.Optgroup && tagAtom != a.Option { + return -1 + } + default: + panic("unreachable") + } + } + switch s { + case defaultScope, listItemScope, buttonScope: + for _, t := range defaultScopeStopTags[p.oe[i].Namespace] { + if t == tagAtom { + return -1 + } + } + } + } + return -1 +} + +// elementInScope is like popUntil, except that it doesn't modify the stack of +// open elements. +func (p *parser) elementInScope(s scope, matchTags ...a.Atom) bool { + return p.indexOfElementInScope(s, matchTags...) != -1 +} + +// clearStackToContext pops elements off the stack of open elements until a +// scope-defined element is found. +func (p *parser) clearStackToContext(s scope) { + for i := len(p.oe) - 1; i >= 0; i-- { + tagAtom := p.oe[i].DataAtom + switch s { + case tableScope: + if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template { + p.oe = p.oe[:i+1] + return + } + case tableRowScope: + if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template { + p.oe = p.oe[:i+1] + return + } + case tableBodyScope: + if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template { + p.oe = p.oe[:i+1] + return + } + default: + panic("unreachable") + } + } +} + +// parseGenericRawTextElements implements the generic raw text element parsing +// algorithm defined in 12.2.6.2. +// https://html.spec.whatwg.org/multipage/parsing.html#parsing-elements-that-contain-only-text +// TODO: Since both RAWTEXT and RCDATA states are treated as tokenizer's part +// officially, need to make tokenizer consider both states. +func (p *parser) parseGenericRawTextElement() { + p.addElement() + p.originalIM = p.im + p.im = textIM +} + +// generateImpliedEndTags pops nodes off the stack of open elements as long as +// the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc. +// If exceptions are specified, nodes with that name will not be popped off. +func (p *parser) generateImpliedEndTags(exceptions ...string) { + var i int +loop: + for i = len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + if n.Type != ElementNode { + break + } + switch n.DataAtom { + case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc: + for _, except := range exceptions { + if n.Data == except { + break loop + } + } + continue + } + break + } + + p.oe = p.oe[:i+1] +} + +// addChild adds a child node n to the top element, and pushes n onto the stack +// of open elements if it is an element node. +func (p *parser) addChild(n *Node) { + if p.shouldFosterParent() { + p.fosterParent(n) + } else { + p.top().AppendChild(n) + } + + if n.Type == ElementNode { + p.oe = append(p.oe, n) + } +} + +// shouldFosterParent returns whether the next node to be added should be +// foster parented. +func (p *parser) shouldFosterParent() bool { + if p.fosterParenting { + switch p.top().DataAtom { + case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr: + return true + } + } + return false +} + +// fosterParent adds a child node according to the foster parenting rules. +// Section 12.2.6.1, "foster parenting". +func (p *parser) fosterParent(n *Node) { + var table, parent, prev, template *Node + var i int + for i = len(p.oe) - 1; i >= 0; i-- { + if p.oe[i].DataAtom == a.Table { + table = p.oe[i] + break + } + } + + var j int + for j = len(p.oe) - 1; j >= 0; j-- { + if p.oe[j].DataAtom == a.Template { + template = p.oe[j] + break + } + } + + if template != nil && (table == nil || j > i) { + template.AppendChild(n) + return + } + + if table == nil { + // The foster parent is the html element. + parent = p.oe[0] + } else { + parent = table.Parent + } + if parent == nil { + parent = p.oe[i-1] + } + + if table != nil { + prev = table.PrevSibling + } else { + prev = parent.LastChild + } + if prev != nil && prev.Type == TextNode && n.Type == TextNode { + prev.Data += n.Data + return + } + + parent.InsertBefore(n, table) +} + +// addText adds text to the preceding node if it is a text node, or else it +// calls addChild with a new text node. +func (p *parser) addText(text string) { + if text == "" { + return + } + + if p.shouldFosterParent() { + p.fosterParent(&Node{ + Type: TextNode, + Data: text, + }) + return + } + + t := p.top() + if n := t.LastChild; n != nil && n.Type == TextNode { + n.Data += text + return + } + p.addChild(&Node{ + Type: TextNode, + Data: text, + }) +} + +// addElement adds a child element based on the current token. +func (p *parser) addElement() { + p.addChild(&Node{ + Type: ElementNode, + DataAtom: p.tok.DataAtom, + Data: p.tok.Data, + Attr: p.tok.Attr, + }) +} + +// Section 12.2.4.3. +func (p *parser) addFormattingElement() { + tagAtom, attr := p.tok.DataAtom, p.tok.Attr + p.addElement() + + // Implement the Noah's Ark clause, but with three per family instead of two. + identicalElements := 0 +findIdenticalElements: + for i := len(p.afe) - 1; i >= 0; i-- { + n := p.afe[i] + if n.Type == scopeMarkerNode { + break + } + if n.Type != ElementNode { + continue + } + if n.Namespace != "" { + continue + } + if n.DataAtom != tagAtom { + continue + } + if len(n.Attr) != len(attr) { + continue + } + compareAttributes: + for _, t0 := range n.Attr { + for _, t1 := range attr { + if t0.Key == t1.Key && t0.Namespace == t1.Namespace && t0.Val == t1.Val { + // Found a match for this attribute, continue with the next attribute. + continue compareAttributes + } + } + // If we get here, there is no attribute that matches a. + // Therefore the element is not identical to the new one. + continue findIdenticalElements + } + + identicalElements++ + if identicalElements >= 3 { + p.afe.remove(n) + } + } + + p.afe = append(p.afe, p.top()) +} + +// Section 12.2.4.3. +func (p *parser) clearActiveFormattingElements() { + for { + if n := p.afe.pop(); len(p.afe) == 0 || n.Type == scopeMarkerNode { + return + } + } +} + +// Section 12.2.4.3. +func (p *parser) reconstructActiveFormattingElements() { + n := p.afe.top() + if n == nil { + return + } + if n.Type == scopeMarkerNode || p.oe.index(n) != -1 { + return + } + i := len(p.afe) - 1 + for n.Type != scopeMarkerNode && p.oe.index(n) == -1 { + if i == 0 { + i = -1 + break + } + i-- + n = p.afe[i] + } + for { + i++ + clone := p.afe[i].clone() + p.addChild(clone) + p.afe[i] = clone + if i == len(p.afe)-1 { + break + } + } +} + +// Section 12.2.5. +func (p *parser) acknowledgeSelfClosingTag() { + p.hasSelfClosingToken = false +} + +// An insertion mode (section 12.2.4.1) is the state transition function from +// a particular state in the HTML5 parser's state machine. It updates the +// parser's fields depending on parser.tok (where ErrorToken means EOF). +// It returns whether the token was consumed. +type insertionMode func(*parser) bool + +// setOriginalIM sets the insertion mode to return to after completing a text or +// inTableText insertion mode. +// Section 12.2.4.1, "using the rules for". +func (p *parser) setOriginalIM() { + if p.originalIM != nil { + panic("html: bad parser state: originalIM was set twice") + } + p.originalIM = p.im +} + +// Section 12.2.4.1, "reset the insertion mode". +func (p *parser) resetInsertionMode() { + for i := len(p.oe) - 1; i >= 0; i-- { + n := p.oe[i] + last := i == 0 + if last && p.context != nil { + n = p.context + } + + switch n.DataAtom { + case a.Select: + if !last { + for ancestor, first := n, p.oe[0]; ancestor != first; { + ancestor = p.oe[p.oe.index(ancestor)-1] + switch ancestor.DataAtom { + case a.Template: + p.im = inSelectIM + return + case a.Table: + p.im = inSelectInTableIM + return + } + } + } + p.im = inSelectIM + case a.Td, a.Th: + // TODO: remove this divergence from the HTML5 spec. + // + // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 + p.im = inCellIM + case a.Tr: + p.im = inRowIM + case a.Tbody, a.Thead, a.Tfoot: + p.im = inTableBodyIM + case a.Caption: + p.im = inCaptionIM + case a.Colgroup: + p.im = inColumnGroupIM + case a.Table: + p.im = inTableIM + case a.Template: + // TODO: remove this divergence from the HTML5 spec. + if n.Namespace != "" { + continue + } + p.im = p.templateStack.top() + case a.Head: + // TODO: remove this divergence from the HTML5 spec. + // + // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 + p.im = inHeadIM + case a.Body: + p.im = inBodyIM + case a.Frameset: + p.im = inFramesetIM + case a.Html: + if p.head == nil { + p.im = beforeHeadIM + } else { + p.im = afterHeadIM + } + default: + if last { + p.im = inBodyIM + return + } + continue + } + return + } +} + +const whitespace = " \t\r\n\f" + +// Section 12.2.6.4.1. +func initialIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case CommentToken: + p.doc.AppendChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + n, quirks := parseDoctype(p.tok.Data) + p.doc.AppendChild(n) + p.quirks = quirks + p.im = beforeHTMLIM + return true + } + p.quirks = true + p.im = beforeHTMLIM + return false +} + +// Section 12.2.6.4.2. +func beforeHTMLIM(p *parser) bool { + switch p.tok.Type { + case DoctypeToken: + // Ignore the token. + return true + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case StartTagToken: + if p.tok.DataAtom == a.Html { + p.addElement() + p.im = beforeHeadIM + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head, a.Body, a.Html, a.Br: + p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) + return false + default: + // Ignore the token. + return true + } + case CommentToken: + p.doc.AppendChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + } + p.parseImpliedToken(StartTagToken, a.Html, a.Html.String()) + return false +} + +// Section 12.2.6.4.3. +func beforeHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + p.tok.Data = strings.TrimLeft(p.tok.Data, whitespace) + if len(p.tok.Data) == 0 { + // It was all whitespace, so ignore it. + return true + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Head: + p.addElement() + p.head = p.top() + p.im = inHeadIM + return true + case a.Html: + return inBodyIM(p) + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head, a.Body, a.Html, a.Br: + p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) + return false + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(StartTagToken, a.Head, a.Head.String()) + return false +} + +// Section 12.2.6.4.4. +func inHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) < len(p.tok.Data) { + // Add the initial whitespace to the current node. + p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) + if s == "" { + return true + } + p.tok.Data = s + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Html: + return inBodyIM(p) + case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta: + p.addElement() + p.oe.pop() + p.acknowledgeSelfClosingTag() + return true + case a.Noscript: + if p.scripting { + p.parseGenericRawTextElement() + return true + } + p.addElement() + p.im = inHeadNoscriptIM + // Don't let the tokenizer go into raw text mode when scripting is disabled. + p.tokenizer.NextIsNotRawText() + return true + case a.Script, a.Title: + p.addElement() + p.setOriginalIM() + p.im = textIM + return true + case a.Noframes, a.Style: + p.parseGenericRawTextElement() + return true + case a.Head: + // Ignore the token. + return true + case a.Template: + p.addElement() + p.afe = append(p.afe, &scopeMarker) + p.framesetOK = false + p.im = inTemplateIM + p.templateStack = append(p.templateStack, inTemplateIM) + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Head: + p.oe.pop() + p.im = afterHeadIM + return true + case a.Body, a.Html, a.Br: + p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) + return false + case a.Template: + if !p.oe.contains(a.Template) { + return true + } + // TODO: remove this divergence from the HTML5 spec. + // + // See https://bugs.chromium.org/p/chromium/issues/detail?id=829668 + p.generateImpliedEndTags() + for i := len(p.oe) - 1; i >= 0; i-- { + if n := p.oe[i]; n.Namespace == "" && n.DataAtom == a.Template { + p.oe = p.oe[:i] + break + } + } + p.clearActiveFormattingElements() + p.templateStack.pop() + p.resetInsertionMode() + return true + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(EndTagToken, a.Head, a.Head.String()) + return false +} + +// 12.2.6.4.5. +func inHeadNoscriptIM(p *parser) bool { + switch p.tok.Type { + case DoctypeToken: + // Ignore the token. + return true + case StartTagToken: + switch p.tok.DataAtom { + case a.Html: + return inBodyIM(p) + case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style: + return inHeadIM(p) + case a.Head, a.Noscript: + // Ignore the token. + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Noscript, a.Br: + default: + // Ignore the token. + return true + } + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) == 0 { + // It was all whitespace. + return inHeadIM(p) + } + case CommentToken: + return inHeadIM(p) + } + p.oe.pop() + if p.top().DataAtom != a.Head { + panic("html: the new current node will be a head element.") + } + p.im = inHeadIM + if p.tok.DataAtom == a.Noscript { + return true + } + return false +} + +// Section 12.2.6.4.6. +func afterHeadIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + s := strings.TrimLeft(p.tok.Data, whitespace) + if len(s) < len(p.tok.Data) { + // Add the initial whitespace to the current node. + p.addText(p.tok.Data[:len(p.tok.Data)-len(s)]) + if s == "" { + return true + } + p.tok.Data = s + } + case StartTagToken: + switch p.tok.DataAtom { + case a.Html: + return inBodyIM(p) + case a.Body: + p.addElement() + p.framesetOK = false + p.im = inBodyIM + return true + case a.Frameset: + p.addElement() + p.im = inFramesetIM + return true + case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title: + p.oe = append(p.oe, p.head) + defer p.oe.remove(p.head) + return inHeadIM(p) + case a.Head: + // Ignore the token. + return true + } + case EndTagToken: + switch p.tok.DataAtom { + case a.Body, a.Html, a.Br: + // Drop down to creating an implied tag. + case a.Template: + return inHeadIM(p) + default: + // Ignore the token. + return true + } + case CommentToken: + p.addChild(&Node{ + Type: CommentNode, + Data: p.tok.Data, + }) + return true + case DoctypeToken: + // Ignore the token. + return true + } + + p.parseImpliedToken(StartTagToken, a.Body, a.Body.String()) + p.framesetOK = true + return false +} + +// copyAttributes copies attributes of src not found on dst to dst. +func copyAttributes(dst *Node, src Token) { + if len(src.Attr) == 0 { + return + } + attr := map[string]string{} + for _, t := range dst.Attr { + attr[t.Key] = t.Val + } + for _, t := range src.Attr { + if _, ok := attr[t.Key]; !ok { + dst.Attr = append(dst.Attr, t) + attr[t.Key] = t.Val + } + } +} + +// Section 12.2.6.4.7. +func inBodyIM(p *parser) bool { + switch p.tok.Type { + case TextToken: + d := p.tok.Data + switch n := p.oe.top(); n.DataAtom { + case a.Pre, a.Listing: + if n.FirstChild == nil { + // Ignore a newline at the start of a
 block.
+				if d != "" && d[0] == '\r' {
+					d = d[1:]
+				}
+				if d != "" && d[0] == '\n' {
+					d = d[1:]
+				}
+			}
+		}
+		d = strings.Replace(d, "\x00", "", -1)
+		if d == "" {
+			return true
+		}
+		p.reconstructActiveFormattingElements()
+		p.addText(d)
+		if p.framesetOK && strings.TrimLeft(d, whitespace) != "" {
+			// There were non-whitespace characters inserted.
+			p.framesetOK = false
+		}
+	case StartTagToken:
+		switch p.tok.DataAtom {
+		case a.Html:
+			if p.oe.contains(a.Template) {
+				return true
+			}
+			copyAttributes(p.oe[0], p.tok)
+		case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
+			return inHeadIM(p)
+		case a.Body:
+			if p.oe.contains(a.Template) {
+				return true
+			}
+			if len(p.oe) >= 2 {
+				body := p.oe[1]
+				if body.Type == ElementNode && body.DataAtom == a.Body {
+					p.framesetOK = false
+					copyAttributes(body, p.tok)
+				}
+			}
+		case a.Frameset:
+			if !p.framesetOK || len(p.oe) < 2 || p.oe[1].DataAtom != a.Body {
+				// Ignore the token.
+				return true
+			}
+			body := p.oe[1]
+			if body.Parent != nil {
+				body.Parent.RemoveChild(body)
+			}
+			p.oe = p.oe[:1]
+			p.addElement()
+			p.im = inFramesetIM
+			return true
+		case a.Address, a.Article, a.Aside, a.Blockquote, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Main, a.Menu, a.Nav, a.Ol, a.P, a.Section, a.Summary, a.Ul:
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
+			p.popUntil(buttonScope, a.P)
+			switch n := p.top(); n.DataAtom {
+			case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
+				p.oe.pop()
+			}
+			p.addElement()
+		case a.Pre, a.Listing:
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+			// The newline, if any, will be dealt with by the TextToken case.
+			p.framesetOK = false
+		case a.Form:
+			if p.form != nil && !p.oe.contains(a.Template) {
+				// Ignore the token
+				return true
+			}
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+			if !p.oe.contains(a.Template) {
+				p.form = p.top()
+			}
+		case a.Li:
+			p.framesetOK = false
+			for i := len(p.oe) - 1; i >= 0; i-- {
+				node := p.oe[i]
+				switch node.DataAtom {
+				case a.Li:
+					p.oe = p.oe[:i]
+				case a.Address, a.Div, a.P:
+					continue
+				default:
+					if !isSpecialElement(node) {
+						continue
+					}
+				}
+				break
+			}
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+		case a.Dd, a.Dt:
+			p.framesetOK = false
+			for i := len(p.oe) - 1; i >= 0; i-- {
+				node := p.oe[i]
+				switch node.DataAtom {
+				case a.Dd, a.Dt:
+					p.oe = p.oe[:i]
+				case a.Address, a.Div, a.P:
+					continue
+				default:
+					if !isSpecialElement(node) {
+						continue
+					}
+				}
+				break
+			}
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+		case a.Plaintext:
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+		case a.Button:
+			p.popUntil(defaultScope, a.Button)
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			p.framesetOK = false
+		case a.A:
+			for i := len(p.afe) - 1; i >= 0 && p.afe[i].Type != scopeMarkerNode; i-- {
+				if n := p.afe[i]; n.Type == ElementNode && n.DataAtom == a.A {
+					p.inBodyEndTagFormatting(a.A, "a")
+					p.oe.remove(n)
+					p.afe.remove(n)
+					break
+				}
+			}
+			p.reconstructActiveFormattingElements()
+			p.addFormattingElement()
+		case a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
+			p.reconstructActiveFormattingElements()
+			p.addFormattingElement()
+		case a.Nobr:
+			p.reconstructActiveFormattingElements()
+			if p.elementInScope(defaultScope, a.Nobr) {
+				p.inBodyEndTagFormatting(a.Nobr, "nobr")
+				p.reconstructActiveFormattingElements()
+			}
+			p.addFormattingElement()
+		case a.Applet, a.Marquee, a.Object:
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			p.afe = append(p.afe, &scopeMarker)
+			p.framesetOK = false
+		case a.Table:
+			if !p.quirks {
+				p.popUntil(buttonScope, a.P)
+			}
+			p.addElement()
+			p.framesetOK = false
+			p.im = inTableIM
+			return true
+		case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			p.oe.pop()
+			p.acknowledgeSelfClosingTag()
+			if p.tok.DataAtom == a.Input {
+				for _, t := range p.tok.Attr {
+					if t.Key == "type" {
+						if strings.ToLower(t.Val) == "hidden" {
+							// Skip setting framesetOK = false
+							return true
+						}
+					}
+				}
+			}
+			p.framesetOK = false
+		case a.Param, a.Source, a.Track:
+			p.addElement()
+			p.oe.pop()
+			p.acknowledgeSelfClosingTag()
+		case a.Hr:
+			p.popUntil(buttonScope, a.P)
+			p.addElement()
+			p.oe.pop()
+			p.acknowledgeSelfClosingTag()
+			p.framesetOK = false
+		case a.Image:
+			p.tok.DataAtom = a.Img
+			p.tok.Data = a.Img.String()
+			return false
+		case a.Textarea:
+			p.addElement()
+			p.setOriginalIM()
+			p.framesetOK = false
+			p.im = textIM
+		case a.Xmp:
+			p.popUntil(buttonScope, a.P)
+			p.reconstructActiveFormattingElements()
+			p.framesetOK = false
+			p.parseGenericRawTextElement()
+		case a.Iframe:
+			p.framesetOK = false
+			p.parseGenericRawTextElement()
+		case a.Noembed:
+			p.parseGenericRawTextElement()
+		case a.Noscript:
+			if p.scripting {
+				p.parseGenericRawTextElement()
+				return true
+			}
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			// Don't let the tokenizer go into raw text mode when scripting is disabled.
+			p.tokenizer.NextIsNotRawText()
+		case a.Select:
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+			p.framesetOK = false
+			p.im = inSelectIM
+			return true
+		case a.Optgroup, a.Option:
+			if p.top().DataAtom == a.Option {
+				p.oe.pop()
+			}
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+		case a.Rb, a.Rtc:
+			if p.elementInScope(defaultScope, a.Ruby) {
+				p.generateImpliedEndTags()
+			}
+			p.addElement()
+		case a.Rp, a.Rt:
+			if p.elementInScope(defaultScope, a.Ruby) {
+				p.generateImpliedEndTags("rtc")
+			}
+			p.addElement()
+		case a.Math, a.Svg:
+			p.reconstructActiveFormattingElements()
+			if p.tok.DataAtom == a.Math {
+				adjustAttributeNames(p.tok.Attr, mathMLAttributeAdjustments)
+			} else {
+				adjustAttributeNames(p.tok.Attr, svgAttributeAdjustments)
+			}
+			adjustForeignAttributes(p.tok.Attr)
+			p.addElement()
+			p.top().Namespace = p.tok.Data
+			if p.hasSelfClosingToken {
+				p.oe.pop()
+				p.acknowledgeSelfClosingTag()
+			}
+			return true
+		case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
+			// Ignore the token.
+		default:
+			p.reconstructActiveFormattingElements()
+			p.addElement()
+		}
+	case EndTagToken:
+		switch p.tok.DataAtom {
+		case a.Body:
+			if p.elementInScope(defaultScope, a.Body) {
+				p.im = afterBodyIM
+			}
+		case a.Html:
+			if p.elementInScope(defaultScope, a.Body) {
+				p.parseImpliedToken(EndTagToken, a.Body, a.Body.String())
+				return false
+			}
+			return true
+		case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
+			p.popUntil(defaultScope, p.tok.DataAtom)
+		case a.Form:
+			if p.oe.contains(a.Template) {
+				i := p.indexOfElementInScope(defaultScope, a.Form)
+				if i == -1 {
+					// Ignore the token.
+					return true
+				}
+				p.generateImpliedEndTags()
+				if p.oe[i].DataAtom != a.Form {
+					// Ignore the token.
+					return true
+				}
+				p.popUntil(defaultScope, a.Form)
+			} else {
+				node := p.form
+				p.form = nil
+				i := p.indexOfElementInScope(defaultScope, a.Form)
+				if node == nil || i == -1 || p.oe[i] != node {
+					// Ignore the token.
+					return true
+				}
+				p.generateImpliedEndTags()
+				p.oe.remove(node)
+			}
+		case a.P:
+			if !p.elementInScope(buttonScope, a.P) {
+				p.parseImpliedToken(StartTagToken, a.P, a.P.String())
+			}
+			p.popUntil(buttonScope, a.P)
+		case a.Li:
+			p.popUntil(listItemScope, a.Li)
+		case a.Dd, a.Dt:
+			p.popUntil(defaultScope, p.tok.DataAtom)
+		case a.H1, a.H2, a.H3, a.H4, a.H5, a.H6:
+			p.popUntil(defaultScope, a.H1, a.H2, a.H3, a.H4, a.H5, a.H6)
+		case a.A, a.B, a.Big, a.Code, a.Em, a.Font, a.I, a.Nobr, a.S, a.Small, a.Strike, a.Strong, a.Tt, a.U:
+			p.inBodyEndTagFormatting(p.tok.DataAtom, p.tok.Data)
+		case a.Applet, a.Marquee, a.Object:
+			if p.popUntil(defaultScope, p.tok.DataAtom) {
+				p.clearActiveFormattingElements()
+			}
+		case a.Br:
+			p.tok.Type = StartTagToken
+			return false
+		case a.Template:
+			return inHeadIM(p)
+		default:
+			p.inBodyEndTagOther(p.tok.DataAtom, p.tok.Data)
+		}
+	case CommentToken:
+		p.addChild(&Node{
+			Type: CommentNode,
+			Data: p.tok.Data,
+		})
+	case ErrorToken:
+		// TODO: remove this divergence from the HTML5 spec.
+		if len(p.templateStack) > 0 {
+			p.im = inTemplateIM
+			return false
+		}
+		for _, e := range p.oe {
+			switch e.DataAtom {
+			case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc, a.Tbody, a.Td, a.Tfoot, a.Th,
+				a.Thead, a.Tr, a.Body, a.Html:
+			default:
+				return true
+			}
+		}
+	}
+
+	return true
+}
+
+func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom, tagName string) {
+	// This is the "adoption agency" algorithm, described at
+	// https://html.spec.whatwg.org/multipage/syntax.html#adoptionAgency
+
+	// TODO: this is a fairly literal line-by-line translation of that algorithm.
+	// Once the code successfully parses the comprehensive test suite, we should
+	// refactor this code to be more idiomatic.
+
+	// Steps 1-2
+	if current := p.oe.top(); current.Data == tagName && p.afe.index(current) == -1 {
+		p.oe.pop()
+		return
+	}
+
+	// Steps 3-5. The outer loop.
+	for i := 0; i < 8; i++ {
+		// Step 6. Find the formatting element.
+		var formattingElement *Node
+		for j := len(p.afe) - 1; j >= 0; j-- {
+			if p.afe[j].Type == scopeMarkerNode {
+				break
+			}
+			if p.afe[j].DataAtom == tagAtom {
+				formattingElement = p.afe[j]
+				break
+			}
+		}
+		if formattingElement == nil {
+			p.inBodyEndTagOther(tagAtom, tagName)
+			return
+		}
+
+		// Step 7. Ignore the tag if formatting element is not in the stack of open elements.
+		feIndex := p.oe.index(formattingElement)
+		if feIndex == -1 {
+			p.afe.remove(formattingElement)
+			return
+		}
+		// Step 8. Ignore the tag if formatting element is not in the scope.
+		if !p.elementInScope(defaultScope, tagAtom) {
+			// Ignore the tag.
+			return
+		}
+
+		// Step 9. This step is omitted because it's just a parse error but no need to return.
+
+		// Steps 10-11. Find the furthest block.
+		var furthestBlock *Node
+		for _, e := range p.oe[feIndex:] {
+			if isSpecialElement(e) {
+				furthestBlock = e
+				break
+			}
+		}
+		if furthestBlock == nil {
+			e := p.oe.pop()
+			for e != formattingElement {
+				e = p.oe.pop()
+			}
+			p.afe.remove(e)
+			return
+		}
+
+		// Steps 12-13. Find the common ancestor and bookmark node.
+		commonAncestor := p.oe[feIndex-1]
+		bookmark := p.afe.index(formattingElement)
+
+		// Step 14. The inner loop. Find the lastNode to reparent.
+		lastNode := furthestBlock
+		node := furthestBlock
+		x := p.oe.index(node)
+		// Step 14.1.
+		j := 0
+		for {
+			// Step 14.2.
+			j++
+			// Step. 14.3.
+			x--
+			node = p.oe[x]
+			// Step 14.4. Go to the next step if node is formatting element.
+			if node == formattingElement {
+				break
+			}
+			// Step 14.5. Remove node from the list of active formatting elements if
+			// inner loop counter is greater than three and node is in the list of
+			// active formatting elements.
+			if ni := p.afe.index(node); j > 3 && ni > -1 {
+				p.afe.remove(node)
+				// If any element of the list of active formatting elements is removed,
+				// we need to take care whether bookmark should be decremented or not.
+				// This is because the value of bookmark may exceed the size of the
+				// list by removing elements from the list.
+				if ni <= bookmark {
+					bookmark--
+				}
+				continue
+			}
+			// Step 14.6. Continue the next inner loop if node is not in the list of
+			// active formatting elements.
+			if p.afe.index(node) == -1 {
+				p.oe.remove(node)
+				continue
+			}
+			// Step 14.7.
+			clone := node.clone()
+			p.afe[p.afe.index(node)] = clone
+			p.oe[p.oe.index(node)] = clone
+			node = clone
+			// Step 14.8.
+			if lastNode == furthestBlock {
+				bookmark = p.afe.index(node) + 1
+			}
+			// Step 14.9.
+			if lastNode.Parent != nil {
+				lastNode.Parent.RemoveChild(lastNode)
+			}
+			node.AppendChild(lastNode)
+			// Step 14.10.
+			lastNode = node
+		}
+
+		// Step 15. Reparent lastNode to the common ancestor,
+		// or for misnested table nodes, to the foster parent.
+		if lastNode.Parent != nil {
+			lastNode.Parent.RemoveChild(lastNode)
+		}
+		switch commonAncestor.DataAtom {
+		case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
+			p.fosterParent(lastNode)
+		default:
+			commonAncestor.AppendChild(lastNode)
+		}
+
+		// Steps 16-18. Reparent nodes from the furthest block's children
+		// to a clone of the formatting element.
+		clone := formattingElement.clone()
+		reparentChildren(clone, furthestBlock)
+		furthestBlock.AppendChild(clone)
+
+		// Step 19. Fix up the list of active formatting elements.
+		if oldLoc := p.afe.index(formattingElement); oldLoc != -1 && oldLoc < bookmark {
+			// Move the bookmark with the rest of the list.
+			bookmark--
+		}
+		p.afe.remove(formattingElement)
+		p.afe.insert(bookmark, clone)
+
+		// Step 20. Fix up the stack of open elements.
+		p.oe.remove(formattingElement)
+		p.oe.insert(p.oe.index(furthestBlock)+1, clone)
+	}
+}
+
+// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
+// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
+// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
+func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) {
+	for i := len(p.oe) - 1; i >= 0; i-- {
+		// Two element nodes have the same tag if they have the same Data (a
+		// string-typed field). As an optimization, for common HTML tags, each
+		// Data string is assigned a unique, non-zero DataAtom (a uint32-typed
+		// field), since integer comparison is faster than string comparison.
+		// Uncommon (custom) tags get a zero DataAtom.
+		//
+		// The if condition here is equivalent to (p.oe[i].Data == tagName).
+		if (p.oe[i].DataAtom == tagAtom) &&
+			((tagAtom != 0) || (p.oe[i].Data == tagName)) {
+			p.oe = p.oe[:i]
+			break
+		}
+		if isSpecialElement(p.oe[i]) {
+			break
+		}
+	}
+}
+
+// Section 12.2.6.4.8.
+func textIM(p *parser) bool {
+	switch p.tok.Type {
+	case ErrorToken:
+		p.oe.pop()
+	case TextToken:
+		d := p.tok.Data
+		if n := p.oe.top(); n.DataAtom == a.Textarea && n.FirstChild == nil {
+			// Ignore a newline at the start of a