1 /* 2 * Copyright (c) 2007, 2016, 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.xml.internal.utils; 22 23 import com.sun.org.apache.xalan.internal.XalanConstants; 24 import com.sun.org.apache.xalan.internal.utils.FactoryImpl; 25 import com.sun.org.apache.xalan.internal.utils.SecuritySupport; 26 import com.sun.org.apache.xalan.internal.utils.XMLSecurityManager; 27 import java.util.HashMap; 28 import javax.xml.XMLConstants; 29 import javax.xml.catalog.CatalogFeatures; 30 import javax.xml.parsers.FactoryConfigurationError; 31 import javax.xml.parsers.ParserConfigurationException; 32 import javax.xml.parsers.SAXParserFactory; 33 import jdk.xml.internal.JdkXmlFeatures; 34 import jdk.xml.internal.JdkXmlUtils; 35 import org.xml.sax.SAXException; 36 import org.xml.sax.SAXNotRecognizedException; 37 import org.xml.sax.SAXNotSupportedException; 38 import org.xml.sax.XMLReader; 39 import org.xml.sax.helpers.XMLReaderFactory; 40 41 /** 42 * Creates XMLReader objects and caches them for re-use. 43 * This class follows the singleton pattern. 44 */ 45 @SuppressWarnings("deprecation") //org.xml.sax.helpers.XMLReaderFactory 46 public class XMLReaderManager { 47 48 private static final String NAMESPACES_FEATURE = 49 "http://xml.org/sax/features/namespaces"; 50 private static final String NAMESPACE_PREFIXES_FEATURE = 51 "http://xml.org/sax/features/namespace-prefixes"; 52 private static final XMLReaderManager m_singletonManager = 53 new XMLReaderManager(); 54 private static final String property = "org.xml.sax.driver"; 55 /** 56 * Parser factory to be used to construct XMLReader objects 57 */ 58 private static SAXParserFactory m_parserFactory; 59 60 /** 61 * Cache of XMLReader objects 62 */ 63 private ThreadLocal<XMLReader> m_readers; 64 65 /** 66 * Keeps track of whether an XMLReader object is in use. 67 */ 68 private HashMap<XMLReader, Boolean> m_inUse; 69 70 private boolean m_useServicesMechanism = true; 71 72 private boolean _secureProcessing; 73 /** 74 * protocols allowed for external DTD references in source file and/or stylesheet. 75 */ 76 private String _accessExternalDTD = XalanConstants.EXTERNAL_ACCESS_DEFAULT; 77 78 private XMLSecurityManager _xmlSecurityManager; 79 80 //Catalog Feature 81 private boolean _useCatalog; 82 private CatalogFeatures _catalogFeatures; 83 84 private int _cdataChunkSize; 85 86 /** 87 * Hidden constructor 88 */ 89 private XMLReaderManager() { 90 } 91 92 /** 93 * Retrieves the singleton reader manager 94 */ 95 public static XMLReaderManager getInstance(boolean useServicesMechanism) { 96 m_singletonManager.setServicesMechnism(useServicesMechanism); 97 return m_singletonManager; 98 } 99 100 /** 101 * Retrieves a cached XMLReader for this thread, or creates a new 102 * XMLReader, if the existing reader is in use. When the caller no 103 * longer needs the reader, it must release it with a call to 104 * {@link #releaseXMLReader}. 105 */ 106 public synchronized XMLReader getXMLReader() throws SAXException { 107 XMLReader reader; 108 109 if (m_readers == null) { 110 // When the m_readers.get() method is called for the first time 111 // on a thread, a new XMLReader will automatically be created. 112 m_readers = new ThreadLocal<>(); 113 } 114 115 if (m_inUse == null) { 116 m_inUse = new HashMap<>(); 117 } 118 119 // If the cached reader for this thread is in use, construct a new 120 // one; otherwise, return the cached reader unless it isn't an 121 // instance of the class set in the 'org.xml.sax.driver' property 122 reader = m_readers.get(); 123 boolean threadHasReader = (reader != null); 124 String factory = SecuritySupport.getSystemProperty(property); 125 if (threadHasReader && m_inUse.get(reader) != Boolean.TRUE && 126 ( factory == null || reader.getClass().getName().equals(factory))) { 127 m_inUse.put(reader, Boolean.TRUE); 128 } else { 129 try { 130 try { 131 // According to JAXP 1.2 specification, if a SAXSource 132 // is created using a SAX InputSource the Transformer or 133 // TransformerFactory creates a reader via the 134 // XMLReaderFactory if setXMLReader is not used 135 reader = XMLReaderFactory.createXMLReader(); 136 try { 137 reader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, _secureProcessing); 138 } catch (SAXNotRecognizedException e) { 139 XMLSecurityManager.printWarning(reader.getClass().getName(), 140 XMLConstants.FEATURE_SECURE_PROCESSING, e); 141 } 142 } catch (SAXException e) { 143 try { 144 // If unable to create an instance, let's try to use 145 // the XMLReader from JAXP 146 if (m_parserFactory == null) { 147 m_parserFactory = FactoryImpl.getSAXFactory(m_useServicesMechanism); 148 m_parserFactory.setNamespaceAware(true); 149 } 150 151 reader = m_parserFactory.newSAXParser().getXMLReader(); 152 } catch (ParserConfigurationException pce) { 153 throw pce; // pass along pce 154 } 155 } 156 try { 157 reader.setFeature(NAMESPACES_FEATURE, true); 158 reader.setFeature(NAMESPACE_PREFIXES_FEATURE, false); 159 } catch (SAXException se) { 160 // Try to carry on if we've got a parser that 161 // doesn't know about namespace prefixes. 162 } 163 } catch (ParserConfigurationException ex) { 164 throw new SAXException(ex); 165 } catch (FactoryConfigurationError ex1) { 166 throw new SAXException(ex1.toString()); 167 } catch (NoSuchMethodError | AbstractMethodError ex2) { 168 } 169 170 // Cache the XMLReader if this is the first time we've created 171 // a reader for this thread. 172 if (!threadHasReader) { 173 m_readers.set(reader); 174 m_inUse.put(reader, Boolean.TRUE); 175 } 176 } 177 178 //reader is cached, but this property might have been reset 179 JdkXmlUtils.setXMLReaderPropertyIfSupport(reader, XMLConstants.ACCESS_EXTERNAL_DTD, 180 _accessExternalDTD, true); 181 182 JdkXmlUtils.setXMLReaderPropertyIfSupport(reader, JdkXmlUtils.CDATA_CHUNK_SIZE, 183 _cdataChunkSize, false); 184 185 String lastProperty = ""; 186 try { 187 if (_xmlSecurityManager != null) { 188 for (XMLSecurityManager.Limit limit : XMLSecurityManager.Limit.values()) { 189 lastProperty = limit.apiProperty(); 190 reader.setProperty(lastProperty, 191 _xmlSecurityManager.getLimitValueAsString(limit)); 192 } 193 if (_xmlSecurityManager.printEntityCountInfo()) { 194 lastProperty = XalanConstants.JDK_ENTITY_COUNT_INFO; 195 reader.setProperty(XalanConstants.JDK_ENTITY_COUNT_INFO, XalanConstants.JDK_YES); 196 } 197 } 198 } catch (SAXException se) { 199 XMLSecurityManager.printWarning(reader.getClass().getName(), lastProperty, se); 200 } 201 202 boolean supportCatalog = true; 203 try { 204 reader.setFeature(JdkXmlUtils.USE_CATALOG, _useCatalog); 205 } 206 catch (SAXNotRecognizedException | SAXNotSupportedException e) { 207 supportCatalog = false; 208 } 209 210 if (supportCatalog && _useCatalog && _catalogFeatures != null) { 211 try { 212 for (CatalogFeatures.Feature f : CatalogFeatures.Feature.values()) { 213 reader.setProperty(f.getPropertyName(), _catalogFeatures.get(f)); 214 } 215 } catch (SAXNotRecognizedException e) { 216 //shall not happen for internal settings 217 } 218 } 219 return reader; 220 } 221 222 /** 223 * Mark the cached XMLReader as available. If the reader was not 224 * actually in the cache, do nothing. 225 * 226 * @param reader The XMLReader that's being released. 227 */ 228 public synchronized void releaseXMLReader(XMLReader reader) { 229 // If the reader that's being released is the cached reader 230 // for this thread, remove it from the m_isUse list. 231 if (m_readers.get() == reader && reader != null) { 232 m_inUse.remove(reader); 233 } 234 } 235 /** 236 * Return the state of the services mechanism feature. 237 */ 238 public boolean useServicesMechnism() { 239 return m_useServicesMechanism; 240 } 241 242 /** 243 * Set the state of the services mechanism feature. 244 */ 245 public void setServicesMechnism(boolean flag) { 246 m_useServicesMechanism = flag; 247 } 248 249 /** 250 * Set feature 251 */ 252 public void setFeature(String name, boolean value) { 253 if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { 254 _secureProcessing = value; 255 } else if (XMLConstants.USE_CATALOG.equals(name)) { 256 _useCatalog = value; 257 } 258 } 259 260 /** 261 * Get property value 262 */ 263 public Object getProperty(String name) { 264 if (name.equals(XMLConstants.ACCESS_EXTERNAL_DTD)) { 265 return _accessExternalDTD; 266 } else if (name.equals(XalanConstants.SECURITY_MANAGER)) { 267 return _xmlSecurityManager; 268 } 269 return null; 270 } 271 272 /** 273 * Set property. 274 */ 275 public void setProperty(String name, Object value) { 276 if (name.equals(XMLConstants.ACCESS_EXTERNAL_DTD)) { 277 _accessExternalDTD = (String)value; 278 } else if (name.equals(XalanConstants.SECURITY_MANAGER)) { 279 _xmlSecurityManager = (XMLSecurityManager)value; 280 } else if (JdkXmlFeatures.CATALOG_FEATURES.equals(name)) { 281 _catalogFeatures = (CatalogFeatures)value; 282 } else if (JdkXmlUtils.CDATA_CHUNK_SIZE.equals(name)) { 283 _cdataChunkSize = JdkXmlUtils.getValue(value, _cdataChunkSize); 284 } 285 } 286 }