xref: /aosp_15_r20/external/gturri-aXMLRPC/src/main/java/de/timroes/axmlrpc/ResponseParser.java (revision 1b3e0c610889c330a4f530b7731f3b672f65ccad)
1 package de.timroes.axmlrpc;
2 
3 import de.timroes.axmlrpc.serializer.SerializerHandler;
4 
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.OutputStream;
8 import java.io.OutputStreamWriter;
9 import java.util.Map;
10 
11 import javax.xml.parsers.DocumentBuilder;
12 import javax.xml.parsers.DocumentBuilderFactory;
13 import javax.xml.parsers.ParserConfigurationException;
14 import javax.xml.transform.OutputKeys;
15 import javax.xml.transform.Transformer;
16 import javax.xml.transform.TransformerException;
17 import javax.xml.transform.TransformerFactory;
18 import javax.xml.transform.dom.DOMSource;
19 import javax.xml.transform.stream.StreamResult;
20 
21 import org.w3c.dom.Document;
22 import org.w3c.dom.Element;
23 
24 /**
25  * The ResponseParser parses the response of an XMLRPC server to an object.
26  *
27  * @author Tim Roes
28  */
29 public class ResponseParser {
30 
31 	private static final String FAULT_CODE = "faultCode";
32 	private static final String FAULT_STRING = "faultString";
33 
34 	/**
35 	 * The given InputStream must contain the xml response from an xmlrpc server.
36 	 * This method extract the content of it as an object.
37 	 *
38 	 * @param serializerHandler You can inject an arbitrary one if you want to use your own transport protocol.
39 	 *     See the README (section "Using an arbitrary transport") for more info on this feature.
40 	 * @param response The InputStream of the server response.
41 	 * @param debugMode This prints data on System.out to make it easy to debug
42 	 * @return The returned object.
43 	 * @throws XMLRPCException Will be thrown whenever something fails.
44 	 * @throws XMLRPCServerException Will be thrown, if the server returns an error.
45 	 */
parse(SerializerHandler serializerHandler, InputStream response, boolean debugMode)46 	public Object parse(SerializerHandler serializerHandler, InputStream response, boolean debugMode) throws XMLRPCException {
47 
48 		try {
49 			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
50 
51 			// Ensure the xml parser won't allow exploitation of the vuln CWE-611
52 			// (described on https://cwe.mitre.org/data/definitions/611.html )
53 			factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
54 			factory.setExpandEntityReferences(false);
55 			factory.setNamespaceAware(true);
56 			factory.setXIncludeAware(false);
57 			factory.setExpandEntityReferences(false);
58 			// End of the configuration of the parser for CWE-611
59 
60 			DocumentBuilder builder = factory.newDocumentBuilder();
61 			Document dom = builder.parse(response);
62 			if (debugMode ){
63 				printDocument(dom, System.out);
64 			}
65 			Element e = dom.getDocumentElement();
66 
67 
68 			// Check for root tag
69 			if(!e.getNodeName().equals(XMLRPCClient.METHOD_RESPONSE)) {
70 				throw new XMLRPCException("MethodResponse root tag is missing.");
71 			}
72 
73 			e = XMLUtil.getOnlyChildElement(e.getChildNodes());
74 
75 			if(e.getNodeName().equals(XMLRPCClient.PARAMS)) {
76 
77 				e = XMLUtil.getOnlyChildElement(e.getChildNodes());
78 
79 				if(!e.getNodeName().equals(XMLRPCClient.PARAM)) {
80 					throw new XMLRPCException("The params tag must contain a param tag.");
81 				}
82 
83 				return getReturnValueFromElement(serializerHandler, e);
84 
85 			} else if(e.getNodeName().equals(XMLRPCClient.FAULT)) {
86 
87 				@SuppressWarnings("unchecked")
88 				Map<String,Object> o = (Map<String,Object>)getReturnValueFromElement(serializerHandler, e);
89 
90 				throw new XMLRPCServerException((String)o.get(FAULT_STRING), (Integer)o.get(FAULT_CODE));
91 
92 			}
93 
94 			throw new XMLRPCException("The methodResponse tag must contain a fault or params tag.");
95 
96 		} catch(XMLRPCServerException e) {
97 			throw e;
98 		} catch (Exception ex) {
99 			throw new XMLRPCException("Error getting result from server.", ex);
100 		}
101 
102 	}
103 
printDocument(Document doc, OutputStream out)104 	public static void printDocument(Document doc, OutputStream out) throws IOException, TransformerException {
105 		TransformerFactory tf = TransformerFactory.newInstance();
106 		Transformer transformer = tf.newTransformer();
107 		transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
108 		transformer.setOutputProperty(OutputKeys.METHOD, "xml");
109 		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
110 		transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
111 		transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
112 
113 		transformer.transform(new DOMSource(doc),
114 				new StreamResult(new OutputStreamWriter(out, "UTF-8")));
115 	}
116 
117 	/**
118 	 * This method takes an element (must be a param or fault element) and
119 	 * returns the deserialized object of this param tag.
120 	 *
121 	 * @param element An param element.
122 	 * @return The deserialized object within the given param element.
123 	 * @throws XMLRPCException Will be thrown when the structure of the document
124 	 *		doesn't match the XML-RPC specification.
125 	 */
getReturnValueFromElement(SerializerHandler serializerHandler, Element element)126 	private Object getReturnValueFromElement(SerializerHandler serializerHandler, Element element) throws XMLRPCException {
127 
128 		Element childElement = XMLUtil.getOnlyChildElement(element.getChildNodes());
129 
130 		return serializerHandler.deserialize(childElement);
131 	}
132 
133 }
134