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 
DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs, Map<String, Boolean> features)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 
DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs, Map<String, Boolean> features, boolean secureProcessing)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 && temp) {
188                     fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD,
189                             State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
190                     fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_SCHEMA,
191                             State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
192                 }
193             }
194         }
195 
196         this.grammar = dbf.getSchema();
197         if (grammar != null) {
198             XMLParserConfiguration config = domParser.getXMLParserConfiguration();
199             XMLComponent validatorComponent = null;
200             /** For Xerces grammars, use built-in schema validator. **/
201             if (grammar instanceof XSGrammarPoolContainer) {
202                 validatorComponent = new XMLSchemaValidator();
203                 fSchemaValidationManager = new ValidationManager();
204                 fUnparsedEntityHandler = new UnparsedEntityHandler(fSchemaValidationManager);
205                 config.setDTDHandler(fUnparsedEntityHandler);
206                 fUnparsedEntityHandler.setDTDHandler(domParser);
207                 domParser.setDTDSource(fUnparsedEntityHandler);
208                 fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(config,
209                         (XSGrammarPoolContainer) grammar, fSchemaValidationManager);
210             }
211             /** For third party grammars, use the JAXP validator component. **/
212             else {
213                 validatorComponent = new JAXPValidatorComponent(grammar.newValidatorHandler());
214                 fSchemaValidationManager = null;
215                 fUnparsedEntityHandler = null;
216                 fSchemaValidatorComponentManager = config;
217             }
218             config.addRecognizedFeatures(validatorComponent.getRecognizedFeatures());
219             config.addRecognizedProperties(validatorComponent.getRecognizedProperties());
220             setFeatures(features);      // Must set before calling setDocumentHandler()
221             config.setDocumentHandler((XMLDocumentHandler) validatorComponent);
222             ((XMLDocumentSource)validatorComponent).setDocumentHandler(domParser);
223             domParser.setDocumentSource((XMLDocumentSource) validatorComponent);
224             fSchemaValidator = validatorComponent;
225         }
226         else {
227             fSchemaValidationManager = null;
228             fUnparsedEntityHandler = null;
229             fSchemaValidatorComponentManager = null;
230             fSchemaValidator = null;
231             setFeatures(features);
232         }
233 
234         //setAttribute override those that may be set by other means
235         setDocumentBuilderFactoryAttributes(dbfAttrs);
236 
237         // Initial EntityResolver
238         fInitEntityResolver = domParser.getEntityResolver();
239     }
240 
setFeatures( Map<String, Boolean> features)241     private void setFeatures( Map<String, Boolean> features)
242         throws SAXNotSupportedException, SAXNotRecognizedException {
243         if (features != null) {
244             for (Map.Entry<String, Boolean> entry : features.entrySet()) {
245                 domParser.setFeature(entry.getKey(), entry.getValue());
246         }
247     }
248     }
249 
250     /**
251      * Set any DocumentBuilderFactory attributes of our underlying DOMParser
252      *
253      * Note: code does not handle possible conflicts between DOMParser
254      * attribute names and JAXP specific attribute names,
255      * eg. DocumentBuilderFactory.setValidating()
256      */
setDocumentBuilderFactoryAttributes( Map<String, Object> dbfAttrs)257     private void setDocumentBuilderFactoryAttributes( Map<String, Object> dbfAttrs)
258         throws SAXNotSupportedException, SAXNotRecognizedException
259     {
260         if (dbfAttrs == null) {
261             // Nothing to do
262             return;
263         }
264 
265         for (Map.Entry<String, Object> entry : dbfAttrs.entrySet()) {
266             String name = entry.getKey();
267             Object val = entry.getValue();
268             if (val instanceof Boolean) {
269                 // Assume feature
270                 domParser.setFeature(name, (Boolean)val);
271             } else {
272                 // Assume property
273                 if (JAXP_SCHEMA_LANGUAGE.equals(name)) {
274                     // JAXP 1.2 support
275                     //None of the properties will take effect till the setValidating(true) has been called
276                     if ( W3C_XML_SCHEMA.equals(val) ) {
277                         if( isValidating() ) {
278                             domParser.setFeature(XMLSCHEMA_VALIDATION_FEATURE, true);
279                             // this should allow us not to emit DTD errors, as expected by the
280                             // spec when schema validation is enabled
281                             domParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
282                         }
283                      }
284                  } else if(JAXP_SCHEMA_SOURCE.equals(name)){
285                     if( isValidating() ) {
286                         String value=(String)dbfAttrs.get(JAXP_SCHEMA_LANGUAGE);
287                         if(value !=null && W3C_XML_SCHEMA.equals(value)){
288                             domParser.setProperty(name, val);
289                         }else{
290                             throw new IllegalArgumentException(
291                                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
292                                 "jaxp-order-not-supported",
293                                 new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE}));
294                         }
295                      }
296                   } else {
297                      //check if the property is managed by security manager
298                      if (fSecurityManager == null ||
299                              !fSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, val)) {
300                          //check if the property is managed by security property manager
301                          if (fSecurityPropertyMgr == null ||
302                                  !fSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, val)) {
303                              //fall back to the existing property manager
304                              domParser.setProperty(name, val);
305                          }
306                      }
307 
308                   }
309              }
310         }
311     }
312 
313     /**
314      * Non-preferred: use the getDOMImplementation() method instead of this
315      * one to get a DOM Level 2 DOMImplementation object and then use DOM
316      * Level 2 methods to create a DOM Document object.
317      */
newDocument()318     public Document newDocument() {
319         return new com.sun.org.apache.xerces.internal.dom.DocumentImpl();
320     }
321 
getDOMImplementation()322     public DOMImplementation getDOMImplementation() {
323         return DOMImplementationImpl.getDOMImplementation();
324     }
325 
parse(InputSource is)326     public Document parse(InputSource is) throws SAXException, IOException {
327         if (is == null) {
328             throw new IllegalArgumentException(
329                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
330                 "jaxp-null-input-source", null));
331         }
332         if (fSchemaValidator != null) {
333             if (fSchemaValidationManager != null) {
334                 fSchemaValidationManager.reset();
335                 fUnparsedEntityHandler.reset();
336             }
337             resetSchemaValidator();
338         }
339         domParser.parse(is);
340         Document doc = domParser.getDocument();
341         domParser.dropDocumentReferences();
342         return doc;
343     }
344 
isNamespaceAware()345     public boolean isNamespaceAware() {
346         try {
347             return domParser.getFeature(NAMESPACES_FEATURE);
348         }
349         catch (SAXException x) {
350             throw new IllegalStateException(x.getMessage());
351         }
352     }
353 
isValidating()354     public boolean isValidating() {
355         try {
356             return domParser.getFeature(VALIDATION_FEATURE);
357         }
358         catch (SAXException x) {
359             throw new IllegalStateException(x.getMessage());
360         }
361     }
362 
363     /**
364      * Gets the XInclude processing mode for this parser
365      * @return the state of XInclude processing mode
366      */
isXIncludeAware()367     public boolean isXIncludeAware() {
368         try {
369             return domParser.getFeature(XINCLUDE_FEATURE);
370         }
371         catch (SAXException exc) {
372             return false;
373         }
374     }
375 
setEntityResolver(EntityResolver er)376     public void setEntityResolver(EntityResolver er) {
377         domParser.setEntityResolver(er);
378     }
379 
setErrorHandler(ErrorHandler eh)380     public void setErrorHandler(ErrorHandler eh) {
381         domParser.setErrorHandler(eh);
382     }
383 
getSchema()384     public Schema getSchema() {
385         return grammar;
386     }
387 
reset()388     public void reset() {
389         /** Restore the initial error handler. **/
390         if (domParser.getErrorHandler() != fInitErrorHandler) {
391             domParser.setErrorHandler(fInitErrorHandler);
392         }
393         /** Restore the initial entity resolver. **/
394         if (domParser.getEntityResolver() != fInitEntityResolver) {
395             domParser.setEntityResolver(fInitEntityResolver);
396         }
397     }
398 
399     // package private
getDOMParser()400     DOMParser getDOMParser() {
401         return domParser;
402     }
403 
resetSchemaValidator()404     private void resetSchemaValidator() throws SAXException {
405         try {
406             fSchemaValidator.reset(fSchemaValidatorComponentManager);
407         }
408         // This should never be thrown from the schema validator.
409         catch (XMLConfigurationException e) {
410             throw new SAXException(e);
411         }
412     }
413 }
414