1 /*
   2  * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package parsers;
  24 
  25 import java.io.ByteArrayInputStream;
  26 import java.io.StringReader;
  27 import javax.xml.parsers.DocumentBuilder;
  28 import javax.xml.parsers.DocumentBuilderFactory;
  29 import javax.xml.parsers.ParserConfigurationException;
  30 import javax.xml.parsers.SAXParser;
  31 import javax.xml.parsers.SAXParserFactory;
  32 import javax.xml.stream.XMLInputFactory;
  33 import javax.xml.stream.XMLStreamReader;
  34 import org.testng.Assert;
  35 import static org.testng.Assert.assertEquals;
  36 import org.testng.annotations.DataProvider;
  37 import org.testng.annotations.Listeners;
  38 import org.testng.annotations.Test;
  39 import org.w3c.dom.Document;
  40 import org.w3c.dom.ls.DOMImplementationLS;
  41 import org.w3c.dom.ls.LSSerializer;
  42 import org.xml.sax.Attributes;
  43 import org.xml.sax.InputSource;
  44 import org.xml.sax.SAXException;
  45 import org.xml.sax.helpers.DefaultHandler;
  46 
  47 /**
  48  * @test
  49  * @bug 8169450 8222415 8219692
  50  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
  51  * @run testng/othervm -DrunSecMngr=true parsers.BaseParsingTest
  52  * @run testng/othervm parsers.BaseParsingTest
  53  * @summary Tests that verify base parsing
  54  */
  55 @Listeners({jaxp.library.BasePolicy.class})
  56 public class BaseParsingTest {
  57     private static final String DOM_IMPL =
  58             "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl";
  59     private static final String SAX_IMPL =
  60             "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl";
  61 
  62     String xml_8219692 = "<a "
  63             + "xmlns=\"http://openjdk_java_net/xml/defaultNS\" "
  64             + "xmlns:p1=\"http://openjdk_java_net/xml/serializer/\">"
  65             + "<b>in default namespace</b></a>";
  66 
  67     /**
  68      * Creates NamespaceAware parsers using old and new factory methods.
  69      * @return NamespaceAware parsers
  70      * @throws ParserConfigurationException
  71      */
  72     @DataProvider(name = "NSAwareDOMFactory")
  73     public static Object[][] getNSDOMFactory() throws Exception {
  74         boolean isNSAware = true;
  75 
  76         return new Object[][]{
  77             {getDOMParser(DocumentBuilderFactory.newDefaultInstance(), isNSAware)},
  78             {getDOMParser(DocumentBuilderFactory.newInstance(), isNSAware)},
  79             {getDOMParser(DocumentBuilderFactory.newInstance(DOM_IMPL, null), isNSAware)},
  80             // using the new methods
  81             {DocumentBuilderFactory.newDefaultNSInstance().newDocumentBuilder()},
  82             {DocumentBuilderFactory.newNSInstance().newDocumentBuilder()},
  83             {DocumentBuilderFactory.newNSInstance(DOM_IMPL, null).newDocumentBuilder()}
  84         };
  85     }
  86 
  87     /**
  88      * Creates parsers using the old instance methods. By default, they are
  89      * not Namespace Aware.
  90      * @return non-NamespaceAware parsers
  91      * @throws ParserConfigurationException
  92      */
  93     @DataProvider(name = "DOMFactory")
  94     public static Object[][] getDOMFactory() throws Exception {
  95         boolean isNSAware = false;
  96 
  97         return new Object[][]{
  98             {getDOMParser(DocumentBuilderFactory.newDefaultInstance(), isNSAware)},
  99             {getDOMParser(DocumentBuilderFactory.newInstance(), isNSAware)},
 100             {getDOMParser(DocumentBuilderFactory.newInstance(DOM_IMPL, null), isNSAware)}
 101         };
 102     }
 103 
 104 
 105     /**
 106      * Creates NamespaceAware parsers using old and new factory methods.
 107      * @return NamespaceAware parsers
 108      * @throws ParserConfigurationException
 109      */
 110     @DataProvider(name = "NSAwareSAXFactory")
 111     public static Object[][] getNSSAXFactory() throws Exception {
 112         boolean isNSAware = true;
 113 
 114         return new Object[][]{
 115             {getSAXParser(SAXParserFactory.newDefaultInstance(), isNSAware)},
 116             {getSAXParser(SAXParserFactory.newInstance(), isNSAware)},
 117             {getSAXParser(SAXParserFactory.newInstance(SAX_IMPL, null), isNSAware)},
 118             // using the new methods
 119             {SAXParserFactory.newDefaultNSInstance().newSAXParser()},
 120             {SAXParserFactory.newNSInstance().newSAXParser()},
 121             {SAXParserFactory.newNSInstance(SAX_IMPL, null).newSAXParser()},
 122         };
 123     }
 124 
 125     @DataProvider(name = "SAXFactory")
 126     public static Object[][] getSAXFactory() throws Exception {
 127         boolean isNSAware = false;
 128 
 129         return new Object[][]{
 130             {getSAXParser(SAXParserFactory.newDefaultInstance(), isNSAware)},
 131             {getSAXParser(SAXParserFactory.newInstance(), isNSAware)},
 132             {getSAXParser(SAXParserFactory.newInstance(SAX_IMPL, null), isNSAware)},
 133         };
 134     }
 135 
 136     @DataProvider(name = "xmlDeclarations")
 137     public static Object[][] xmlDeclarations() {
 138         return new Object[][]{
 139             {"<?xml version=\"1.0\"?><root><test>t</test></root>"},
 140             {"<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><test>t</test></root>"},
 141             {"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone='yes'?><root><test>t</test></root>"},
 142             {"<?xml\n"
 143                 + " version=\"1.0\"?>\n"
 144                 + "<root>\n"
 145                 + " <test>t</test>\n"
 146                 + "</root>"},
 147             {"<?xml\n"
 148                 + " version=\"1.0\"\n"
 149                 + " encoding=\"UTF-8\"?>\n"
 150                 + "<root>\n"
 151                 + " <test>t</test>\n"
 152                 + "</root>"},
 153             {"<?xml\n"
 154                 + " version=\"1.0\"\n"
 155                 + " encoding=\"UTF-8\"\n"
 156                 + " standalone=\"yes\"?>\n"
 157                 + "<root>\n"
 158                 + " <test>t</test>\n"
 159                 + "</root>"},
 160             {"<?xml\n"
 161                 + " version\n"
 162                 + "=\n"
 163                 + "\"1.0\"\n"
 164                 + " encoding\n"
 165                 + "=\n"
 166                 + "\"UTF-8\"\n"
 167                 + " standalone\n"
 168                 + "=\n"
 169                 + "\"yes\"?>\n"
 170                 + "<root>\n"
 171                 + " <test>t</test>\n"
 172                 + "</root>"},
 173             {"<?xml version=\"1.1\"?><root><test>t</test></root>"},
 174             {"<?xml version=\"1.1\" encoding=\"UTF-8\"?><root><test>t</test></root>"},
 175             {"<?xml version=\"1.1\" encoding=\"UTF-8\" standalone='yes'?><root><test>t</test></root>"},
 176             {"<?xml\n"
 177                 + " version=\"1.1\"?>\n"
 178                 + "<root>\n"
 179                 + " <test>t</test>\n"
 180                 + "</root>"},
 181             {"<?xml\n"
 182                 + " version=\"1.1\"\n"
 183                 + " encoding=\"UTF-8\"?>\n"
 184                 + "<root>\n"
 185                 + " <test>t</test>\n"
 186                 + "</root>"},
 187             {"<?xml\n"
 188                 + " version=\"1.1\"\n"
 189                 + " encoding=\"UTF-8\"\n"
 190                 + " standalone=\"yes\"?>\n"
 191                 + "<root>\n"
 192                 + " <test>t</test>\n"
 193                 + "</root>"},
 194             {"<?xml\n"
 195                 + " version\n"
 196                 + "=\n"
 197                 + "\"1.1\"\n"
 198                 + " encoding\n"
 199                 + "=\n"
 200                 + "\"UTF-8\"\n"
 201                 + " standalone\n"
 202                 + "=\n"
 203                 + "\"yes\"?>\n"
 204                 + "<root>\n"
 205                 + " <test>t</test>\n"
 206                 + "</root>"}
 207         };
 208     }
 209 
 210     /**
 211      * @bug 8169450
 212      * Verifies that the parser successfully parses the declarations provided in
 213      * xmlDeclarations. Exception would otherwise be thrown as reported in 8169450.
 214      *
 215      * XML Declaration according to https://www.w3.org/TR/REC-xml/#NT-XMLDecl
 216      * [23] XMLDecl     ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
 217      * [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
 218      * [25] Eq          ::= S? '=' S? [26] VersionNum ::= '1.' [0-9]+
 219      *
 220      * @param xml the test xml
 221      * @throws Exception if the parser fails to parse the xml
 222      */
 223     @Test(dataProvider = "xmlDeclarations")
 224     public void test(String xml) throws Exception {
 225         XMLInputFactory xif = XMLInputFactory.newDefaultFactory();
 226         XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(xml));
 227         while (xsr.hasNext()) {
 228             xsr.next();
 229         }
 230     }
 231 
 232     /**
 233      * @bug 8169450
 234      * This particular issue does not appear in DOM parsing since the spaces are
 235      * normalized during version detection. This test case then serves as a guard
 236      * against such an issue from occurring in the version detection.
 237      *
 238      * @param xml the test xml
 239      * @throws Exception if the parser fails to parse the xml
 240      */
 241     @Test(dataProvider = "xmlDeclarations")
 242     public void testWithDOM(String xml) throws Exception {
 243         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 244         DocumentBuilder db = dbf.newDocumentBuilder();
 245         db.parse(new InputSource(new StringReader(xml)));
 246     }
 247 
 248     /**
 249      * @bug 8222415
 250      * Verifies that the parser is configured properly for UTF-16BE or LE.
 251      * @throws Exception
 252      */
 253     @Test
 254     public void testEncoding() throws Exception {
 255         ByteArrayInputStream bis = new ByteArrayInputStream(
 256                 "<?xml version=\"1.0\" encoding=\"UTF-16\"?> <a/>".getBytes("UnicodeLittle"));
 257         InputSource is = new InputSource(bis);
 258         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 259         DocumentBuilder db = dbf.newDocumentBuilder();
 260 
 261         Document doc = db.parse(is);
 262         assertEquals("UTF-16LE", doc.getInputEncoding());
 263     }
 264 
 265     /**
 266      * @bug 8219692
 267      * Verifies that the default namespace declaration is preserved when
 268      * NamespaceAware is set on the parser.
 269      * @throws Exception
 270      */
 271     @Test(dataProvider = "NSAwareDOMFactory")
 272     public void testNSAwareDOMFactory(DocumentBuilder db) throws Exception {
 273         LSSerializer ls = getSerializer(db);
 274         String out = ls.writeToString(getDoc(db, xml_8219692));
 275         System.out.println(out);
 276         Assert.assertTrue(out.contains("http://openjdk_java_net/xml/defaultNS"));
 277     }
 278 
 279     /**
 280      * @bug 8219692
 281      * Verifies that the default namespace declaration is missing when the
 282      * old factory methods are used.
 283      * @throws Exception
 284      */
 285     @Test(dataProvider = "DOMFactory")
 286     public void testDOMFactory(DocumentBuilder db) throws Exception {
 287         LSSerializer ls = getSerializer(db);
 288         String out = ls.writeToString(getDoc(db, xml_8219692));
 289         System.out.println(out);
 290         Assert.assertFalse(out.contains("http://openjdk_java_net/xml/defaultNS"));
 291     }
 292 
 293     /**
 294      * @bug 8219692
 295      * Verifies that the default namespace declaration is preserved when
 296      * NamespaceAware is set on the parser.
 297      * @throws Exception
 298      */
 299     @Test(dataProvider = "NSAwareSAXFactory")
 300     public void testNSAwareSAXFactory(SAXParser sp) throws Exception {
 301         MyHandler h = new MyHandler();
 302         sp.parse(new InputSource(new StringReader(xml_8219692)), h);
 303 
 304         Assert.assertTrue(h.isNSAware);
 305     }
 306 
 307     /**
 308      * @bug 8219692
 309      * Verifies that the default namespace declaration is missing when the
 310      * old factory methods are used.
 311      * @throws Exception
 312      */
 313     @Test(dataProvider = "SAXFactory")
 314     public void testSAXFactory(SAXParser sp) throws Exception {
 315         MyHandler h = new MyHandler();
 316         sp.parse(new InputSource(new StringReader(xml_8219692)), h);
 317 
 318         Assert.assertFalse(h.isNSAware);
 319     }
 320 
 321     private static DocumentBuilder getDOMParser(DocumentBuilderFactory dbf, boolean isNSAware)
 322             throws Exception {
 323         dbf.setNamespaceAware(isNSAware);
 324         return dbf.newDocumentBuilder();
 325     }
 326 
 327     private static SAXParser getSAXParser(SAXParserFactory spf, boolean isNSAware)
 328             throws Exception {
 329         spf.setNamespaceAware(isNSAware);
 330         return spf.newSAXParser();
 331     }
 332 
 333     private LSSerializer getSerializer(DocumentBuilder db) throws Exception {
 334         DOMImplementationLS di = (DOMImplementationLS) db.getDOMImplementation();
 335         return di.createLSSerializer();
 336     }
 337 
 338     private Document getDoc(DocumentBuilder db, String xml) throws Exception {
 339         InputSource is = new InputSource(new StringReader(xml));
 340         return db.parse(is);
 341     }
 342 
 343     /**
 344      * SAX Handler
 345      */
 346     class MyHandler extends DefaultHandler {
 347         boolean isNSAware = false;
 348 
 349         @Override
 350         public void startElement(String uri, String localName, String qName,
 351             Attributes attributes) throws SAXException {
 352             isNSAware = "http://openjdk_java_net/xml/defaultNS".equals(uri)
 353                     && ("a".equals(localName) || "b".equals(localName));
 354         }
 355     }
 356 }