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