1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Don't mangle xml and xpath unless xml is not in fact a well-formed document, in xpath(). If mangling xpath, make a saner attempt where xpath expression does not begin with '/'.

This commit is contained in:
Andrew Dunstan
2009-02-28 19:13:28 +00:00
parent 6c8f478623
commit 69daf2defe

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.68.2.6 2008/11/10 18:02:27 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.68.2.7 2009/02/28 19:13:28 adunstan Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -3320,11 +3320,37 @@ xpath(PG_FUNCTION_ARGS)
xml_init(); xml_init();
/* These extra chars for string and xpath_expr allow for hacks below */
string = (xmlChar *) palloc((len + 8) * sizeof(xmlChar));
xpath_expr = (xmlChar *) palloc((xpath_len + 5) * sizeof(xmlChar));
memcpy (string, datastr, len);
string[len] = '\0';
xmlInitParser();
/* /*
* To handle both documents and fragments, regardless of the fact whether * redundant XML parsing (two parsings for the same value during one
* the XML datum has a single root (XML well-formedness), we wrap the XML * command execution are possible)
* datum in a dummy element (<x>...</x>) and extend the XPath expression */
* accordingly. To do it, throw away the XML prolog, if any. ctxt = xmlNewParserCtxt();
if (ctxt == NULL)
xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
"could not allocate parser context");
doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
if (doc == NULL || xmlDocGetRootElement(doc) == NULL)
{
/*
* In case we have a fragment rather than a well-formed XML document,
* which has a single root (XML well-formedness), we try again after
* transforming the xml by stripping away the XML prolog, if any, and
* wrapping the remainder in a dummy element (<x>...</x>),
* and later extending the XPath expression accordingly.
*/ */
if (len >= 5 && if (len >= 5 &&
xmlStrncmp((xmlChar *) datastr, (xmlChar *) "<?xml", 5) == 0) xmlStrncmp((xmlChar *) datastr, (xmlChar *) "<?xml", 5) == 0)
@ -3344,32 +3370,45 @@ xpath(PG_FUNCTION_ARGS)
len -= i; len -= i;
} }
string = (xmlChar *) palloc((len + 8) * sizeof(xmlChar));
memcpy(string, "<x>", 3); memcpy(string, "<x>", 3);
memcpy(string + 3, datastr, len); memcpy(string + 3, datastr, len);
memcpy(string + 3 + len, "</x>", 5); memcpy(string + 3 + len, "</x>", 5);
len += 7; len += 7;
xpath_expr = (xmlChar *) palloc((xpath_len + 3) * sizeof(xmlChar)); doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
if (doc == NULL)
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
"could not parse XML data");
/* we already know xpath_len > 0 - see above , so this test is safe */
if (*VARDATA(xpath_expr_text) == '/')
{
memcpy(xpath_expr, "/x", 2); memcpy(xpath_expr, "/x", 2);
memcpy(xpath_expr + 2, VARDATA(xpath_expr_text), xpath_len); memcpy(xpath_expr + 2, VARDATA(xpath_expr_text), xpath_len);
xpath_expr[xpath_len + 2] = '\0'; xpath_expr[xpath_len + 2] = '\0';
xpath_len += 2; xpath_len += 2;
}
else
{
memcpy(xpath_expr, "/x//", 4);
memcpy(xpath_expr + 4, VARDATA(xpath_expr_text), xpath_len);
xpath_expr[xpath_len + 4] = '\0';
xpath_len += 4;
}
xmlInitParser(); }
else
{
/* /*
* redundant XML parsing (two parsings for the same value during one * if we didn't need to mangle the XML, we don't need to mangle the
* command execution are possible) * xpath either.
*/ */
ctxt = xmlNewParserCtxt(); memcpy(xpath_expr, VARDATA(xpath_expr_text), xpath_len);
if (ctxt == NULL) xpath_expr[xpath_len] = '\0';
xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY, }
"could not allocate parser context");
doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
if (doc == NULL)
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
"could not parse XML data");
xpathctx = xmlXPathNewContext(doc); xpathctx = xmlXPathNewContext(doc);
if (xpathctx == NULL) if (xpathctx == NULL)
xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY, xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,