• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 package software.amazon.awssdk.protocol.asserts.marshalling;
17 
18 import static org.junit.Assert.fail;
19 
20 import java.io.StringWriter;
21 import java.io.Writer;
22 import javax.xml.XMLConstants;
23 import javax.xml.parsers.DocumentBuilder;
24 import javax.xml.parsers.DocumentBuilderFactory;
25 import javax.xml.parsers.ParserConfigurationException;
26 import javax.xml.transform.OutputKeys;
27 import javax.xml.transform.Transformer;
28 import javax.xml.transform.TransformerFactory;
29 import javax.xml.transform.dom.DOMSource;
30 import javax.xml.transform.stream.StreamResult;
31 import org.custommonkey.xmlunit.Diff;
32 import org.custommonkey.xmlunit.examples.RecursiveElementNameAndTextQualifier;
33 import org.w3c.dom.Document;
34 import software.amazon.awssdk.utils.StringInputStream;
35 
36 public final class XmlAsserts {
37 
38     private static final DocumentBuilder DOCUMENT_BUILDER = getDocumentBuilder();
39 
XmlAsserts()40     private XmlAsserts() {
41     }
42 
getDocumentBuilder()43     private static DocumentBuilder getDocumentBuilder() {
44         DocumentBuilderFactory dbf = newSecureDocumentBuilderFactory();
45         try {
46             return dbf.newDocumentBuilder();
47         } catch (ParserConfigurationException e) {
48             throw new RuntimeException(e);
49         }
50     }
51 
assertXmlEquals(String expectedXml, String actualXml)52     public static void assertXmlEquals(String expectedXml, String actualXml) {
53         try {
54             doAssertXmlEquals(expectedXml, actualXml);
55         } catch (Exception e) {
56             e.printStackTrace();
57             fail(e.getMessage());
58         }
59     }
60 
doAssertXmlEquals(String expectedXml, String actualXml)61     private static void doAssertXmlEquals(String expectedXml, String actualXml) throws Exception {
62         Diff diff = new Diff(expectedXml, actualXml);
63         diff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
64         if (!diff.similar()) {
65             fail("\nExpected the following XML\n" + formatXml(expectedXml) +
66                  "\nbut actual XML was\n\n" +
67                  formatXml(actualXml));
68         }
69     }
70 
formatXml(String xmlDocumentString)71     private static String formatXml(String xmlDocumentString) throws Exception {
72         return formatXml(DOCUMENT_BUILDER.parse(new StringInputStream(xmlDocumentString)));
73     }
74 
formatXml(Document xmlDocument)75     private static String formatXml(Document xmlDocument) throws Exception {
76         Transformer transformer = newSecureTransformerFactory().newTransformer();
77         transformer.setOutputProperty(OutputKeys.INDENT, "yes");
78         StreamResult result = new StreamResult(new StringWriter());
79         DOMSource source = new DOMSource(xmlDocument);
80         transformer.transform(source, result);
81         try (Writer writer = result.getWriter()) {
82             return writer.toString();
83         }
84     }
85 
newSecureDocumentBuilderFactory()86     private static DocumentBuilderFactory newSecureDocumentBuilderFactory() {
87         DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
88         docFactory.setXIncludeAware(false);
89         docFactory.setExpandEntityReferences(false);
90         trySetFeature(docFactory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
91         trySetFeature(docFactory, "http://apache.org/xml/features/disallow-doctype-decl", true);
92         trySetFeature(docFactory, "http://xml.org/sax/features/external-general-entities", false);
93         trySetFeature(docFactory, "http://xml.org/sax/features/external-parameter-entities", false);
94         trySetAttribute(docFactory, "http://javax.xml.XMLConstants/property/accessExternalDTD", "");
95         trySetAttribute(docFactory, "http://javax.xml.XMLConstants/property/accessExternalSchema", "");
96         return docFactory;
97     }
98 
newSecureTransformerFactory()99     private static TransformerFactory newSecureTransformerFactory() {
100         TransformerFactory transformerFactory = TransformerFactory.newInstance();
101         trySetAttribute(transformerFactory, XMLConstants.ACCESS_EXTERNAL_DTD, "");
102         trySetAttribute(transformerFactory, XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
103         return transformerFactory;
104     }
105 
trySetFeature(DocumentBuilderFactory factory, String feature, boolean value)106     private static void trySetFeature(DocumentBuilderFactory factory, String feature, boolean value) {
107         try {
108             factory.setFeature(feature, value);
109         } catch (Exception e) {
110             throw new RuntimeException(e);
111         }
112     }
113 
trySetAttribute(DocumentBuilderFactory factory, String feature, String value)114     private static void trySetAttribute(DocumentBuilderFactory factory, String feature, String value) {
115         try {
116             factory.setAttribute(feature, value);
117         } catch (Exception e) {
118             throw new RuntimeException(e);
119         }
120     }
121 
trySetAttribute(TransformerFactory factory, String feature, Object value)122     private static void trySetAttribute(TransformerFactory factory, String feature, Object value) {
123         try {
124             factory.setAttribute(feature, value);
125         } catch (Exception e) {
126             throw new RuntimeException(e);
127         }
128     }
129 }
130