keremoge commented on code in PR #14174: URL: https://github.com/apache/apisix/pull/14174#discussion_r4512776869
########## apisix/plugins/soap-signer/xml.lua: ########## @@ -0,0 +1,868 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one or more +-- contributor license agreements. See the NOTICE file distributed with +-- this work for additional information regarding copyright ownership. +-- The ASF licenses this file to You 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. +-- +local ffi = require("ffi") +local jit = require("jit") + +local byte = string.byte +local find = string.find +local gmatch = string.gmatch +local sub = string.sub +local ipairs = ipairs +local table_concat = table.concat +local table_sort = table.sort +local tonumber = tonumber +local type = type + + +ffi.cdef[[ +typedef unsigned char xmlChar; +typedef struct _xmlDoc xmlDoc; +typedef xmlDoc *xmlDocPtr; +typedef struct _xmlParserCtxt xmlParserCtxt; +typedef xmlParserCtxt *xmlParserCtxtPtr; +typedef struct _xmlError xmlError; +typedef xmlError *xmlErrorPtr; +typedef void (*xmlStructuredErrorFunc)(void *userData, xmlErrorPtr error); +typedef struct _xmlSAXHandler xmlSAXHandler; +typedef struct _xmlNode xmlNode; +typedef xmlNode *xmlNodePtr; +typedef struct _xmlNs xmlNs; +typedef xmlNs *xmlNsPtr; +typedef struct _xmlAttr xmlAttr; +typedef xmlAttr *xmlAttrPtr; +typedef struct _xmlNodeSet xmlNodeSet; +typedef xmlNodeSet *xmlNodeSetPtr; +typedef void (*xmlFreeFunc)(void *mem); +extern xmlFreeFunc xmlFree; +]] + +-- FFI types are process-wide: struct bodies must only be declared once, or +-- reloading this module (for example on a plugin hot reload) fails with +-- "attempt to redefine". +if ffi.sizeof("struct _xmlSAXHandler") == nil then + ffi.cdef[[ +struct _xmlSAXHandler { + void *internalSubset; + void *isStandalone; + void *hasInternalSubset; + void *hasExternalSubset; + void *resolveEntity; + void *getEntity; + void *entityDecl; + void *notationDecl; + void *attributeDecl; + void *elementDecl; + void *unparsedEntityDecl; + void *setDocumentLocator; + void *startDocument; + void *endDocument; + void *startElement; + void *endElement; + void *reference; + void *characters; + void *ignorableWhitespace; + void *processingInstruction; + void *comment; + void *warning; + void *error; + void *fatalError; + void *getParameterEntity; + void *cdataBlock; + void *externalSubset; + unsigned int initialized; + void *_private; + void *startElementNs; + void *endElementNs; + xmlStructuredErrorFunc serror; +}; +]] +end + +if ffi.sizeof("struct _xmlParserCtxt") == nil then + ffi.cdef[[ +struct _xmlParserCtxt { + xmlSAXHandler *sax; +}; +]] +end + +if ffi.sizeof("struct _xmlNs") == nil then + ffi.cdef[[ +struct _xmlNs { + xmlNsPtr next; + int type; + const xmlChar *href; + const xmlChar *prefix; + void *_private; + xmlDocPtr context; +}; +]] +end + +if ffi.sizeof("struct _xmlAttr") == nil then + ffi.cdef[[ +struct _xmlAttr { + void *_private; + int type; + const xmlChar *name; + xmlNodePtr children; + xmlNodePtr last; + xmlNodePtr parent; + xmlAttrPtr next; + xmlAttrPtr prev; + xmlDocPtr doc; + xmlNsPtr ns; + int atype; + void *psvi; +}; +]] +end + +if ffi.sizeof("struct _xmlNode") == nil then + ffi.cdef[[ +struct _xmlNode { + void *_private; + int type; + const xmlChar *name; + xmlNodePtr children; + xmlNodePtr last; + xmlNodePtr parent; + xmlNodePtr next; + xmlNodePtr prev; + xmlDocPtr doc; + xmlNsPtr ns; + xmlChar *content; + xmlAttrPtr properties; + xmlNsPtr nsDef; + void *psvi; + unsigned short line; + unsigned short extra; +}; +]] +end + +if ffi.sizeof("struct _xmlError") == nil then + ffi.cdef[[ +struct _xmlError { + int domain; + int code; + char *message; + int level; +}; +]] +end + +ffi.cdef[[ +void xmlInitParser(void); +xmlParserCtxtPtr xmlNewParserCtxt(void); +xmlDocPtr xmlCtxtReadMemory(xmlParserCtxtPtr ctxt, const char *buffer, int size, + const char *URL, const char *encoding, int options); +void xmlFreeParserCtxt(xmlParserCtxtPtr ctxt); +void xmlFreeDoc(xmlDocPtr cur); +xmlNodePtr xmlDocGetRootElement(const xmlDoc *doc); +xmlDocPtr xmlNewDoc(const xmlChar *version); +xmlNodePtr xmlDocCopyNode(xmlNodePtr node, xmlDocPtr doc, int extended); +xmlNodePtr xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root); + +xmlNsPtr xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix); +xmlNsPtr xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *name_space); +xmlNsPtr xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href); +xmlNodePtr xmlNewNode(xmlNsPtr ns, const xmlChar *name); +xmlNodePtr xmlNewChild(xmlNodePtr parent, xmlNsPtr ns, + const xmlChar *name, const xmlChar *content); +xmlNodePtr xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem); +void xmlUnlinkNode(xmlNodePtr cur); +void xmlFreeNode(xmlNodePtr cur); + +xmlAttrPtr xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, + const xmlChar *name, const xmlChar *value); +xmlAttrPtr xmlSetProp(xmlNodePtr node, const xmlChar *name, + const xmlChar *value); +xmlChar *xmlGetNsProp(const xmlNodePtr node, const xmlChar *name, + const xmlChar *name_space); +xmlChar *xmlGetNoNsProp(const xmlNodePtr node, const xmlChar *name); +xmlChar *xmlGetProp(const xmlNodePtr node, const xmlChar *name); +xmlChar *xmlNodeGetContent(const xmlNodePtr cur); +int xmlValidateNCName(const xmlChar *value, int space); + +int xmlC14NDocDumpMemory(xmlDocPtr doc, xmlNodeSetPtr nodes, + int mode, xmlChar **inclusive_ns_prefixes, + int with_comments, xmlChar **doc_txt_ptr); +void xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr, + int *doc_txt_len, const char *txt_encoding); +]] + +local loaded, C = pcall(ffi.load, "xml2") +if not loaded then + local lib + loaded, lib = pcall(ffi.load, "libxml2.so.2") + if not loaded then + error("libxml2 is not available, install the libxml2 package " + .. "(for example `apt-get install -y libxml2`): " .. tostring(lib), 0) + end + C = lib +end +C.xmlInitParser() + +local XML_ELEMENT_NODE = 1 +local XML_TEXT_NODE = 3 +local XML_CDATA_SECTION_NODE = 4 +local XML_DTD_NODE = 14 +local XML_ERR_ERROR = 2 +local XML_PARSE_NONET = 2048 +local XML_PARSE_NOERROR = 32 +local XML_PARSE_NOWARNING = 64 +local EXCLUSIVE_C14N = 1 +local XML_ID_NAMESPACE = "http://www.w3.org/XML/1998/namespace" +local WSU_ID_NAMESPACE = "http://docs.oasis-open.org/wss/2004/01/" + .. "oasis-200401-wss-wssecurity-utility-1.0.xsd" + +local DTD_ERROR = "DTD and entity declarations are not allowed" + +-- libxml2 2.9 (the version in Debian bookworm based APISIX images) compares +-- every attribute of an element with the ones before it and resolves every +-- element and attribute name against all namespace declarations in scope. +-- Many attributes on one element, or many namespace declarations in scope, +-- therefore cost super-linear CPU time while the NGINX worker is blocked. +-- Reject such documents before they reach the parser; real documents stay +-- far below these limits. +local MAX_ATTRIBUTES_PER_ELEMENT = 256 +local MAX_NAMESPACES_IN_SCOPE = 128 +-- The shortest possible attribute is 5 bytes (` a=""`), so only a markup +-- segment longer than this can hold too many attributes. +local MIN_SUSPICIOUS_SEGMENT = MAX_ATTRIBUTES_PER_ELEMENT * 5 +local ATTRIBUTE_PATTERN = "%s[^%s=<>\"']+%s*=%s*[\"']" +local NAMESPACE_DECLARATION_PATTERN = "%sxmlns[%s:=]" + +local _M = {} + + +local function xml_char(value) + if value == nil then + return nil + end + return ffi.cast("const xmlChar *", value) +end + + +local function copy_and_free(value) + if value == nil then + return nil + end + local result = ffi.string(value) + C.xmlFree(value) + return result +end + + +local function count_plain(value, needle, first, last, limit) + local count = 0 + local position = first + while count <= limit do + local found = find(value, needle, position, true) + if not found or found > last then + break + end + count = count + 1 + position = found + 1 + end Review Comment: fixed on https://github.com/apache/apisix/pull/14174/changes/b04c7e75249dcb3b780e01fdf5e2aa9eba7d8745 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
