1 /*
   2  * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xerces.internal.jaxp;
  22 
  23 import java.io.IOException;
  24 import java.util.Iterator;
  25 import java.util.Map;
  26 
  27 import javax.xml.parsers.DocumentBuilder;
  28 import javax.xml.validation.Schema;
  29 import javax.xml.XMLConstants;
  30 
  31 import com.sun.org.apache.xerces.internal.dom.DOMImplementationImpl;
  32 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
  33 import com.sun.org.apache.xerces.internal.impl.Constants;
  34 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  35 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator;
  36 import com.sun.org.apache.xerces.internal.jaxp.validation.XSGrammarPoolContainer;
  37 import com.sun.org.apache.xerces.internal.parsers.DOMParser;
  38 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  39 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  40 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager.Property;
  41 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager.State;
  42 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  43 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  44 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  45 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  46 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  47 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
  48 import org.w3c.dom.DOMImplementation;
  49 import org.w3c.dom.Document;
  50 import org.xml.sax.EntityResolver;
  51 import org.xml.sax.ErrorHandler;
  52 import org.xml.sax.InputSource;
  53 import org.xml.sax.SAXException;
  54 import org.xml.sax.SAXNotRecognizedException;
  55 import org.xml.sax.SAXNotSupportedException;
  56 
  57 /**
  58  * @author Rajiv Mordani
  59  * @author Edwin Goei
  60  */
  61 public class DocumentBuilderImpl extends DocumentBuilder
  62         implements JAXPConstants
  63 {
  64     /** Feature identifier: namespaces. */
  65     private static final String NAMESPACES_FEATURE =
  66         Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
  67 
  68     /** Feature identifier: include ignorable white space. */
  69     private static final String INCLUDE_IGNORABLE_WHITESPACE =
  70         Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE;
  71 
  72     /** Feature identifier: create entiry ref nodes feature. */
  73     private static final String CREATE_ENTITY_REF_NODES_FEATURE =
  74         Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE;
  75 
  76     /** Feature identifier: include comments feature. */
  77     private static final String INCLUDE_COMMENTS_FEATURE =
  78         Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE;
  79 
  80     /** Feature identifier: create cdata nodes feature. */
  81     private static final String CREATE_CDATA_NODES_FEATURE =
  82         Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE;
  83 
  84     /** Feature identifier: XInclude processing */
  85     private static final String XINCLUDE_FEATURE =
  86         Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE;
  87 
  88     /** feature identifier: XML Schema validation */
  89     private static final String XMLSCHEMA_VALIDATION_FEATURE =
  90         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
  91 
  92     /** Feature identifier: validation */
  93     private static final String VALIDATION_FEATURE =
  94         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
  95 
  96     /** Property identifier: security manager. */
  97     private static final String SECURITY_MANAGER =
  98         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
  99 
 100     /** Property identifier: Security property manager. */
 101     private static final String XML_SECURITY_PROPERTY_MANAGER =
 102             Constants.XML_SECURITY_PROPERTY_MANAGER;
 103 
 104     /** property identifier: access external dtd. */
 105     public static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD;
 106 
 107     /** Property identifier: access to external schema */
 108     public static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA;
 109 
 110 
 111     private final DOMParser domParser;
 112     private final Schema grammar;
 113 
 114     private final XMLComponent fSchemaValidator;
 115     private final XMLComponentManager fSchemaValidatorComponentManager;
 116     private final ValidationManager fSchemaValidationManager;
 117     private final UnparsedEntityHandler fUnparsedEntityHandler;
 118 
 119     /** Initial ErrorHandler */
 120     private final ErrorHandler fInitErrorHandler;
 121 
 122     /** Initial EntityResolver */
 123     private final EntityResolver fInitEntityResolver;
 124 
 125     private XMLSecurityManager fSecurityManager;
 126     private XMLSecurityPropertyManager fSecurityPropertyMgr;
 127 
 128     DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs,
 129             Map<String, Boolean> features)
 130         throws SAXNotRecognizedException, SAXNotSupportedException {
 131         this(dbf, dbfAttrs, features, false);
 132     }
 133 
 134     DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs,
 135             Map<String, Boolean> features, boolean secureProcessing)
 136         throws SAXNotRecognizedException, SAXNotSupportedException
 137     {
 138         domParser = new DOMParser();
 139 
 140         // If validating, provide a default ErrorHandler that prints
 141         // validation errors with a warning telling the user to set an
 142         // ErrorHandler
 143         if (dbf.isValidating()) {
 144             fInitErrorHandler = new DefaultValidationErrorHandler(domParser.getXMLParserConfiguration().getLocale());
 145             setErrorHandler(fInitErrorHandler);
 146         }
 147         else {
 148             fInitErrorHandler = domParser.getErrorHandler();
 149         }
 150 
 151         domParser.setFeature(VALIDATION_FEATURE, dbf.isValidating());
 152 
 153         // "namespaceAware" == SAX Namespaces feature
 154         domParser.setFeature(NAMESPACES_FEATURE, dbf.isNamespaceAware());
 155 
 156         // Set various parameters obtained from DocumentBuilderFactory
 157         domParser.setFeature(INCLUDE_IGNORABLE_WHITESPACE,
 158                 !dbf.isIgnoringElementContentWhitespace());
 159         domParser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE,
 160                 !dbf.isExpandEntityReferences());
 161         domParser.setFeature(INCLUDE_COMMENTS_FEATURE,
 162                 !dbf.isIgnoringComments());
 163         domParser.setFeature(CREATE_CDATA_NODES_FEATURE,
 164                 !dbf.isCoalescing());
 165 
 166         // Avoid setting the XInclude processing feature if the value is false.
 167         // This will keep the configuration from throwing an exception if it
 168         // does not support XInclude.
 169         if (dbf.isXIncludeAware()) {
 170             domParser.setFeature(XINCLUDE_FEATURE, true);
 171         }
 172 
 173         fSecurityPropertyMgr = new XMLSecurityPropertyManager();
 174         domParser.setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
 175 
 176         fSecurityManager = new XMLSecurityManager(secureProcessing);
 177         domParser.setProperty(SECURITY_MANAGER, fSecurityManager);
 178 
 179         if (secureProcessing) {
 180             /**
 181              * If secure processing is explicitly set on the factory, the
 182              * access properties will be set unless the corresponding
 183              * System Properties or jaxp.properties are set
 184              */
 185             if (features != null) {
 186                 Boolean temp = features.get(XMLConstants.FEATURE_SECURE_PROCESSING);
 187                 if (temp != null) {
 188                     if (temp && Constants.IS_JDK8_OR_ABOVE) {
 189                         fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD,
 190                                 State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 191                         fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_SCHEMA,
 192                                 State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 193                     }
 194                 }
 195             }
 196         }
 197 
 198         this.grammar = dbf.getSchema();
 199         if (grammar != null) {
 200             XMLParserConfiguration config = domParser.getXMLParserConfiguration();
 201             XMLComponent validatorComponent = null;
 202             /** For Xerces grammars, use built-in schema validator. **/
 203             if (grammar instanceof XSGrammarPoolContainer) {
 204                 validatorComponent = new XMLSchemaValidator();
 205                 fSchemaValidationManager = new ValidationManager();
 206                 fUnparsedEntityHandler = new UnparsedEntityHandler(fSchemaValidationManager);
 207                 config.setDTDHandler(fUnparsedEntityHandler);
 208                 fUnparsedEntityHandler.setDTDHandler(domParser);
 209                 domParser.setDTDSource(fUnparsedEntityHandler);
 210                 fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(config,
 211                         (XSGrammarPoolContainer) grammar, fSchemaValidationManager);
 212             }
 213             /** For third party grammars, use the JAXP validator component. **/
 214             else {
 215                 validatorComponent = new JAXPValidatorComponent(grammar.newValidatorHandler());
 216                 fSchemaValidationManager = null;
 217                 fUnparsedEntityHandler = null;
 218                 fSchemaValidatorComponentManager = config;
 219             }
 220             config.addRecognizedFeatures(validatorComponent.getRecognizedFeatures());
 221             config.addRecognizedProperties(validatorComponent.getRecognizedProperties());
 222             setFeatures(features);      // Must set before calling setDocumentHandler()
 223             config.setDocumentHandler((XMLDocumentHandler) validatorComponent);
 224             ((XMLDocumentSource)validatorComponent).setDocumentHandler(domParser);
 225             domParser.setDocumentSource((XMLDocumentSource) validatorComponent);
 226             fSchemaValidator = validatorComponent;
 227         }
 228         else {
 229             fSchemaValidationManager = null;
 230             fUnparsedEntityHandler = null;
 231             fSchemaValidatorComponentManager = null;
 232             fSchemaValidator = null;
 233             setFeatures(features);
 234         }
 235 
 236         //setAttribute override those that may be set by other means
 237         setDocumentBuilderFactoryAttributes(dbfAttrs);
 238 
 239         // Initial EntityResolver
 240         fInitEntityResolver = domParser.getEntityResolver();
 241     }
 242 
 243     private void setFeatures( Map<String, Boolean> features)
 244         throws SAXNotSupportedException, SAXNotRecognizedException {
 245         if (features != null) {
 246             for (Map.Entry<String, Boolean> entry : features.entrySet()) {
 247                 domParser.setFeature(entry.getKey(), entry.getValue());
 248         }
 249     }
 250     }
 251 
 252     /**
 253      * Set any DocumentBuilderFactory attributes of our underlying DOMParser
 254      *
 255      * Note: code does not handle possible conflicts between DOMParser
 256      * attribute names and JAXP specific attribute names,
 257      * eg. DocumentBuilderFactory.setValidating()
 258      */
 259     private void setDocumentBuilderFactoryAttributes( Map<String, Object> dbfAttrs)
 260         throws SAXNotSupportedException, SAXNotRecognizedException
 261     {
 262         if (dbfAttrs == null) {
 263             // Nothing to do
 264             return;
 265         }
 266 
 267         for (Map.Entry<String, Object> entry : dbfAttrs.entrySet()) {
 268             String name = entry.getKey();
 269             Object val = entry.getValue();
 270             if (val instanceof Boolean) {
 271                 // Assume feature
 272                 domParser.setFeature(name, (Boolean)val);
 273             } else {
 274                 // Assume property
 275                 if (JAXP_SCHEMA_LANGUAGE.equals(name)) {
 276                     // JAXP 1.2 support
 277                     //None of the properties will take effect till the setValidating(true) has been called
 278                     if ( W3C_XML_SCHEMA.equals(val) ) {
 279                         if( isValidating() ) {
 280                             domParser.setFeature(XMLSCHEMA_VALIDATION_FEATURE, true);
 281                             // this should allow us not to emit DTD errors, as expected by the
 282                             // spec when schema validation is enabled
 283                             domParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
 284                         }
 285                      }
 286                  } else if(JAXP_SCHEMA_SOURCE.equals(name)){
 287                     if( isValidating() ) {
 288                         String value=(String)dbfAttrs.get(JAXP_SCHEMA_LANGUAGE);
 289                         if(value !=null && W3C_XML_SCHEMA.equals(value)){
 290                             domParser.setProperty(name, val);
 291                         }else{
 292                             throw new IllegalArgumentException(
 293                                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
 294                                 "jaxp-order-not-supported",
 295                                 new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE}));
 296                         }
 297                      }
 298                   } else {
 299                      //check if the property is managed by security manager
 300                      if (fSecurityManager == null ||
 301                              !fSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, val)) {
 302                          //check if the property is managed by security property manager
 303                          if (fSecurityPropertyMgr == null ||
 304                                  !fSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, val)) {
 305                              //fall back to the existing property manager
 306                              domParser.setProperty(name, val);
 307                          }
 308                      }
 309 
 310                   }
 311              }
 312         }
 313     }
 314 
 315     /**
 316      * Non-preferred: use the getDOMImplementation() method instead of this
 317      * one to get a DOM Level 2 DOMImplementation object and then use DOM
 318      * Level 2 methods to create a DOM Document object.
 319      */
 320     public Document newDocument() {
 321         return new com.sun.org.apache.xerces.internal.dom.DocumentImpl();
 322     }
 323 
 324     public DOMImplementation getDOMImplementation() {
 325         return DOMImplementationImpl.getDOMImplementation();
 326     }
 327 
 328     public Document parse(InputSource is) throws SAXException, IOException {
 329         if (is == null) {
 330             throw new IllegalArgumentException(
 331                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
 332                 "jaxp-null-input-source", null));
 333         }
 334         if (fSchemaValidator != null) {
 335             if (fSchemaValidationManager != null) {
 336                 fSchemaValidationManager.reset();
 337                 fUnparsedEntityHandler.reset();
 338             }
 339             resetSchemaValidator();
 340         }
 341         domParser.parse(is);
 342         Document doc = domParser.getDocument();
 343         domParser.dropDocumentReferences();
 344         return doc;
 345     }
 346 
 347     public boolean isNamespaceAware() {
 348         try {
 349             return domParser.getFeature(NAMESPACES_FEATURE);
 350         }
 351         catch (SAXException x) {
 352             throw new IllegalStateException(x.getMessage());
 353         }
 354     }
 355 
 356     public boolean isValidating() {
 357         try {
 358             return domParser.getFeature(VALIDATION_FEATURE);
 359         }
 360         catch (SAXException x) {
 361             throw new IllegalStateException(x.getMessage());
 362         }
 363     }
 364 
 365     /**
 366      * Gets the XInclude processing mode for this parser
 367      * @return the state of XInclude processing mode
 368      */
 369     public boolean isXIncludeAware() {
 370         try {
 371             return domParser.getFeature(XINCLUDE_FEATURE);
 372         }
 373         catch (SAXException exc) {
 374             return false;
 375         }
 376     }
 377 
 378     public void setEntityResolver(EntityResolver er) {
 379         domParser.setEntityResolver(er);
 380     }
 381 
 382     public void setErrorHandler(ErrorHandler eh) {
 383         domParser.setErrorHandler(eh);
 384     }
 385 
 386     public Schema getSchema() {
 387         return grammar;
 388     }
 389 
 390     public void reset() {
 391         /** Restore the initial error handler. **/
 392         if (domParser.getErrorHandler() != fInitErrorHandler) {
 393             domParser.setErrorHandler(fInitErrorHandler);
 394         }
 395         /** Restore the initial entity resolver. **/
 396         if (domParser.getEntityResolver() != fInitEntityResolver) {
 397             domParser.setEntityResolver(fInitEntityResolver);
 398         }
 399     }
 400 
 401     // package private
 402     DOMParser getDOMParser() {
 403         return domParser;
 404     }
 405 
 406     private void resetSchemaValidator() throws SAXException {
 407         try {
 408             fSchemaValidator.reset(fSchemaValidatorComponentManager);
 409         }
 410         // This should never be thrown from the schema validator.
 411         catch (XMLConfigurationException e) {
 412             throw new SAXException(e);
 413         }
 414     }
 415 }