[Git][java-team/axmlrpc][upstream] 4 commits: New upstream version 1.14.0

Emmanuel Bourg (@ebourg) gitlab at salsa.debian.org
Thu Sep 24 13:40:11 BST 2026



Emmanuel Bourg pushed to branch upstream at Debian Java Maintainers / axmlrpc


Commits:
6ed4029d by Emmanuel Bourg at 2026-09-24T13:22:09+02:00
New upstream version 1.14.0
- - - - -
54375d70 by Emmanuel Bourg at 2026-09-24T13:48:02+02:00
New upstream version 1.15.0
- - - - -
20a79618 by Emmanuel Bourg at 2026-09-24T13:57:09+02:00
New upstream version 1.16.0
- - - - -
bb3c5398 by Emmanuel Bourg at 2026-09-24T14:02:40+02:00
New upstream version 1.17.0
- - - - -


9 changed files:

- Changelog
- README.md
- pom.xml
- src/main/java/de/timroes/axmlrpc/ResponseParser.java
- src/main/java/de/timroes/axmlrpc/XMLRPCClient.java
- src/main/java/de/timroes/axmlrpc/XMLRPCTimeoutException.java
- src/main/java/de/timroes/axmlrpc/XMLUtil.java
- src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java
- src/test/java/de/timroes/axmlrpc/serializer/TestResponseParser.java


Changes:

=====================================
Changelog
=====================================
@@ -1,3 +1,16 @@
+Fix options added in 1.15.0 (those were not usable)
+
+1.15.0
+Add
+- setConnectTimeout
+- setReadTimeout
+- callWithOverridenTimeout
+
+1.14.0
+Fix security issue CWE-611
+Add support for CDATA section in the server response
+
+1.13.0
 DateTime serializer format is now injectable
 
 1.12.1


=====================================
README.md
=====================================
@@ -5,10 +5,6 @@ aXMLRPC is a Java library with a leightweight XML-RPC client. XML-RPC is
 a specification for making remote procedure calls over the HTTP protocol
 in an XML format. The specificationc can be found under http://www.xmlrpc.com/spec.
 
-The library was developed for the use with Android. Since it has no dependencies to 
-any Android library or any other 3rd-party library, it is fully functional in any
-common java virtual machine (not only on Android).
-
 You can control the client with some flags to extend its functionality. See the section
 about flags.
 


=====================================
pom.xml
=====================================
@@ -3,7 +3,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>fr.turri</groupId>
 	<artifactId>aXMLRPC</artifactId>
-	<version>1.13.0</version>
+	<version>1.17.0</version>
 	<packaging>jar</packaging>
 	<name>aXMLRPC</name>
 	<description>Lightweight Java XML-RPC working also on Android.</description>
@@ -42,10 +42,15 @@
 			<artifactId>jISO8601</artifactId>
 			<version>0.2</version>
 		</dependency>
+        <dependency>
+            <groupId>xerces</groupId>
+            <artifactId>xercesImpl</artifactId>
+            <version>2.12.2</version>
+        </dependency>
         <dependency>
           <groupId>com.github.tomakehurst</groupId>
           <artifactId>wiremock-jre8</artifactId>
-          <version>2.28.0</version>
+          <version>2.35.1</version>
           <scope>test</scope>
         </dependency>
 	</dependencies>
@@ -53,7 +58,7 @@
         <connection>scm:git:https://github.com/gturri/aXMLRPC.git</connection>
         <developerConnection>scm:git:git at github.com:gturri/aXMLRPC.git</developerConnection>
         <url>https://github.com/gturri/aXMLRPC</url>
-        <tag>aXMLRPC-1.13.0</tag>
+        <tag>aXMLRPC-1.17.0</tag>
 	</scm>
     <build>
       <pluginManagement>


