05ef089bdb7ede0a1a577f77f67e13b04b54551b
[yangtools.git] / common / util / src / main / java / org / opendaylight / yangtools / util / xml / UntrustedXML.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.util.xml;
9
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 javax.annotation.Nonnull;
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.xml.sax.SAXException;
25
26 /**
27  * Set of utility methods for instantiating parser that deal with untrusted XML sources.
28  *
29  * @author Robert Varga
30  */
31 @Beta
32 public final class UntrustedXML {
33     private static final DocumentBuilderFactory DBF;
34     static {
35         final DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
36         f.setCoalescing(true);
37         f.setExpandEntityReferences(false);
38         f.setIgnoringElementContentWhitespace(true);
39         f.setIgnoringComments(true);
40         f.setNamespaceAware(true);
41         f.setXIncludeAware(false);
42         try {
43             f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
44             f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
45             f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
46             f.setFeature("http://xml.org/sax/features/external-general-entities", false);
47             f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
48         } catch (final ParserConfigurationException e) {
49             throw new ExceptionInInitializerError(e);
50         }
51         DBF = f;
52     }
53
54     private static final SAXParserFactory SPF;
55     static {
56         final SAXParserFactory f = SAXParserFactory.newInstance();
57         f.setNamespaceAware(true);
58         f.setXIncludeAware(false);
59         try {
60             f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
61             f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
62             f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
63             f.setFeature("http://xml.org/sax/features/external-general-entities", false);
64             f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
65         } catch (final Exception e) {
66             throw new ExceptionInInitializerError(e);
67         }
68
69         SPF = f;
70     }
71
72     private static final XMLInputFactory XIF;
73     static {
74         final XMLInputFactory f = XMLInputFactory.newInstance();
75
76         f.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
77         f.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.TRUE);
78         f.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
79         f.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
80
81         XIF = f;
82     }
83
84
85     /**
86      * Create a new {@link DocumentBuilder} for dealing with untrusted XML data. This method is equivalent to
87      * {@link DocumentBuilderFactory#newDocumentBuilder()}, except it does not throw a checked exception.
88      *
89      * @return A new DocumentBuilder
90      * @throws UnsupportedOperationException if the runtime fails to instantiate a good enough builder
91      */
92     public static @Nonnull DocumentBuilder newDocumentBuilder() {
93         try {
94             return DBF.newDocumentBuilder();
95         } catch (ParserConfigurationException e) {
96             throw new UnsupportedOperationException("Failed to instantiate a DocumentBuilder", e);
97         }
98     }
99
100     /**
101      * Create a new {@link SAXParser} for dealing with untrusted XML data. This method is equivalent to
102      * {@link SAXParserFactory#newSAXParser()}, except it does not throw a checked exception.
103      *
104      * @return A new SAXParser
105      * @throws UnsupportedOperationException if the runtime fails to instantiate a good enough builder
106      */
107     public static @Nonnull SAXParser newSAXParser() {
108         try {
109             return SPF.newSAXParser();
110         } catch (ParserConfigurationException | SAXException e) {
111             throw new UnsupportedOperationException("Failed to instantiate a SAXParser", e);
112         }
113     }
114
115     /**
116      * Create a new {@link XMLStreamReader} for dealing with untrusted XML data. This method is equivalent to
117      * {@link XMLInputFactory#createXMLStreamReader(InputStream)}.
118      *
119      * @return A new XMLStreamReader
120      * @throws XMLStreamException when the underlying factory throws it
121      */
122     public static @Nonnull XMLStreamReader createXMLStreamReader(final InputStream stream) throws XMLStreamException {
123         return XIF.createXMLStreamReader(stream);
124     }
125
126     /**
127      * Create a new {@link XMLStreamReader} for dealing with untrusted XML data. This method is equivalent to
128      * {@link XMLInputFactory#createXMLStreamReader(InputStream, String)}, except it takes an explict charset argument.
129      *
130      * @return A new XMLStreamReader
131      * @throws XMLStreamException when the underlying factory throws it
132      */
133     public static @Nonnull XMLStreamReader createXMLStreamReader(final InputStream stream, final Charset charset)
134             throws XMLStreamException {
135         return XIF.createXMLStreamReader(stream, charset.name());
136     }
137
138     /**
139      * Create a new {@link XMLStreamReader} for dealing with untrusted XML data. This method is equivalent to
140      * {@link XMLInputFactory#createXMLStreamReader(Reader)}.
141      *
142      * @return A new XMLStreamReader
143      * @throws XMLStreamException when the underlying factory throws it
144      */
145     public static @Nonnull XMLStreamReader createXMLStreamReader(final Reader reader) throws XMLStreamException {
146         return XIF.createXMLStreamReader(reader);
147     }
148 }