1 /*
   2  * Copyright (c) 2014, 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 
  24 package stream.XMLStreamReaderTest;
  25 
  26 import java.io.File;
  27 import java.io.FileInputStream;
  28 import java.io.StringReader;
  29 import java.util.List;
  30 
  31 import javax.xml.stream.XMLEventReader;
  32 import javax.xml.stream.XMLInputFactory;
  33 import javax.xml.stream.XMLStreamConstants;
  34 import javax.xml.stream.events.Characters;
  35 import javax.xml.stream.events.DTD;
  36 import javax.xml.stream.events.EntityDeclaration;
  37 import javax.xml.stream.events.EntityReference;
  38 import javax.xml.stream.events.XMLEvent;
  39 
  40 import org.testng.Assert;
  41 import org.testng.annotations.Listeners;
  42 import org.testng.annotations.Test;
  43 
  44 /*
  45  * @test
  46  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
  47  * @run testng/othervm -DrunSecMngr=true stream.XMLStreamReaderTest.SupportDTDTest
  48  * @run testng/othervm stream.XMLStreamReaderTest.SupportDTDTest
  49  * @summary Test SUPPORT_DTD and IS_REPLACING_ENTITY_REFERENCES.
  50  */
  51 
  52 /**
  53 *
  54 * SUPPORT_DTD behavior:
  55 * Regardless of supportDTD, always report a DTD event () and throw an
  56 * exception if an entity reference is found when supportDTD is false
  57 *
  58 * The behavior is related to property IS_REPLACING_ENTITY_REFERENCES.
  59 *
  60 * SUPPORT_DTD      Replace Entity   DTD                    ENTITY_REFERENCE
  61 * true (default)   true (default)   yes, has entities      no, return Characters
  62 * true (default)   false            yes, has entities      yes, can print entity name
  63 * false            true (default)   yes, but no entity     Exception: Undeclared general entity
  64 * false            false            yes, but no entity     yes, can print entity name
  65 *
  66 * Two patches related:
  67 * sjsxp issue 9: XMLDocumentScannerImpl.java rev 1.6
  68 * If the supportDTD property is set to FALSE, external and internal subsets
  69 * are now ignored, rather than an error being reported. In particular, with
  70 * this property set to FALSE, no error is reported if an external subset cannot
  71 * be found. Note that the internal subset is still parsed (and errors could be
  72 * reported here) but no events are returned by the parser. This fixes SJSXP
  73 * issue 9 from Java.net.
  74 * Note: SAX and DOM report fatal errors:
  75 *       If either SAX or DOM is used, turning on http://apache.org/xml/features/disallow-doctype-decl [1] effectively disables DTD,
  76 *       according to the spec: A fatal error is thrown if the incoming document contains a DOCTYPE declaration.
  77 *       The current jaxp implementation actually throws a nullpointexception. A better error message could be used.
  78 *
  79 */
  80 @Listeners({jaxp.library.FilePolicy.class})
  81 public class SupportDTDTest {
  82     final boolean DEBUG = false;
  83     final String _file = "ExternalDTD.xml";
  84     final String XML = "<?xml version='1.0' ?>" + "<!DOCTYPE root [\n" + "<!ENTITY intEnt 'internal entity'>\n" + "<!ENTITY extParsedEnt SYSTEM 'url:dummy'>\n"
  85             + "<!NOTATION notation PUBLIC 'notation-public-id'>\n" + "<!NOTATION notation2 SYSTEM 'url:dummy'>\n"
  86             + "<!ENTITY extUnparsedEnt SYSTEM 'url:dummy2' NDATA notation>\n" + "]>" + "<root>&intEnt;</root>";
  87 
  88     final String XML1 = "<?xml version='1.0' encoding ='utf-8'?>" + "<!DOCTYPE document SYSTEM \"" + this.getClass().getResource("ExternalDTD.dtd").getFile()
  89             + "\">" + "<document>" + "<name>&mkm;</name>" + "</document>";
  90 
  91    // final String XML1 = "<?xml version='1.0' encoding ='utf-8'?>" + "<!DOCTYPE document SYSTEM \"/home/oracle/repo/xmlwork/dev/jdk/test/javax/xml/jaxp/unittest/javax/xml/stream/XMLStreamReaderTest/ExternalDTD.dtd\">" + "<document>"
  92    //         + "<name>&mkm;</name>" + "</document>";
  93 
  94     final int ENTITY_INTERNAL_ONLY = 1;
  95     final int ENTITY_EXTERNAL_ONLY = 2;
  96     final int ENTITY_BOTH = 3;
  97 
  98     boolean _DTDReturned = false;
  99     boolean _EntityEventReturned = false;
 100     boolean _hasEntityDelaration = false;
 101     boolean _exceptionThrown = false;
 102 
 103     /** Creates a new instance of StreamReader */
 104     public SupportDTDTest(String name) {
 105     }
 106 
 107     void reset() {
 108         _DTDReturned = false;
 109         _EntityEventReturned = false;
 110         _hasEntityDelaration = false;
 111         _exceptionThrown = false;
 112     }
 113 
 114     // tests 1-4 test internal entities only
 115     @Test
 116     public void test1() {
 117         supportDTD(true, true, ENTITY_INTERNAL_ONLY);
 118         Assert.assertEquals(true, _DTDReturned);
 119         Assert.assertEquals(true, _hasEntityDelaration);
 120         Assert.assertEquals(false, _EntityEventReturned);
 121     }
 122 
 123     @Test
 124     public void test2() {
 125         supportDTD(true, false, ENTITY_INTERNAL_ONLY);
 126         Assert.assertEquals(true, _DTDReturned);
 127         Assert.assertEquals(true, _hasEntityDelaration);
 128         Assert.assertEquals(true, _EntityEventReturned);
 129     }
 130 
 131     @Test
 132     public void test3() {
 133         supportDTD(false, true, ENTITY_INTERNAL_ONLY);
 134         Assert.assertEquals(true, _DTDReturned);
 135         Assert.assertEquals(false, _hasEntityDelaration);
 136         Assert.assertEquals(true, _exceptionThrown);
 137     }
 138 
 139     @Test
 140     public void test4() {
 141         supportDTD(false, false, ENTITY_INTERNAL_ONLY);
 142         Assert.assertEquals(true, _DTDReturned);
 143         Assert.assertEquals(false, _hasEntityDelaration);
 144         Assert.assertEquals(true, _EntityEventReturned);
 145     }
 146 
 147     // tests 5-8 test external entities only
 148     @Test
 149     public void test5() {
 150         supportDTD(true, true, ENTITY_EXTERNAL_ONLY);
 151         Assert.assertEquals(true, _DTDReturned);
 152         Assert.assertEquals(true, _hasEntityDelaration);
 153         Assert.assertEquals(false, _EntityEventReturned);
 154     }
 155 
 156     @Test
 157     public void test6() {
 158         supportDTD(true, false, ENTITY_EXTERNAL_ONLY);
 159         Assert.assertEquals(true, _DTDReturned);
 160         Assert.assertEquals(true, _hasEntityDelaration);
 161         Assert.assertEquals(true, _EntityEventReturned);
 162     }
 163 
 164     @Test
 165     public void test7() {
 166         supportDTD(false, true, ENTITY_EXTERNAL_ONLY);
 167         Assert.assertEquals(true, _DTDReturned);
 168         Assert.assertEquals(false, _hasEntityDelaration);
 169         Assert.assertEquals(true, _exceptionThrown);
 170     }
 171 
 172     @Test
 173     public void test8() {
 174         supportDTD(false, false, ENTITY_EXTERNAL_ONLY);
 175         Assert.assertEquals(true, _DTDReturned);
 176         Assert.assertEquals(false, _hasEntityDelaration);
 177         Assert.assertEquals(true, _EntityEventReturned);
 178     }
 179 
 180     // tests 9-12 test both internal and external entities
 181     @Test
 182     public void test9() {
 183         supportDTD(true, true, ENTITY_BOTH);
 184         Assert.assertEquals(true, _DTDReturned);
 185         Assert.assertEquals(true, _hasEntityDelaration);
 186         Assert.assertEquals(false, _EntityEventReturned);
 187     }
 188 
 189     @Test
 190     public void test10() {
 191         supportDTD(true, false, ENTITY_BOTH);
 192         Assert.assertEquals(true, _DTDReturned);
 193         Assert.assertEquals(true, _hasEntityDelaration);
 194         Assert.assertEquals(true, _EntityEventReturned);
 195     }
 196 
 197     @Test
 198     public void test11() {
 199         supportDTD(false, true, ENTITY_BOTH);
 200         Assert.assertEquals(true, _DTDReturned);
 201         Assert.assertEquals(false, _hasEntityDelaration);
 202         Assert.assertEquals(true, _exceptionThrown);
 203     }
 204 
 205     @Test
 206     public void test12() {
 207         supportDTD(false, false, ENTITY_BOTH);
 208         Assert.assertEquals(true, _DTDReturned);
 209         Assert.assertEquals(false, _hasEntityDelaration);
 210         Assert.assertEquals(true, _EntityEventReturned);
 211     }
 212 
 213     public void supportDTD(boolean supportDTD, boolean replaceEntity, int inputType) {
 214         reset();
 215         print("\n");
 216         print((supportDTD ? "SupportDTD=true" : "SupportDTD=false") + ", " + (replaceEntity ? "replaceEntity=true" : "replaceEntity=false"));
 217         try {
 218             XMLInputFactory xif = getFactory(supportDTD, replaceEntity);
 219             XMLEventReader r = getEventReader(xif, inputType);
 220             int eventType = 0;
 221             int count = 0;
 222             while (r.hasNext()) {
 223                 XMLEvent event = r.nextEvent();
 224                 eventType = event.getEventType();
 225                 print("Event " + ++count + ": " + eventType);
 226                 switch (eventType) {
 227                     case XMLStreamConstants.DTD:
 228                         DisplayEntities((DTD) event);
 229                         _DTDReturned = true;
 230                         break;
 231                     case XMLStreamConstants.ENTITY_REFERENCE:
 232                         print("Entity Name: " + ((EntityReference) event).getName());
 233                         _EntityEventReturned = true;
 234                         break;
 235                     case XMLStreamConstants.CHARACTERS:
 236                         print("Text: " + ((Characters) event).getData());
 237                 }
 238             }
 239 
 240         } catch (Exception e) {
 241             _exceptionThrown = true;
 242             if (DEBUG)
 243                 e.printStackTrace();
 244         }
 245     }
 246 
 247     XMLInputFactory getFactory(boolean supportDTD, boolean replaceEntity) {
 248         XMLInputFactory xif = XMLInputFactory.newInstance();
 249         xif.setProperty(XMLInputFactory.SUPPORT_DTD, (supportDTD) ? Boolean.TRUE : Boolean.FALSE);
 250         xif.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, (replaceEntity) ? Boolean.TRUE : Boolean.FALSE);
 251         // xif.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.TRUE);
 252         return xif;
 253     }
 254 
 255     private XMLEventReader getEventReader(XMLInputFactory inputFactory, int input) throws Exception {
 256         XMLEventReader er = null;
 257         if (input == ENTITY_INTERNAL_ONLY) {
 258             er = inputFactory.createXMLEventReader(new StringReader(XML));
 259         } else if (input == ENTITY_EXTERNAL_ONLY) {
 260             er = inputFactory.createXMLEventReader(new StringReader(XML1));
 261         } else {
 262             File file = new File(this.getClass().getResource(_file).getFile());
 263             FileInputStream inputStream = new FileInputStream(file);
 264             // XMLStreamReader r = xif.createXMLStreamReader(inputStream);
 265             er = inputFactory.createXMLEventReader(inputStream);
 266         }
 267         return er;
 268     }
 269 
 270     void DisplayEntities(DTD event) {
 271         List entities = event.getEntities();
 272         if (entities == null) {
 273             _hasEntityDelaration = false;
 274             print("No entity found.");
 275         } else {
 276             _hasEntityDelaration = true;
 277             for (int i = 0; i < entities.size(); i++) {
 278                 EntityDeclaration entity = (EntityDeclaration) entities.get(i);
 279                 print(entity.getName());
 280             }
 281         }
 282 
 283     }
 284 
 285     void print(String s) {
 286         if (DEBUG)
 287             System.out.println(s);
 288     }
 289 
 290 }