2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.util.xml;
10 import com.google.common.annotations.Beta;
11 import java.io.InputStream;
12 import java.io.Reader;
13 import java.nio.charset.Charset;
14 import java.util.function.Supplier;
15 import javax.xml.XMLConstants;
16 import javax.xml.parsers.DocumentBuilder;
17 import javax.xml.parsers.DocumentBuilderFactory;
18 import javax.xml.parsers.ParserConfigurationException;
19 import javax.xml.parsers.SAXParser;
20 import javax.xml.parsers.SAXParserFactory;
21 import javax.xml.stream.XMLInputFactory;
22 import javax.xml.stream.XMLStreamException;
23 import javax.xml.stream.XMLStreamReader;
24 import org.eclipse.jdt.annotation.NonNull;
25 import org.opendaylight.yangtools.util.ClassLoaderUtils;
26 import org.xml.sax.SAXException;
27 import org.xml.sax.SAXNotRecognizedException;
28 import org.xml.sax.SAXNotSupportedException;
31 * Set of utility methods for instantiating parser that deal with untrusted XML sources.
33 * @author Robert Varga
36 public final class UntrustedXML {
37 private static final @NonNull DocumentBuilderFactory DBF;
40 final DocumentBuilderFactory f = getLimited(DocumentBuilderFactory::newInstance);
41 f.setCoalescing(true);
42 f.setExpandEntityReferences(false);
43 f.setIgnoringElementContentWhitespace(true);
44 f.setIgnoringComments(true);
45 f.setNamespaceAware(true);
46 f.setXIncludeAware(false);
48 f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
49 f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
50 f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
51 f.setFeature("http://xml.org/sax/features/external-general-entities", false);
52 f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
53 } catch (final ParserConfigurationException e) {
54 throw new ExceptionInInitializerError(e);
59 private static final SAXParserFactory SPF;
62 final SAXParserFactory f = getLimited(SAXParserFactory::newInstance);
63 f.setNamespaceAware(true);
64 f.setXIncludeAware(false);
66 f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
67 f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
68 f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
69 f.setFeature("http://xml.org/sax/features/external-general-entities", false);
70 f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
71 } catch (final SAXNotRecognizedException | SAXNotSupportedException | ParserConfigurationException e) {
72 throw new ExceptionInInitializerError(e);
78 private static final XMLInputFactory XIF;
81 final XMLInputFactory f = getLimited(XMLInputFactory::newInstance);
82 f.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
83 f.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.TRUE);
84 f.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
85 f.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
90 private UntrustedXML() {
95 * Create a new {@link DocumentBuilder} for dealing with untrusted XML data. This method is equivalent to
96 * {@link DocumentBuilderFactory#newDocumentBuilder()}, except it does not throw a checked exception.
98 * @return A new DocumentBuilder
99 * @throws UnsupportedOperationException if the runtime fails to instantiate a good enough builder
101 public static @NonNull DocumentBuilder newDocumentBuilder() {
103 return DBF.newDocumentBuilder();
104 } catch (ParserConfigurationException e) {
105 throw new UnsupportedOperationException("Failed to instantiate a DocumentBuilder", e);
110 * Create a new {@link SAXParser} for dealing with untrusted XML data. This method is equivalent to
111 * {@link SAXParserFactory#newSAXParser()}, except it does not throw a checked exception.
113 * @return A new SAXParser
114 * @throws UnsupportedOperationException if the runtime fails to instantiate a good enough builder
116 public static @NonNull SAXParser newSAXParser() {
118 return SPF.newSAXParser();
119 } catch (ParserConfigurationException | SAXException e) {
120 throw new UnsupportedOperationException("Failed to instantiate a SAXParser", e);
125 * Create a new {@link XMLStreamReader} for dealing with untrusted XML data. This method is equivalent to
126 * {@link XMLInputFactory#createXMLStreamReader(InputStream)}.
128 * @return A new XMLStreamReader
129 * @throws XMLStreamException when the underlying factory throws it
131 public static @NonNull XMLStreamReader createXMLStreamReader(final InputStream stream) throws XMLStreamException {
132 return XIF.createXMLStreamReader(stream);
136 * Create a new {@link XMLStreamReader} for dealing with untrusted XML data. This method is equivalent to
137 * {@link XMLInputFactory#createXMLStreamReader(InputStream, String)}, except it takes an explict charset argument.
139 * @return A new XMLStreamReader
140 * @throws XMLStreamException when the underlying factory throws it
142 public static @NonNull XMLStreamReader createXMLStreamReader(final InputStream stream, final Charset charset)
143 throws XMLStreamException {
144 return XIF.createXMLStreamReader(stream, charset.name());
148 * Create a new {@link XMLStreamReader} for dealing with untrusted XML data. This method is equivalent to
149 * {@link XMLInputFactory#createXMLStreamReader(Reader)}.
151 * @return A new XMLStreamReader
152 * @throws XMLStreamException when the underlying factory throws it
154 public static @NonNull XMLStreamReader createXMLStreamReader(final Reader reader) throws XMLStreamException {
155 return XIF.createXMLStreamReader(reader);
158 private static <T> T getLimited(final @NonNull Supplier<T> supplier) {
159 final ClassLoader loader = UntrustedXML.class.getClassLoader();
160 return loader == null ? supplier.get() : ClassLoaderUtils.getWithClassLoader(loader, supplier);