=====================================
src/main/java/de/timroes/axmlrpc/ResponseParser.java
=====================================
@@ -10,6 +10,7 @@ import java.util.Map;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
@@ -45,9 +46,17 @@ public class ResponseParser {
 	public Object parse(SerializerHandler serializerHandler, InputStream response, boolean debugMode) throws XMLRPCException {
 
 		try {
-
 			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
+			// Ensure the xml parser won't allow exploitation of the vuln CWE-611
+			// (described on https://cwe.mitre.org/data/definitions/611.html )
+			factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+			factory.setExpandEntityReferences(false);
 			factory.setNamespaceAware(true);
+			factory.setXIncludeAware(false);
+			factory.setExpandEntityReferences(false);
+			// End of the configuration of the parser for CWE-611
+
 			DocumentBuilder builder = factory.newDocumentBuilder();
 			Document dom = builder.parse(response);
 			if (debugMode ){


=====================================
src/main/java/de/timroes/axmlrpc/XMLRPCClient.java
=====================================
@@ -196,7 +196,8 @@ public class XMLRPCClient {
 
 	private Proxy proxy;
 
-	private int timeout;
+	private int connectTimeout;
+	private int readTimeout;
 	private final SerializerHandler serializerHandler;
 
 	/**
@@ -296,7 +297,7 @@ public class XMLRPCClient {
 	}
 
 	/**
-	 * Sets the time in seconds after which a call should timeout.
+	 * Set both the connect timeout and the read timeout.
 	 * If {@code timeout} will be zero or less the connection will never timeout.
 	 * In case the connection times out an {@link XMLRPCTimeoutException} will
 	 * be thrown for calls made by {@link #call(java.lang.String, java.lang.Object[])}.
@@ -307,7 +308,16 @@ public class XMLRPCClient {
 	 * @param timeout The timeout for connections in seconds.
 	 */
 	public void setTimeout(int timeout) {
-		this.timeout = timeout;
+		this.connectTimeout = timeout;
+		this.readTimeout = timeout;
+	}
+
+	public void setConnectTimeout(int timeout) {
+		this.connectTimeout = timeout;
+	}
+
+	public void setReadTimeout(int timeout) {
+		this.readTimeout = timeout;
 	}
 
 	/**
@@ -460,11 +470,31 @@ public class XMLRPCClient {
 	 *
 	 * @param method A method name to call.
 	 * @param params An array of parameters for the method.
-	 * @return The result of the server.
+	 * @return The result of the call.
 	 * @throws XMLRPCException Will be thrown if an error occurred during the call.
 	 */
 	public Object call(String method, Object... params) throws XMLRPCException {
-		return new Caller().call(method, params);
+		return callWithOverriddenTimeout(method, connectTimeout, readTimeout, params);
+	}
+
+	/**
+	 * Call a remote procedure on the server. The method must be described by
+	 * a method name. If the method requires parameters, this must be set.
+	 * The type of the return object depends on the server. You should consult
+	 * the server documentation and then cast the return value according to that.
+	 * This method will block until the server returned a result (or an error occurred).
+	 * Read the README file delivered with the source code of this library for more
+	 * information.
+	 *
+	 * @param method A method name to call.
+	 * @param connectTimeout The connect timeout to use for this call.
+	 * @param readTimeout The read timeout to use for this call.
+	 * @param params An array of parameters for the method.
+	 * @return The result of the call.
+	 * @throws XMLRPCException Will be thrown if an error occurred during the call.
+	 */
+	public Object callWithOverriddenTimeout(String method, int connectTimeout, int readTimeout, Object[] params) throws XMLRPCException {
+		return new Caller().call(method, connectTimeout, readTimeout, params);
 	}
 
 	/**
@@ -483,8 +513,33 @@ public class XMLRPCClient {
 	 * @return The id of the current request.
 	 */
 	public long callAsync(XMLRPCCallback listener, String methodName, Object... params) {
+		return callAsyncWithOverriddenTimeout(listener, methodName, connectTimeout, readTimeout, params);
+	}
+
+	/**
+	 * Asynchronously call a remote procedure on the server. The method must be
+	 * described by a method name. If the method requires parameters, this must
+	 * be set. When the server returns a response the onResponse method is called
+	 * on the listener. If the server returns an error the onServerError method
+	 * is called on the listener. The onError method is called whenever something
+	 * fails. This method returns immediately and returns an identifier for the
+	 * request. All listener methods get this id as a parameter to distinguish
+	 * between
+	 * multiple requests.
+	 *
+	 * @param listener       A listener, which will be notified about the server
+	 *                       response or errors.
+	 * @param methodName     A method name to call on the server.
+	 * @param connectTimeout The connect timeout to use for this call.
+	 * @param readTimeout    The read timeout to use for this call.
+	 * @param params         An array of parameters for the method.
+	 * @return The id of the current request.
+	 */
+	public long callAsyncWithOverriddenTimeout(
+		XMLRPCCallback listener, String methodName, int connectTimeout, int readTimeout,
+		Object... params) {
 		long id = System.currentTimeMillis();
-		new Caller(listener, id, methodName, params).start();
+		new Caller(listener, id, methodName, connectTimeout, readTimeout, params).start();
 		return id;
 	}
 
@@ -549,6 +604,8 @@ public class XMLRPCClient {
 		private long threadId;
 		private String methodName;
 		private Object[] params;
+		private int connectTimeout;
+		private int readTimeout;
 
 		private volatile boolean canceled;
 		private HttpURLConnection http;
@@ -559,13 +616,18 @@ public class XMLRPCClient {
 		 * @param listener The listener to notice about the response or an error.
 		 * @param threadId An id that will be send to the listener.
 		 * @param methodName The method name to call.
+		 * @param connectTimeout The connect timeout to use for this call.
+		 * @param readTimeout The read timeout to use for this call.
 		 * @param params The parameters of the call or null.
 		 */
-		public Caller(XMLRPCCallback listener, long threadId, String methodName, Object[] params) {
+		public Caller(XMLRPCCallback listener, long threadId, String methodName,
+			int connectTimeout, int readTimeout, Object[] params) {
 			this.listener = listener;
 			this.threadId = threadId;
 			this.methodName = methodName;
 			this.params = params;
+			this.connectTimeout = connectTimeout;
+			this.readTimeout = readTimeout;
 		}
 
 		/**
@@ -589,7 +651,7 @@ public class XMLRPCClient {
 
 			try {
 				backgroundCalls.put(threadId, this);
-				Object o = this.call(methodName, params);
+				Object o = this.call(methodName, connectTimeout, readTimeout, params);
 				listener.onResponse(threadId, o);
 			} catch(CancelException ex) {
 				// Don't notify the listener, if the call has been canceled.
@@ -624,11 +686,12 @@ public class XMLRPCClient {
 		 *
 		 * @param methodName A method name to call.
 		 * @param params An array of parameters for the method.
-		 * @return The result of the server.
+		 * @param connectTimeout The connect timeout to use for this call.
+		 * @param readTimeout The read timeout to use for this call.
+		 * @return The result of the call.
 		 * @throws XMLRPCException Will be thrown if an error occurred during the call.
 		 */
-		public Object call(String methodName, Object[] params) throws XMLRPCException {
-
+		public Object call(String methodName, int connectTimeout, int readTimeout, Object[] params) throws XMLRPCException {
 			try {
 
 				Call c = createCall(methodName, params);
@@ -647,9 +710,11 @@ public class XMLRPCClient {
 				http.setDoInput(true);
 
 				// Set timeout
-				if(timeout > 0) {
-					http.setConnectTimeout(timeout * 1000);
-					http.setReadTimeout(timeout * 1000);
+				if(connectTimeout > 0) {
+					http.setConnectTimeout(connectTimeout * 1000);
+				}
+				if (readTimeout > 0) {
+					http.setReadTimeout(readTimeout * 1000);
 				}
 
 				// Set the request parameters
@@ -715,7 +780,7 @@ public class XMLRPCClient {
 						URL oldURL = url;
 						url = new URL(newLocation);
 						http.disconnect();
-						Object forwardedResult = call(methodName, params);
+						Object forwardedResult = call(methodName, connectTimeout, readTimeout, params);
 
 						// In case of temporary forward, restore original URL again for next call.
 						if(temporaryForward) {
@@ -747,7 +812,7 @@ public class XMLRPCClient {
 				return responseParser.parse(serializerHandler, istream, isFlagSet(FLAGS_DEBUG));
 
 			} catch(SocketTimeoutException ex) {
-				throw new XMLRPCTimeoutException("The XMLRPC call timed out.");
+				throw new XMLRPCTimeoutException("The XMLRPC call timed out.", ex);
 			} catch (IOException ex) {
 				// If the thread has been canceled this exception will be thrown.
 				// So only throw an exception if the thread hasnt been canceled


=====================================
src/main/java/de/timroes/axmlrpc/XMLRPCTimeoutException.java
=====================================
@@ -7,9 +7,11 @@ package de.timroes.axmlrpc;
  * @author Tim Roes
  */
 public class XMLRPCTimeoutException extends XMLRPCException {
-
 	XMLRPCTimeoutException(String ex) {
 		super(ex);
 	}
 
+	XMLRPCTimeoutException(String message, Exception cause) {
+		super(message, cause);
+	}
 }


=====================================
src/main/java/de/timroes/axmlrpc/XMLUtil.java
=====================================
@@ -76,7 +76,7 @@ public class XMLUtil {
 				continue;
 			}
 
-			if(n.getNodeType() != Node.TEXT_NODE) {
+			if(n.getNodeType() != Node.TEXT_NODE && n.getNodeType() != Node.CDATA_SECTION_NODE) {
 				throw new XMLRPCException("Element must contain only text elements.");
 			}
 


=====================================
src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java
=====================================
@@ -183,7 +183,7 @@ public class SerializerHandler {
 			byte[] old = (byte[])object;
 			Byte[] boxed = new Byte[old.length];
 			for(int i = 0; i < boxed.length; i++) {
-				boxed[i] = new Byte(old[i]);
+				boxed[i] = Byte.valueOf(old[i]);
 			}
 			object = boxed;
 			s = base64;


=====================================
src/test/java/de/timroes/axmlrpc/serializer/TestResponseParser.java
=====================================
@@ -13,7 +13,7 @@ import org.junit.Rule;
 
 import com.github.tomakehurst.wiremock.junit.WireMockRule;
 
-import de.timroes.axmlrpc.XMLRPCClient;
+import de.timroes.axmlrpc.*;
 
 public class TestResponseParser {
 	private final int port = 8080;
@@ -72,14 +72,52 @@ public class TestResponseParser {
 		assertTrue("Should have thrown because date was empty and we used the default behavior", didThrow);
 	}
 
+	@Test
+	public void robustToCWE611() throws Exception {
+		setMockWithRawContent("<?xml version=\"1.0\"?> <!DOCTYPE replace [<!ENTITY ent SYSTEM \"http://localhost/malware\"> ]><methodResponse><params><param><value><string>&ent;</string></value></param></params></methodResponse>");
+		boolean didThrowExpectedException = false;
+
+		try {
+		  makeDummyCall(XMLRPCClient.FLAGS_NONE);
+		} catch(XMLRPCException e) {
+			didThrowExpectedException = isCWE611ExceptedException(e);
+			if (!didThrowExpectedException) {
+				// if we don't get the exception we were expecting, rethrow so user has clues about what went wrong
+				// and can troubleshoot the test more easily
+				throw e;
+			}
+		}
+
+		assertTrue("Should have thrown because this payload is malicious", didThrowExpectedException);
+	}
+
+	@Test
+	public void canParseResponseWithCDATA() throws Exception {
+		setMockWithXmlRpcContent("<value><string><![CDATA[ab<&>cd]]></string></value>");
+
+		assertEquals("ab<&>cd", makeDummyCall());
+	}
+
 	private void setMockWithXmlRpcContent(String content){
+	  setMockWithRawContent("<methodResponse><params><param>" + content + "</param></params></methodResponse>");
+	}
+
+	private void setMockWithRawContent(String rawContent) {
 		stubFor(post(urlEqualTo(endPoint))
 				.willReturn(aResponse()
 						.withStatus(200)
-						.withBody("<methodResponse><params><param>" + content + "</param></params></methodResponse>")
+						.withBody(rawContent)
 						));
 	}
 
+	private boolean isCWE611ExceptedException(XMLRPCException e) {
+		Throwable cause = e.getCause();
+		if (cause == null) {
+      return false;
+		}
+		return cause.getMessage().contains("DOCTYPE is disallowed");
+	}
+
 	private Object makeDummyCall() throws Exception {
 		return makeDummyCall(XMLRPCClient.FLAGS_NONE);
 	}



View it on GitLab: https://salsa.debian.org/java-team/axmlrpc/-/compare/13ea0979f3cca92b14f06296a88954cf521aa102...bb3c539897d0b7b5748229c502a6b0affcba6090

-- 
View it on GitLab: https://salsa.debian.org/java-team/axmlrpc/-/compare/13ea0979f3cca92b14f06296a88954cf521aa102...bb3c539897d0b7b5748229c502a6b0affcba6090
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20260924/579bfdcf/attachment.htm>


More information about the pkg-java-commits mailing list