source: josm/trunk/src/org/openstreetmap/josm/tools/XmlUtils.java@ 17379

Last change on this file since 17379 was 16560, checked in by simon04, 4 years ago

fix #19286 - External entities are resolved when parsing tagging presets (patch by hiddewie, modified)

  • Property svn:eol-style set to native
File size: 7.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.io.IOException;
5import java.io.InputStream;
6import java.util.stream.IntStream;
7
8import javax.xml.XMLConstants;
9import javax.xml.parsers.DocumentBuilder;
10import javax.xml.parsers.DocumentBuilderFactory;
11import javax.xml.parsers.ParserConfigurationException;
12import javax.xml.parsers.SAXParser;
13import javax.xml.parsers.SAXParserFactory;
14import javax.xml.stream.XMLInputFactory;
15import javax.xml.transform.TransformerConfigurationException;
16import javax.xml.transform.TransformerFactory;
17import javax.xml.validation.Schema;
18import javax.xml.validation.SchemaFactory;
19import javax.xml.validation.SchemaFactoryConfigurationError;
20import javax.xml.validation.Validator;
21
22import org.w3c.dom.Document;
23import org.w3c.dom.Element;
24import org.w3c.dom.Node;
25import org.w3c.dom.NodeList;
26import org.xml.sax.InputSource;
27import org.xml.sax.SAXException;
28import org.xml.sax.SAXNotRecognizedException;
29import org.xml.sax.SAXNotSupportedException;
30import org.xml.sax.helpers.DefaultHandler;
31
32/**
33 * XML utils, mainly used to construct safe factories.
34 * @since 13901
35 */
36public final class XmlUtils {
37
38 private static final String FEATURE_DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
39
40 private XmlUtils() {
41 // Hide default constructor for utils classes
42 }
43
44 /**
45 * Returns the W3C XML Schema factory implementation. Robust method dealing with ContextClassLoader problems.
46 * @return the W3C XML Schema factory implementation
47 */
48 public static SchemaFactory newXmlSchemaFactory() {
49 try {
50 return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
51 } catch (SchemaFactoryConfigurationError e) {
52 Logging.debug(e);
53 // Can happen with icedtea-web. Use workaround from https://issues.apache.org/jira/browse/GERONIMO-6185
54 Thread currentThread = Thread.currentThread();
55 ClassLoader old = currentThread.getContextClassLoader();
56 currentThread.setContextClassLoader(null);
57 try {
58 return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
59 } finally {
60 currentThread.setContextClassLoader(old);
61 }
62 }
63 }
64
65 /**
66 * Returns a new secure DOM builder, supporting XML namespaces.
67 * @return a new secure DOM builder, supporting XML namespaces
68 * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
69 */
70 public static DocumentBuilder newSafeDOMBuilder() throws ParserConfigurationException {
71 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
72 builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
73 builderFactory.setNamespaceAware(true);
74 builderFactory.setValidating(false);
75 return builderFactory.newDocumentBuilder();
76 }
77
78 /**
79 * Parse the content given {@link InputStream} as XML.
80 * This method uses a secure DOM builder, supporting XML namespaces.
81 *
82 * @param is The InputStream containing the content to be parsed.
83 * @return the result DOM document
84 * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
85 * @throws IOException if any IO errors occur.
86 * @throws SAXException for SAX errors.
87 */
88 public static Document parseSafeDOM(InputStream is) throws ParserConfigurationException, IOException, SAXException {
89 Stopwatch stopwatch = Stopwatch.createStarted();
90 Logging.debug("Starting DOM parsing of {0}", is);
91 Document result = newSafeDOMBuilder().parse(is);
92 Logging.debug(stopwatch.toString("DOM parsing"));
93 return result;
94 }
95
96 /**
97 * Returns a new secure SAX parser, supporting XML namespaces.
98 * @return a new secure SAX parser, supporting XML namespaces
99 * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
100 * @throws SAXException for SAX errors.
101 */
102 public static SAXParser newSafeSAXParser() throws ParserConfigurationException, SAXException {
103 SAXParserFactory parserFactory = SAXParserFactory.newInstance();
104 parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
105 parserFactory.setFeature(FEATURE_DISALLOW_DOCTYPE_DECL, true);
106 parserFactory.setNamespaceAware(true);
107 return parserFactory.newSAXParser();
108 }
109
110 /**
111 * Parse the content given {@link org.xml.sax.InputSource} as XML using the specified {@link org.xml.sax.helpers.DefaultHandler}.
112 * This method uses a secure SAX parser, supporting XML namespaces.
113 *
114 * @param is The InputSource containing the content to be parsed.
115 * @param dh The SAX DefaultHandler to use.
116 * @throws ParserConfigurationException if a parser cannot be created which satisfies the requested configuration.
117 * @throws SAXException for SAX errors.
118 * @throws IOException if any IO errors occur.
119 */
120 public static void parseSafeSAX(InputSource is, DefaultHandler dh) throws ParserConfigurationException, SAXException, IOException {
121 Stopwatch stopwatch = Stopwatch.createStarted();
122 Logging.debug("Starting SAX parsing of {0} using {1}", is, dh);
123 newSafeSAXParser().parse(is, dh);
124 Logging.debug(stopwatch.toString("SAX parsing"));
125 }
126
127 /**
128 * Returns a new secure {@link XMLInputFactory}.
129 * @return a new secure {@code XMLInputFactory}, for which external entities are not loaded
130 */
131 public static XMLInputFactory newSafeXMLInputFactory() {
132 XMLInputFactory factory = XMLInputFactory.newInstance();
133 // do not try to load external entities, nor validate the XML
134 factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
135 factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
136 factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
137 return factory;
138 }
139
140 /**
141 * Returns a new secure {@link TransformerFactory}.
142 * @return a new secure {@link TransformerFactory}
143 * @throws TransformerConfigurationException if the factory or the Transformers or Templates it creates cannot support this feature.
144 */
145 public static TransformerFactory newSafeTransformerFactory() throws TransformerConfigurationException {
146 TransformerFactory factory = TransformerFactory.newInstance();
147 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
148 return factory;
149 }
150
151 /**
152 * Returns a new secure {@link Validator}.
153 * @param schema XML schema
154 * @return a new secure {@link Validator}
155 * @since 14441
156 */
157 public static Validator newSafeValidator(Schema schema) {
158 Validator validator = schema.newValidator();
159 try {
160 validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
161 validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
162 } catch (SAXNotRecognizedException | SAXNotSupportedException e) {
163 // All implementations that implement JAXP 1.5 or newer are required to support these two properties
164 Logging.trace(e);
165 }
166 return validator;
167 }
168
169 /**
170 * Get the first child element
171 * @param parent parent node
172 * @return the first child element
173 * @since 14348
174 */
175 public static Element getFirstChildElement(Node parent) {
176 NodeList children = parent.getChildNodes();
177 return (Element) IntStream.range(0, children.getLength())
178 .mapToObj(children::item)
179 .filter(child -> child instanceof Element)
180 .findFirst().orElse(null);
181 }
182}
Note: See TracBrowser for help on using the repository browser.