# HG changeset patch # User joehw # Date 1549389455 28800 # Node ID 5d95a8dbb6e4fc5983f9f358717b464ce4ac2575 # Parent 1126811a5124f7408951734d834f6226514fd69e 8206132: DOM parser does not honor DocumentBuilderFactory.setExpandEntityReferences(false) Reviewed-by: rriggs, lancea diff -r 1126811a5124 -r 5d95a8dbb6e4 src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java Tue Feb 05 09:56:19 2019 -0800 +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLDocumentFragmentScannerImpl.java Tue Feb 05 09:57:35 2019 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. */ /* @@ -73,7 +73,7 @@ * @author Eric Ye, IBM * @author Sunitha Reddy, SUN Microsystems * - * @LastModified: Sep 2017 + * @LastModified: Jan 2019 */ public class XMLDocumentFragmentScannerImpl extends XMLScanner @@ -163,6 +163,10 @@ protected static final String STANDARD_URI_CONFORMANT = Constants.XERCES_FEATURE_PREFIX +Constants.STANDARD_URI_CONFORMANT_FEATURE; + /** Feature id: create entity ref nodes. */ + protected static final String CREATE_ENTITY_REF_NODES = + Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE; + /** Property identifier: Security property manager. */ private static final String XML_SECURITY_PROPERTY_MANAGER = Constants.XML_SECURITY_PROPERTY_MANAGER; @@ -322,6 +326,9 @@ /** Xerces Feature: Disallow doctype declaration. */ protected boolean fDisallowDoctype = false; + /** Create entity reference nodes. */ + protected boolean fCreateEntityRefNodes = false; + /** * CDATA chunk size limit */ @@ -596,6 +603,8 @@ fSecurityManager = (XMLSecurityManager)componentManager.getProperty(Constants.SECURITY_MANAGER, null); fNotifyBuiltInRefs = componentManager.getFeature(NOTIFY_BUILTIN_REFS, false); + fCreateEntityRefNodes = componentManager.getFeature(CREATE_ENTITY_REF_NODES, fCreateEntityRefNodes); + Object resolver = componentManager.getProperty(ENTITY_RESOLVER, null); fExternalSubsetResolver = (resolver instanceof ExternalSubsetResolver) ? (ExternalSubsetResolver) resolver : null; @@ -1837,14 +1846,20 @@ } else reportFatalError("EntityNotDeclared", new Object[]{name}); } - //we are starting the entity even if the entity was not declared - //if that was the case it its taken care in XMLEntityManager.startEntity() - //we immediately call the endEntity. Application gets to know if there was - //any entity that was not declared. - fEntityManager.startEntity(true, name, false); - //set the scaner state to content.. parser will automatically revive itself at any point of time. - //setScannerState(SCANNER_STATE_CONTENT); - //return true ; + + // create EntityReference only + if (fCreateEntityRefNodes) { + fDocumentHandler.startGeneralEntity(name, null, null, null); + } else { + //we are starting the entity even if the entity was not declared + //if that was the case it its taken care in XMLEntityManager.startEntity() + //we immediately call the endEntity. Application gets to know if there was + //any entity that was not declared. + fEntityManager.startEntity(true, name, false); + //set the scaner state to content.. parser will automatically revive itself at any point of time. + //setScannerState(SCANNER_STATE_CONTENT); + //return true ; + } } // scanEntityReference() // utility methods diff -r 1126811a5124 -r 5d95a8dbb6e4 src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractDOMParser.java --- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractDOMParser.java Tue Feb 05 09:56:19 2019 -0800 +++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractDOMParser.java Tue Feb 05 09:57:35 2019 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2019 Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -84,7 +84,7 @@ * @author Andy Clark, IBM * @author Elena Litani, IBM * - * @LastModified: Nov 2017 + * @LastModified: Jan 2019 */ public class AbstractDOMParser extends AbstractXMLDocumentParser { @@ -491,8 +491,10 @@ if (DEBUG_EVENTS) { System.out.println ("==>startGeneralEntity ("+name+")"); if (DEBUG_BASEURI) { - System.out.println (" expandedSystemId( **baseURI): "+identifier.getExpandedSystemId ()); - System.out.println (" baseURI:"+ identifier.getBaseSystemId ()); + System.out.println (" expandedSystemId( **baseURI): " + + identifier == null ? null : identifier.getExpandedSystemId()); + System.out.println (" baseURI:" + + identifier == null ? null : identifier.getBaseSystemId()); } } @@ -512,7 +514,7 @@ EntityReferenceImpl erImpl =(EntityReferenceImpl)er; // set base uri - erImpl.setBaseURI (identifier.getExpandedSystemId ()); + erImpl.setBaseURI (identifier == null ? null : identifier.getExpandedSystemId()); if (fDocumentType != null) { // set actual encoding NamedNodeMap entities = fDocumentType.getEntities (); @@ -528,12 +530,17 @@ } fInEntityRef = true; fCurrentNode.appendChild (er); - fCurrentNode = er; + + if (!fCreateEntityRefNodes) { + fCurrentNode = er; + } else { + ((NodeImpl)er).setReadOnly (true, true); + } } else { - int er = - fDeferredDocumentImpl.createDeferredEntityReference (name, identifier.getExpandedSystemId ()); + int er = fDeferredDocumentImpl.createDeferredEntityReference (name, + identifier == null ? null : identifier.getExpandedSystemId ()); if (fDocumentTypeIndex != -1) { // find corresponding Entity decl int node = fDeferredDocumentImpl.getLastChild (fDocumentTypeIndex, false); @@ -552,7 +559,10 @@ } } fDeferredDocumentImpl.appendChild (fCurrentNodeIndex, er); - fCurrentNodeIndex = er; + + if (!fCreateEntityRefNodes) { + fCurrentNodeIndex = er; + } } } // startGeneralEntity(String,XMLResourceIdentifier, Augmentations) diff -r 1126811a5124 -r 5d95a8dbb6e4 test/jaxp/javax/xml/jaxp/unittest/dom/DOMFeatureTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jaxp/javax/xml/jaxp/unittest/dom/DOMFeatureTest.java Tue Feb 05 09:57:35 2019 -0800 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package dom; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Listeners; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.SAXException; + +/* + * @test + * @bug 8206132 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng dom.DOMFeatureTest + * @summary Tests DOM features. + */ +@Listeners({jaxp.library.BasePolicy.class}) +public class DOMFeatureTest { + + private static final String XML1 = "\n" + + "\n" + + " \n" + + " \n" + + "]>\n" + + "\n" + + " &author;\n" + + ""; + + private static final String XML2 = "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + "]>\n" + + "\n" + + " &author; Hamlet<chapter>Chapter 1</chapter>\n" + + ""; + + private static final String XML3 = "\n" + + "" + + " \n" + + " \n" + + " \n" + + "]>\n" + + "\n" + + " &author; Hamlet<chapter>Chapter 1</chapter>\n" + + ""; + + /* + * DataProvider: for testing the EntityExpansion feature + * Data columns: case number, feature setting (true/false), xml file, + * number of nodes expected, text content expected, element if any + */ + @DataProvider(name = "EntityExpansion") + Object[][] getData() throws Exception { + return new Object[][]{ + {1, true, XML1, 1, "William Shakespeare", null}, + {2, true, XML2, 2, "William Shakespeare Hamlet", "chapter"}, + {3, false, XML1, 1, null, null}, + {4, false, XML2, 3, " Hamlet", "chapter"}, + {4, false, XML3, 3, " Hamlet", "chapter"}, + }; + } + + /* + * DataProvider: for testing the EntityExpansion feature + * Data columns: feature setting (true/false), xml file + */ + @DataProvider(name = "EntityExpansion1") + Object[][] getData1() throws Exception { + return new Object[][]{ + {true, XML3}, + }; + } + /** + * Verifies the EntityExpansion feature. + * @param caseNo the case number + * @param feature flag indicating the setting of the feature + * @param xml the XML string + * @param n the number of nodes expected + * @param expectedText expected Text string + * @param expectedElement expected Element + * @throws Exception + */ + @Test(dataProvider = "EntityExpansion") + public void testEntityExpansion(int caseNo, boolean feature, String xml, + int n, String expectedText, String expectedElement) throws Exception { + final Document doc = getDocument(feature, xml); + final Element e = (Element) doc.getElementsByTagName("title").item(0); + final NodeList nl = e.getChildNodes(); + + switch (caseNo) { + case 1: + // The DOM tree should contain just the Text node + Assert.assertTrue(nl.item(0) instanceof Text); + Assert.assertEquals(nl.item(0).getNodeValue(), expectedText); + Assert.assertEquals(nl.getLength(), n); + break; + case 2: + // The DOM tree contains the Text node and an Element (chapter) + Assert.assertTrue(nl.item(0) instanceof Text); + Assert.assertEquals(nl.item(0).getNodeValue(), expectedText); + Assert.assertTrue(nl.item(1) instanceof Element); + Assert.assertEquals(nl.item(1).getNodeName(), expectedElement); + Assert.assertEquals(nl.getLength(), n); + break; + case 3: + // The DOM tree contains just the EntityReference node + Assert.assertTrue(nl.item(0) instanceof EntityReference); + Assert.assertEquals(nl.item(0).getNodeValue(), null); + Assert.assertEquals(nl.getLength(), n); + break; + case 4: + // The DOM tree contains a EntityReference, Text and an Element + Assert.assertTrue(nl.item(0) instanceof EntityReference); + Assert.assertEquals(nl.item(0).getNodeValue(), null); + Assert.assertTrue(nl.item(1) instanceof Text); + Assert.assertEquals(nl.item(1).getNodeValue(), expectedText); + Assert.assertTrue(nl.item(2) instanceof Element); + Assert.assertEquals(nl.item(2).getNodeName(), expectedElement); + Assert.assertEquals(nl.getLength(), n); + break; + } + } + + /** + * Verifies the EntityExpansion feature. When the feature is set to true, the + * parser will attempt to resolve the external reference, that in turn will + * result in an Exception. + * @param feature flag indicating the setting of the feature + * @param xml the XML string + * @throws Exception: when a non-existent external reference is encountered + */ + @Test(dataProvider = "EntityExpansion1", expectedExceptions = java.net.UnknownHostException.class) + public void testEntityExpansion1(boolean feature, String xml) + throws Exception { + final Document doc = getDocument(feature, xml); + final Element e = (Element) doc.getElementsByTagName("title").item(0); + final NodeList nl = e.getChildNodes(); + } + + private static Document getDocument(boolean expand, String xml) + throws SAXException, IOException, ParserConfigurationException { + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setExpandEntityReferences(expand); + + final DocumentBuilder docBuilder = dbf.newDocumentBuilder(); + + InputStream a = new ByteArrayInputStream(xml.getBytes()); + Document out = docBuilder.parse(a); + return out; + } +} diff -r 1126811a5124 -r 5d95a8dbb6e4 test/jaxp/javax/xml/jaxp/unittest/dom/ElementTraversal.java --- a/test/jaxp/javax/xml/jaxp/unittest/dom/ElementTraversal.java Tue Feb 05 09:56:19 2019 -0800 +++ b/test/jaxp/javax/xml/jaxp/unittest/dom/ElementTraversal.java Tue Feb 05 09:57:35 2019 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,7 +125,6 @@ Document doc = null; try { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setExpandEntityReferences(false); DocumentBuilder db = dbf.newDocumentBuilder(); doc = db.parse(xmlFile); } catch (ParserConfigurationException | SAXException | IOException e) { diff -r 1126811a5124 -r 5d95a8dbb6e4 test/jaxp/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java --- a/test/jaxp/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java Tue Feb 05 09:56:19 2019 -0800 +++ b/test/jaxp/javax/xml/jaxp/unittest/dom/ls/LSSerializerTest.java Tue Feb 05 09:57:35 2019 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,7 @@ import javax.xml.parsers.ParserConfigurationException; import org.testng.Assert; +import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.w3c.dom.DOMError; @@ -52,7 +53,7 @@ /* * @test - * @bug 8080906 8114834 + * @bug 8080906 8114834 8206132 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm -DrunSecMngr=true dom.ls.LSSerializerTest * @run testng/othervm dom.ls.LSSerializerTest @@ -225,31 +226,111 @@ Assert.assertEquals(XML11_DOCUMENT_OUTPUT, defaultSerialization, "Invalid serialization of XML 1.1 document: "); } + // XML source + private static final String XML = + "\n" + + "" + + " " + + " " + + "text\">" + + " " + + " " + + " ]>" + + " &name1;" + + "b &name2; &name1; b" + + " &name; " + + "&ele1;d" + + " &ele2;eee " + + "<att>" + + " &ele; g" + + "&ele2;" ; + + // result when "entities" = true, equvalent to setting ExpandEntityReference to false + private static final String RESULT_TRUE = + "\n" + + "\n" + + "\n" + + "text'>\n" + + "\n" + + "\n" + + "]>\n" + + "\n" + + " &name1;\n" + + " b &name2;&name1; b\n" + + " &name;\n" + + " &ele1;d\n" + + " &ele2;eee \n" + + " <att>\n" + + " &ele; g\n" + + " &ele2;\n" + + "\n"; + + // result when "entities" = false, equvalent to setting ExpandEntityReference to true + private static final String RESULT_FALSE = + "\n" + + "\n" + + "\n" + + "text'>\n" + + "\n" + + "\n" + + "]>\n" + + "\n" + + " Jo Smith\n" + + " b Jo Smith Jo Smith b\n" + + " Jo Smith \n" + + " \n" + + " \n" + + " text\n" + + " \n" + + " d\n" + + " \n" + + " \n" + + " \n" + + " text\n" + + " \n" + + " eee \n" + + " \n" + + " <att>\n" + + " \n" + + " \n" + + " text\n" + + " \n" + + " g\n" + + " \n" + + " \n" + + " \n" + + " text\n" + + " \n" + + " \n" + + "\n"; + /* - * @bug 8114834 test entity reference, nested entity reference when entities - * is true and false + * DataProvider: for testing the entities parameter + * Data columns: xml source, entities setting, expected result */ - @Test - public void testEntityReference() throws Exception { - final String XML_DOCUMENT = "\n" + - "" + - " " + - " " + - "text\">" + - " " + - " " + - " ]>" + - " &name1;" + - "b &name2; &name1; b" + - " &name; " + - "&ele1;d" + - " &ele2;eee " + - "<att>" + - " &ele; g" + - "&ele2;" ; + @DataProvider(name = "entities") + Object[][] getData() throws Exception { + return new Object[][]{ + {XML, Boolean.TRUE, RESULT_TRUE}, + {XML, Boolean.FALSE, RESULT_FALSE}, + }; + } - + /** + * Tests serializing DOM Document with DOMConfiguration's "entities" parameter. + * + * @param source the XML source + * @param entities the entities parameter setting + * @param expected expected string result + * @throws Exception + * @bug 8114834 8206132 + */ + @Test(dataProvider = "entities") + public void testEntityReference(String source, Boolean entities, String expected) + throws Exception { DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); @@ -257,76 +338,18 @@ DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementation; LSParser domParser = domImplementationLS.createLSParser(MODE_SYNCHRONOUS, null); - domParser.getDomConfig().setParameter("entities", Boolean.TRUE); + domParser.getDomConfig().setParameter("entities", entities); LSInput src = domImplementationLS.createLSInput(); - src.setStringData(XML_DOCUMENT); + src.setStringData(source); Document document = domParser.parse(src); LSSerializer lsSerializer = domImplementationLS.createLSSerializer(); - lsSerializer.getDomConfig().setParameter("format-pretty-print", true); - System.out.println("test with default entities is " + lsSerializer.getDomConfig().getParameter("entities")); - Assert.assertEquals(lsSerializer.writeToString(document), - "\n" + - "\n" + - "\n" + - "text'>\n" + - "\n" + - "\n" + - "]>\n" + - "\n" + - " &name1;Jo Smith\n" + - " b &name2;Jo Smith &name1;Jo Smith b\n" + - " &name;Jo Smith \n" + - " &ele1;d\n" + - " &ele2;eee \n" + - " <att>\n" + - " &ele; g\n" + - " &ele2;\n" + - "\n"); + System.out.println("test with default entities is " + + lsSerializer.getDomConfig().getParameter("entities")); - lsSerializer.getDomConfig().setParameter("entities", Boolean.FALSE); - System.out.println("test with entities is false"); - Assert.assertEquals(lsSerializer.writeToString(document), - "\n" + - "\n" + - "\n" + - "text'>\n" + - "\n" + - "\n" + - "]>\n" + - "\n" + - " &name;Jo Smith\n" + - " b &name;Jo Smith &name;Jo Smith b\n" + - " &name;Jo Smith \n" + - " \n" + - " \n" + - " text\n" + - " \n" + - " d\n" + - " \n" + - " \n" + - " \n" + - " text\n" + - " \n" + - " eee \n" + - " \n" + - " <att>\n" + - " \n" + - " \n" + - " text\n" + - " \n" + - " g\n" + - " \n" + - " \n" + - " \n" + - " text\n" + - " \n" + - " \n" + - "\n"); - + String result = lsSerializer.writeToString(document); + Assert.assertEquals(result, expected); } }