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

Emmanuel Bourg gitlab at salsa.debian.org
Mon Jan 18 16:09:36 GMT 2021



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


Commits:
53d76b4e by Emmanuel Bourg at 2021-01-18T16:11:55+01:00
New upstream version 1.10.0
- - - - -
89dc2b3e by Emmanuel Bourg at 2021-01-18T16:12:05+01:00
New upstream version 1.11.0
- - - - -
0ea780d1 by Emmanuel Bourg at 2021-01-18T16:12:09+01:00
New upstream version 1.12.0
- - - - -
d267598e by Emmanuel Bourg at 2021-01-18T16:12:14+01:00
New upstream version 1.12.1
- - - - -


24 changed files:

- + .github/workflows/codeql-analysis.yml
- .gitignore
- .travis.yml
- Changelog
- README.md
- pom.xml
- src/main/java/de/timroes/axmlrpc/Call.java
- src/main/java/de/timroes/axmlrpc/CookieManager.java
- src/main/java/de/timroes/axmlrpc/ResponseParser.java
- src/main/java/de/timroes/axmlrpc/XMLRPCClient.java
- src/main/java/de/timroes/axmlrpc/XMLRPCServerException.java
- src/main/java/de/timroes/axmlrpc/XMLRPCTimeoutException.java
- src/main/java/de/timroes/axmlrpc/XMLUtil.java
- src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java
- src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java
- src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java
- src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java
- src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java
- src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java
- src/main/java/de/timroes/base64/Base64.java
- src/test/java/de/timroes/axmlrpc/serializer/TestDateTimeSerializer.java
- src/test/java/de/timeroes/axmlrpc/TestResponseParser.java → src/test/java/de/timroes/axmlrpc/serializer/TestResponseParser.java
- src/test/java/de/timroes/axmlrpc/serializer/TestSerializers.java
- src/test/java/de/timeroes/base64/TestBase64.java → src/test/java/de/timroes/base64/TestBase64.java


Changes:

=====================================
.github/workflows/codeql-analysis.yml
=====================================
@@ -0,0 +1,71 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+name: "CodeQL"
+
+on:
+  push:
+    branches: [master]
+  pull_request:
+    # The branches below must be a subset of the branches above
+    branches: [master]
+  schedule:
+    - cron: '0 16 * * 3'
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+
+    strategy:
+      fail-fast: false
+      matrix:
+        # Override automatic language detection by changing the below list
+        # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
+        language: ['java']
+        # Learn more...
+        # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout at v2
+      with:
+        # We must fetch at least the immediate parents so that if this is
+        # a pull request then we can checkout the head.
+        fetch-depth: 2
+
+    # If this run was triggered by a pull request event, then checkout
+    # the head of the pull request instead of the merge commit.
+    - run: git checkout HEAD^2
+      if: ${{ github.event_name == 'pull_request' }}
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init at v1
+      with:
+        languages: ${{ matrix.language }}
+        # If you wish to specify custom queries, you can do so here or in a config file.
+        # By default, queries listed here will override any specified in a config file. 
+        # Prefix the list here with "+" to use these queries and those in the config file.
+        # queries: ./path/to/local/query, your-org/your-repo/queries at main
+
+    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+    # If this step fails, then you should remove it and run the build manually (see below)
+    - name: Autobuild
+      uses: github/codeql-action/autobuild at v1
+
+    # ℹī¸ Command-line programs to run using the OS shell..
+    # 📚 https://git.io/JvXDl
+
+    # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines
+    #    and modify them (or add more) to build your code if your project
+    #    uses a compiled language
+
+    #- run: |
+    #   make bootstrap
+    #   make release
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze at v1


=====================================
.gitignore
=====================================
@@ -1,8 +1,18 @@
 nbproject/
-build/
 dist/
-.gradle/
 /.nb-gradle/private/
 target
 .classpath
 .project
+
+# Gradle
+.gradle
+local.properties
+build
+
+# IntelliJ IDEA
+.idea
+*.iml
+
+# OSX
+.DS_Store


=====================================
.travis.yml
=====================================
@@ -1 +1,8 @@
 language: java
+arch:
+   - ppc64le
+   - amd64
+before_install:
+  - if [ $TRAVIS_CPU_ARCH = ppc64le ]; then
+          sudo apt-get install maven ;
+    fi


=====================================
Changelog
=====================================
@@ -1,3 +1,16 @@
+Fix security issue CWE-611
+
+1.12.0
+Add flag ACCEPT_NULL_DATES
+
+1.11.0
+Tweaks to make it possible to use an arbitrary transport
+Fix potential race condition
+
+1.10.0
+Fix serialization of the sequence ']]>'
+
+1.9.0
 Add FLAGS_DEBUG to display the xml returned by the server
 
 1.8.3


=====================================
README.md
=====================================
@@ -235,7 +235,7 @@ proxy to connect to the XML-RPC server.
 By default outgoing string values will be encoded according to specification.
 Meaning the & sign will be encoded to `&` and the "less then" sign to `<`.
 If you set this flag, the encoding won't be done for outgoing string values.
-See `FLAGS_NO_STRING_ENCODE` for the counterpart.
+See `FLAGS_NO_STRING_DECODE` for the counterpart.
 
 
 #### FLAGS_NO_STRING_DECODE
@@ -247,6 +247,11 @@ won't be decoded to the & sign and the "less then" sign. See
 Will display additional information on the console.
 Do not use it in production.
 
+#### FLAGS_ACCEPT_NULL_DATE
+By default a response with an empty date (eg: `<value><dateTime.iso8601/></value>`)
+is invalid and hence throws an exception.
+With this flag, this input is accepted, and returns a null date
+
 Meta Flags
 ----------
 
@@ -270,6 +275,20 @@ of the server will be ignored.
 This will enable the following flags: FLAGS_IGNORE_NAMESPACES, FLAGS_NIL,
 FLAGS_DEFAULT_TYPE_STRING
 
+Using an arbitrary transport
+============================
+aXMLRPC uses http with the java.net API. If you want to use another protocol or API, you can do:
+
+```java
+    boolean debug = false;
+    SerializerHandler serializerHandler = new SerializerHandler(); // or you may build it with flags
+    String payload = new Call(serializerHandler, "add", 5, 10).getXML(debug);
+
+    InputStream istream = sendPayloadWithMyTransport(payload); // use your implementation here
+
+    Integer i = (Integer) new ResponseParser.parse(serializerHandler, istream, debug);
+```
+
 
 License
 =======


=====================================
pom.xml
=====================================
@@ -3,7 +3,7 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>fr.turri</groupId>
 	<artifactId>aXMLRPC</artifactId>
-	<version>1.9.0</version>
+	<version>1.12.1</version>
 	<packaging>jar</packaging>
 	<name>aXMLRPC</name>
 	<description>Lightweight Java XML-RPC working also on Android.</description>
@@ -34,7 +34,7 @@
 		<dependency>
 			<groupId>junit</groupId>
 			<artifactId>junit</artifactId>
-			<version>4.12</version>
+			<version>4.13.1</version>
 			<scope>test</scope>
 		</dependency>
 		<dependency>
@@ -44,59 +44,16 @@
 		</dependency>
         <dependency>
           <groupId>com.github.tomakehurst</groupId>
-          <artifactId>wiremock</artifactId>
-          <version>1.58</version>
+          <artifactId>wiremock-jre8</artifactId>
+          <version>2.27.2</version>
           <scope>test</scope>
-          <classifier>standalone</classifier>
-          <exclusions>
-            <exclusion>
-              <groupId>org.mortbay.jetty</groupId>
-              <artifactId>jetty</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.google.guava</groupId>
-              <artifactId>guava</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-core</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-annotations</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.fasterxml.jackson.core</groupId>
-              <artifactId>jackson-databind</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.apache.httpcomponents</groupId>
-              <artifactId>httpclient</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>org.skyscreamer</groupId>
-              <artifactId>jsonassert</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>xmlunit</groupId>
-              <artifactId>xmlunit</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>com.jayway.jsonpath</groupId>
-              <artifactId>json-path</artifactId>
-            </exclusion>
-            <exclusion>
-              <groupId>net.sf.jopt-simple</groupId>
-              <artifactId>jopt-simple</artifactId>
-            </exclusion>
-          </exclusions>
         </dependency>
 	</dependencies>
 	<scm>
         <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.9.0</tag>
+        <tag>aXMLRPC-1.12.1</tag>
 	</scm>
     <build>
       <pluginManagement>
@@ -114,10 +71,15 @@
         </plugins>
       </pluginManagement>
       <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-site-plugin</artifactId>
+          <version>3.9.1</version>
+        </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-jar-plugin</artifactId>
-          <version>2.6</version>
+          <version>3.2.0</version>
           <configuration>
             <archive>
               <manifest>
@@ -129,7 +91,7 @@
         <plugin>
           <groupId>org.sonatype.plugins</groupId>
           <artifactId>nexus-staging-maven-plugin</artifactId>
-          <version>1.6.7</version>
+          <version>1.6.8</version>
           <extensions>true</extensions>
           <configuration>
             <serverId>ossrh</serverId>
@@ -140,7 +102,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-javadoc-plugin</artifactId>
-          <version>2.10.3</version>
+          <version>3.2.0</version>
           <executions>
             <execution>
               <id>attach-javadocs</id>
@@ -154,10 +116,15 @@
     </build>
     <reporting>
       <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-project-info-reports-plugin</artifactId>
+          <version>3.1.1</version>
+        </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-report-plugin</artifactId>
-          <version>2.19.1</version>
+          <version>2.22.2</version>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
@@ -167,7 +134,7 @@
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-javadoc-plugin</artifactId>
-          <version>2.10.3</version>
+          <version>3.2.0</version>
           <reportSets>
             <reportSet>
               <reports>
@@ -182,7 +149,7 @@
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
           <artifactId>findbugs-maven-plugin</artifactId>
-          <version>3.0.3</version>
+          <version>3.0.5</version>
         </plugin>
       </plugins>
     </reporting>
@@ -194,7 +161,7 @@
             <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-source-plugin</artifactId>
-              <version>3.0.0</version>
+              <version>3.2.1</version>
               <executions>
                 <execution>
                   <id>attach-sources</id>
@@ -207,7 +174,7 @@
             <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-javadoc-plugin</artifactId>
-              <version>2.10.3</version>
+              <version>3.2.0</version>
               <executions>
                 <execution>
                   <id>attach-javadocs</id>


=====================================
src/main/java/de/timroes/axmlrpc/Call.java
=====================================
@@ -1,5 +1,6 @@
 package de.timroes.axmlrpc;
 
+import de.timroes.axmlrpc.serializer.Serializer;
 import de.timroes.axmlrpc.serializer.SerializerHandler;
 import de.timroes.axmlrpc.xmlcreator.SimpleXMLCreator;
 import de.timroes.axmlrpc.xmlcreator.XmlElement;
@@ -16,23 +17,29 @@ public class Call {
 
 	private String method;
 	private Object[] params;
+	private final SerializerHandler serializerHandler;
 
 	/**
 	 * Create a new method call with the given name and no parameters.
+	 * @param serializerHandler You can inject an arbitrary one if you want to use your own transport protocol.
+	 *     See the README (section "Using an arbitrary transport") for more info on this feature.
 	 * @param method The method to be called.
 	 */
-	public Call(String method) {
-		this(method, null);
+	public Call(SerializerHandler serializerHandler, String method) {
+		this(serializerHandler, method, null);
 	}
 
 	/**
 	 * Create a new method call with the given name and parameters.
+	 * @param serializerHandler You can inject an arbitrary one if you want to use your own transport protocol.
+	 *     See the README (section "Using an arbitrary transport") for more info on this feature.
 	 * @param method The method to be called.
 	 * @param params An array of parameters for the method.
 	 */
-	public Call(String method, Object[] params) {
+	public Call(SerializerHandler serializerHandler, String method, Object[] params) {
 		this.method = method;
 		this.params = params;
+		this.serializerHandler = serializerHandler;
 	}
 
 	/**
@@ -40,6 +47,8 @@ public class Call {
 	 * http://www.xmlrpc.com/spec. If flags have been set in the XMLRPCClient
 	 * the returning xml does not comply strict to the standard.
 	 *
+	 * @param debugMode This prints data on System.out to make it easy to debug
+	 *
 	 * @return The string of the xml representing this call.
 	 * @throws XMLRPCException Will be thrown whenever the xml representation cannot
 	 * 		be build without errors.
@@ -57,11 +66,11 @@ public class Call {
 		methodCall.addChildren(methodName);
 
 		if(params != null && params.length > 0) {
-			XmlElement params = new XmlElement(XMLRPCClient.PARAMS);
-			methodCall.addChildren(params);
+			XmlElement callParams = new XmlElement(XMLRPCClient.PARAMS);
+			methodCall.addChildren(callParams);
 
 			for(Object o : this.params) {
-				params.addChildren(getXMLParam(o));
+				callParams.addChildren(getXMLParam(o));
 			}
 		}
 
@@ -85,7 +94,7 @@ public class Call {
 		XmlElement param = new XmlElement(XMLRPCClient.PARAM);
 		XmlElement value = new XmlElement(XMLRPCClient.VALUE);
 		param.addChildren(value);
-		value.addChildren(SerializerHandler.getDefault().serialize(o));
+		value.addChildren(serializerHandler.serialize(o));
 		return param;
 	}
 


=====================================
src/main/java/de/timroes/axmlrpc/CookieManager.java
=====================================
@@ -62,7 +62,7 @@ class CookieManager {
 		// Extract every Set-Cookie field and put the cookie to the cookies map.
 		for(int i = 0; i < http.getHeaderFields().size(); i++) {
 			key = http.getHeaderFieldKey(i);
-			if(key != null && SET_COOKIE.toLowerCase().equals(key.toLowerCase())) {
+			if(key != null && SET_COOKIE.equalsIgnoreCase(key.toLowerCase())) {
 				cookie = http.getHeaderField(i).split(";")[0];
 				split = cookie.split("=");
 				if(split.length >= 2)


=====================================
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;
@@ -25,7 +26,7 @@ import org.w3c.dom.Element;
  *
  * @author Tim Roes
  */
-class ResponseParser {
+public class ResponseParser {
 
 	private static final String FAULT_CODE = "faultCode";
 	private static final String FAULT_STRING = "faultString";
@@ -34,17 +35,28 @@ class ResponseParser {
 	 * The given InputStream must contain the xml response from an xmlrpc server.
 	 * This method extract the content of it as an object.
 	 *
+	 * @param serializerHandler You can inject an arbitrary one if you want to use your own transport protocol.
+	 *     See the README (section "Using an arbitrary transport") for more info on this feature.
 	 * @param response The InputStream of the server response.
+	 * @param debugMode This prints data on System.out to make it easy to debug
 	 * @return The returned object.
 	 * @throws XMLRPCException Will be thrown whenever something fails.
 	 * @throws XMLRPCServerException Will be thrown, if the server returns an error.
 	 */
-	public Object parse(InputStream response, boolean debugMode) throws XMLRPCException {
+	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 ){
@@ -68,12 +80,12 @@ class ResponseParser {
 					throw new XMLRPCException("The params tag must contain a param tag.");
 				}
 
-				return getReturnValueFromElement(e);
+				return getReturnValueFromElement(serializerHandler, e);
 
 			} else if(e.getNodeName().equals(XMLRPCClient.FAULT)) {
 
 				@SuppressWarnings("unchecked")
-				Map<String,Object> o = (Map<String,Object>)getReturnValueFromElement(e);
+				Map<String,Object> o = (Map<String,Object>)getReturnValueFromElement(serializerHandler, e);
 
 				throw new XMLRPCServerException((String)o.get(FAULT_STRING), (Integer)o.get(FAULT_CODE));
 
@@ -81,13 +93,10 @@ class ResponseParser {
 
 			throw new XMLRPCException("The methodResponse tag must contain a fault or params tag.");
 
+		} catch(XMLRPCServerException e) {
+			throw e;
 		} catch (Exception ex) {
-
-			if(ex instanceof XMLRPCServerException)
-				throw (XMLRPCServerException)ex;
-			else
-				throw new XMLRPCException("Error getting result from server.", ex);
-
+			throw new XMLRPCException("Error getting result from server.", ex);
 		}
 
 	}
@@ -114,12 +123,11 @@ class ResponseParser {
 	 * @throws XMLRPCException Will be thrown when the structure of the document
 	 *		doesn't match the XML-RPC specification.
 	 */
-	private Object getReturnValueFromElement(Element element) throws XMLRPCException {
-
-		element = XMLUtil.getOnlyChildElement(element.getChildNodes());
+	private Object getReturnValueFromElement(SerializerHandler serializerHandler, Element element) throws XMLRPCException {
 
-		return SerializerHandler.getDefault().deserialize(element);
+		Element childElement = XMLUtil.getOnlyChildElement(element.getChildNodes());
 
+		return serializerHandler.deserialize(childElement);
 	}
 
-}
\ No newline at end of file
+}


=====================================
src/main/java/de/timroes/axmlrpc/XMLRPCClient.java
=====================================
@@ -81,7 +81,7 @@ public class XMLRPCClient {
 
 	/**
 	 * The client will be able to send null values. A null value will be send
-	 * as <nil/>. This extension is described under: http://ontosys.com/xml-rpc/extensions.php
+	 * as <nil/>. This extension is described under: http://ontosys.com/xml-rpc/extensions.php
 	 */
 	public static final int FLAGS_NIL = 0x08;
 
@@ -138,14 +138,14 @@ public class XMLRPCClient {
 
 	/**
 	 * This prevents the decoding of incoming strings, meaning & and <
-	 * won't be decoded to the & sign and the "less then" sign. See
+	 * won't be decoded to the & sign and the "less then" sign. See
 	 * {@link #FLAGS_NO_STRING_ENCODE} for the counterpart.
 	 */
 	public static final int FLAGS_NO_STRING_DECODE = 0x800;
 
 	/**
 	 * By default outgoing string values will be encoded according to specification.
-	 * Meaning the & sign will be encoded to & and the "less then" sign to <.
+	 * Meaning the & sign will be encoded to &amp; and the "less then" sign to &lt;.
 	 * If you set this flag, the encoding won't be done for outgoing string values.
 	 * See {@link #FLAGS_NO_STRING_ENCODE} for the counterpart.
 	 */
@@ -157,6 +157,11 @@ public class XMLRPCClient {
 	 */
 	public static final int FLAGS_DEBUG = 0x2000;
 
+	/**
+	 * Accepts response containing eg: <dateTime.iso8601/>
+	 */
+	public static final int FLAGS_ACCEPT_NULL_DATES = 0x4000;
+
 	/**
 	 * This flag disables all SSL warnings. It is an alternative to use
 	 * FLAGS_SSL_IGNORE_INVALID_CERT | FLAGS_SSL_IGNORE_INVALID_HOST. There
@@ -192,6 +197,7 @@ public class XMLRPCClient {
 	private Proxy proxy;
 
 	private int timeout;
+	private final SerializerHandler serializerHandler;
 
 	/**
 	 * Create a new XMLRPC client for the given URL.
@@ -202,7 +208,7 @@ public class XMLRPCClient {
 	 */
 	public XMLRPCClient(URL url, String userAgent, int flags) {
 
-		SerializerHandler.initialize(flags);
+		this.serializerHandler = new SerializerHandler(flags);
 
 		this.url = url;
 
@@ -520,8 +526,7 @@ public class XMLRPCClient {
 			throw new XMLRPCRuntimeException("Method name must only contain A-Z a-z . : _ / ");
 		}
 
-		return new Call(method, params);
-
+		return new Call(serializerHandler, method, params);
 	}
 
 	/**
@@ -617,7 +622,7 @@ public class XMLRPCClient {
 		 * Read the README file delivered with the source code of this library for more
 		 * information.
 		 *
-		 * @param method A method name to call.
+		 * @param methodName A method name to call.
 		 * @param params An array of parameters for the method.
 		 * @return The result of the server.
 		 * @throws XMLRPCException Will be thrown if an error occurred during the call.
@@ -668,7 +673,7 @@ public class XMLRPCClient {
 					// Due to a bug on android, the getResponseCode()-method will
 					// fail the first time, with a IOException, when 401 or 403 has been returned.
 					// The second time it should success. If it fail the second time again
-					// the normal exceptipon handling can take care of this, since
+					// the normal exception handling can take care of this, since
 					// it is a real error.
 					statusCode = http.getResponseCode();
 				}
@@ -698,7 +703,7 @@ public class XMLRPCClient {
 						|| statusCode == HttpURLConnection.HTTP_MOVED_TEMP) {
 					// ... do either a foward
 					if(isFlagSet(FLAGS_FORWARD)) {
-						boolean temporaryForward = (statusCode == HttpURLConnection.HTTP_MOVED_TEMP);
+						boolean temporaryForward = statusCode == HttpURLConnection.HTTP_MOVED_TEMP;
 
 						// Get new location from header field.
 						String newLocation = http.getHeaderField("Location");
@@ -733,15 +738,13 @@ public class XMLRPCClient {
 				}
 
 				// Check for strict parameters
-				if(isFlagSet(FLAGS_STRICT)) {
-					if(!http.getContentType().startsWith(TYPE_XML)) {
-						throw new XMLRPCException("The Content-Type of the response must be text/xml.");
-					}
+				if(isFlagSet(FLAGS_STRICT) && !http.getContentType().startsWith(TYPE_XML)) {
+					throw new XMLRPCException("The Content-Type of the response must be text/xml.");
 				}
 
 				cookieManager.readCookies(http);
 
-				return responseParser.parse(istream, isFlagSet(FLAGS_DEBUG));
+				return responseParser.parse(serializerHandler, istream, isFlagSet(FLAGS_DEBUG));
 
 			} catch(SocketTimeoutException ex) {
 				throw new XMLRPCTimeoutException("The XMLRPC call timed out.");


=====================================
src/main/java/de/timroes/axmlrpc/XMLRPCServerException.java
=====================================
@@ -8,7 +8,7 @@ package de.timroes.axmlrpc;
  */
 public class XMLRPCServerException extends XMLRPCException {
 
-	private int errornr;
+	private final int errornr;
 
 	public XMLRPCServerException(String ex, int errnr) {
 		super(ex);


=====================================
src/main/java/de/timroes/axmlrpc/XMLRPCTimeoutException.java
=====================================
@@ -4,7 +4,7 @@ package de.timroes.axmlrpc;
  * Will be thrown when a call to the server times out. The timeout can be 
  * set via {@link XMLRPCClient#setTimeout(int)}.
  * 
- * @author Tim Roes <mail at timroes.de>
+ * @author Tim Roes
  */
 public class XMLRPCTimeoutException extends XMLRPCException {
 
@@ -12,4 +12,4 @@ public class XMLRPCTimeoutException extends XMLRPCException {
 		super(ex);
 	}
 
-}
\ No newline at end of file
+}


=====================================
src/main/java/de/timroes/axmlrpc/XMLUtil.java
=====================================
@@ -12,6 +12,8 @@ import org.w3c.dom.NodeList;
  */
 public class XMLUtil {
 
+	private XMLUtil() {}
+
 	/**
 	 * Returns the only child element in a given NodeList.
 	 * Will throw an error if there is more then one child element or any other
@@ -111,7 +113,7 @@ public class XMLUtil {
 	/**
 	 * Creates an xml tag with a given type and content.
 	 *
-	 * @param type The type of the xml tag. What will be filled in the <..>..
+	 * @param type The type of the xml tag. What will be filled in the <..>.
 	 * @param content The content of the tag.
 	 * @return The xml tag with its content as a string.
 	 */
@@ -121,4 +123,4 @@ public class XMLUtil {
 		return xml;
 	}
 
-}
\ No newline at end of file
+}


=====================================
src/main/java/de/timroes/axmlrpc/serializer/ArraySerializer.java
=====================================
@@ -18,6 +18,11 @@ public class ArraySerializer implements Serializer {
 
 	private static final String ARRAY_DATA = "data";
 	private static final String ARRAY_VALUE = "value";
+	private final SerializerHandler serializerHandler;
+
+	public ArraySerializer(SerializerHandler serializerHandler){
+		this.serializerHandler = serializerHandler;
+	}
 
 	public Object deserialize(Element content) throws XMLRPCException {
 
@@ -45,7 +50,7 @@ public class ArraySerializer implements Serializer {
 				throw new XMLRPCException("Wrong element inside of array.");
 			}
 
-			list.add(SerializerHandler.getDefault().deserialize((Element)value));
+			list.add(serializerHandler.deserialize((Element)value));
 
 		}
 
@@ -69,7 +74,7 @@ public class ArraySerializer implements Serializer {
 			XmlElement e;
 			for(Object obj : iter) {
 				e = new XmlElement(ARRAY_VALUE);
-				e.addChildren(SerializerHandler.getDefault().serialize(obj));
+				e.addChildren(serializerHandler.serialize(obj));
 				data.addChildren(e);
 			}
 


=====================================
src/main/java/de/timroes/axmlrpc/serializer/BooleanSerializer.java
=====================================
@@ -12,13 +12,13 @@ import org.w3c.dom.Element;
 public class BooleanSerializer implements Serializer {
 
 	public Object deserialize(Element content) throws XMLRPCException {
-		return (XMLUtil.getOnlyTextContent(content.getChildNodes()).equals("1"))
+		return XMLUtil.getOnlyTextContent(content.getChildNodes()).equals("1")
 				? Boolean.TRUE : Boolean.FALSE;
 	}
 
 	public XmlElement serialize(Object object) {
 		return XMLUtil.makeXmlTag(SerializerHandler.TYPE_BOOLEAN,
-				((Boolean)object == true) ? "1" : "0");
+				(Boolean)object ? "1" : "0");
 	}
 
 }
\ No newline at end of file


=====================================
src/main/java/de/timroes/axmlrpc/serializer/DateTimeSerializer.java
=====================================
@@ -16,7 +16,14 @@ import fr.turri.jiso8601.Iso8601Deserializer;
 public class DateTimeSerializer implements Serializer {
 
 	private static final String DATETIME_FORMAT = "yyyyMMdd'T'HHmmss";
-	private static final SimpleDateFormat DATE_FORMATER = new SimpleDateFormat(DATETIME_FORMAT);
+	private final SimpleDateFormat DATE_FORMATER = new SimpleDateFormat(DATETIME_FORMAT);
+
+	private final boolean accepts_null_input;
+
+	public DateTimeSerializer(boolean accepts_null_input) {
+		this.accepts_null_input = accepts_null_input;
+	}
+
 
 	@Override
 	public Object deserialize(Element content) throws XMLRPCException {
@@ -24,6 +31,10 @@ public class DateTimeSerializer implements Serializer {
 	}
 
 	public Object deserialize(String dateStr) throws XMLRPCException {
+		if (accepts_null_input && (dateStr==null || dateStr.trim().length()==0)) {
+			return null;
+		}
+
 		try {
 			return Iso8601Deserializer.toDate(dateStr);
 		} catch (Exception ex) {


=====================================
src/main/java/de/timroes/axmlrpc/serializer/SerializerHandler.java
=====================================
@@ -2,7 +2,6 @@ package de.timroes.axmlrpc.serializer;
 
 import de.timroes.axmlrpc.XMLRPCClient;
 import de.timroes.axmlrpc.XMLRPCException;
-import de.timroes.axmlrpc.XMLRPCRuntimeException;
 import de.timroes.axmlrpc.XMLUtil;
 import de.timroes.axmlrpc.xmlcreator.XmlElement;
 import java.math.BigDecimal;
@@ -12,11 +11,9 @@ import java.util.Map;
 import org.w3c.dom.Element;
 
 /**
- * The serializer handler serializes and deserialized objects.
+ * The serializer handler serializes and deserializes objects.
  * It takes an object, determine its type and let the responsible handler serialize it.
  * For deserialization it looks at the xml tag around the element.
- * The class is designed as a kind of singleton, so it can be accessed from anywhere in
- * the library.
  *
  * @author Tim Roes
  */
@@ -34,57 +31,32 @@ public class SerializerHandler {
 	public static final String TYPE_BASE64 = "base64";
 	public static final String TYPE_NULL = "nil";
 
-	private static SerializerHandler instance;
-
-	/**
-	 * Initialize the serialization handler. This method must be called before
-	 * the get method returns any object.
-	 *
-	 * @param flags The flags that has been set in the XMLRPCClient.
-	 * @see XMLRPCClient
-	 */
-	public static void initialize(int flags) {
-		instance = new SerializerHandler(flags);
-	}
-
-	/**
-	 * Return the instance of the SerializerHandler.
-	 * It must have been initialized with initialize() before.
-	 *
-	 * @return The instance of the SerializerHandler.
-	 */
-	public static SerializerHandler getDefault() {
-		if(instance == null) {
-			throw new XMLRPCRuntimeException("The SerializerHandler has not been initialized.");
-		}
-		return instance;
-	}
-
 	private StringSerializer string;
 	private BooleanSerializer bool = new BooleanSerializer();
 	private IntSerializer integer = new IntSerializer();
 	private LongSerializer long8 = new LongSerializer();
-	private StructSerializer struct = new StructSerializer();
+	private StructSerializer struct;
 	private DoubleSerializer floating = new DoubleSerializer();
-	private DateTimeSerializer datetime = new DateTimeSerializer();
-	private ArraySerializer array = new ArraySerializer();
+	private DateTimeSerializer datetime;
+	private ArraySerializer array;
 	private Base64Serializer base64 = new Base64Serializer();
 	private NullSerializer nil = new NullSerializer();
-	
+
 	private int flags;
 
-	/**
-	 * Generates the SerializerHandler.
-	 * This method can only called from within the class (the initialize method).
-	 *
-	 * @param flags The flags to use.
-	 */
-	private SerializerHandler(int flags) {
+	public SerializerHandler(){
+		this(XMLRPCClient.FLAGS_DEBUG);
+	}
+
+	public SerializerHandler(int flags) {
 		this.flags = flags;
 		string = new StringSerializer(
 			(flags & XMLRPCClient.FLAGS_NO_STRING_ENCODE) == 0,
 			(flags & XMLRPCClient.FLAGS_NO_STRING_DECODE) == 0
 		);
+		struct = new StructSerializer(this);
+		array = new ArraySerializer(this);
+		datetime = new DateTimeSerializer((flags & XMLRPCClient.FLAGS_ACCEPT_NULL_DATES) != 0);
 	}
 
 	/**
@@ -112,17 +84,17 @@ public class SerializerHandler {
 		}
 			
 		// Grep type element from inside value element
-		element = XMLUtil.getOnlyChildElement(element.getChildNodes());
+		Element childElement = XMLUtil.getOnlyChildElement(element.getChildNodes());
 
-		Serializer s = null;
+		Serializer s;
 
 		String type;
 
 		// If FLAGS_IGNORE_NAMESPACE has been set, only use local name.
 		if((flags & XMLRPCClient.FLAGS_IGNORE_NAMESPACES) != 0) {
-			type = element.getLocalName() == null ? element.getNodeName() : element.getLocalName();
+			type = childElement.getLocalName() == null ? childElement.getNodeName() : childElement.getLocalName();
 		} else {
-			type = element.getNodeName();
+			type = childElement.getNodeName();
 		}
 
 		if((flags & XMLRPCClient.FLAGS_NIL) != 0 && TYPE_NULL.equals(type)) {
@@ -154,7 +126,7 @@ public class SerializerHandler {
 			throw new XMLRPCException("No deserializer found for type '" + type + "'.");
 		}
 
-		return s.deserialize(element);
+		return s.deserialize(childElement);
 
 	}
 
@@ -169,7 +141,7 @@ public class SerializerHandler {
 	 */
 	public XmlElement serialize(Object object) throws XMLRPCException {
 
-		Serializer s = null;
+		Serializer s;
 
 		if((flags & XMLRPCClient.FLAGS_NIL) != 0 && object == null) {
 			s = nil;


=====================================
src/main/java/de/timroes/axmlrpc/serializer/StringSerializer.java
=====================================
@@ -30,7 +30,10 @@ public class StringSerializer implements Serializer {
 	public XmlElement serialize(Object object) {
 		String content = object.toString();
 		if(encodeStrings) {
-			content = content.replaceAll("&", "&").replaceAll("<", "<");
+			content = content
+					.replaceAll("&", "&")
+					.replaceAll("<", "<")
+					.replaceAll("]]>", "]]>");
 		}
 		return XMLUtil.makeXmlTag(SerializerHandler.TYPE_STRING, content);
 	}


=====================================
src/main/java/de/timroes/axmlrpc/serializer/StructSerializer.java
=====================================
@@ -19,6 +19,12 @@ public class StructSerializer implements Serializer {
 	private static final String STRUCT_NAME = "name";
 	private static final String STRUCT_VALUE = "value";
 
+	private final SerializerHandler serializerHandler;
+
+	public StructSerializer(SerializerHandler serializerHandler) {
+		this.serializerHandler = serializerHandler;
+	}
+
 	public Object deserialize(Element content) throws XMLRPCException {
 
 		Map<String, Object> map = new HashMap<String, Object>();
@@ -62,7 +68,7 @@ public class StructSerializer implements Serializer {
 					if(o != null) {
 						throw new XMLRPCException("Value of a struct member cannot be set twice.");
 					} else {
-						o = SerializerHandler.getDefault().deserialize((Element)m);
+						o = serializerHandler.deserialize((Element)m);
 					}
 				} else {
 					throw new XMLRPCException("A struct member must only contain one name and one value.");
@@ -96,7 +102,7 @@ public class StructSerializer implements Serializer {
 				name = new XmlElement(STRUCT_NAME);
 				value = new XmlElement(STRUCT_VALUE);
 				name.setContent(member.getKey());
-				value.addChildren(SerializerHandler.getDefault().serialize(member.getValue()));
+				value.addChildren(serializerHandler.serialize(member.getValue()));
 				entry.addChildren(name);
 				entry.addChildren(value);
 				struct.addChildren(entry);


=====================================
src/main/java/de/timroes/base64/Base64.java
=====================================
@@ -14,6 +14,8 @@ public class Base64 {
 
 	private static final HashMap<Character,Byte> map = new HashMap<Character, Byte>();
 
+	private Base64() {}
+
 	static {
 		for(int i = 0; i < code.length; i++) {
 			map.put(code[i], (byte)i);
@@ -44,10 +46,10 @@ public class Base64 {
 		int outi = 0;
 		int b1, b2, b3, b4;
 		for(int i = 0; i < input.length; i+=4) {
-			b1 = (map.get(input[i]) - 1);
-			b2 = (map.get(input[i+1]) - 1);
-			b3 = (map.get(input[i+2]) - 1);
-			b4 = (map.get(input[i+3]) - 1);
+			b1 = map.get(input[i]) - 1;
+			b2 = map.get(input[i+1]) - 1;
+			b3 = map.get(input[i+2]) - 1;
+			b4 = map.get(input[i+3]) - 1;
 			out[outi++] = (byte)(b1 << 2 | b2 >>> 4);
 			out[outi++] = (byte)((b2 & 0x0F) << 4 | b3 >>> 2);
 			out[outi++] = (byte)((b3 & 0x03) << 6 | (b4 & 0x3F));


=====================================
src/test/java/de/timroes/axmlrpc/serializer/TestDateTimeSerializer.java
=====================================
@@ -74,7 +74,7 @@ public class TestDateTimeSerializer {
 
 	@Test
 	public void canParseMilliseconds() throws Exception {
-		Date ms500 = (Date) new DateTimeSerializer().deserialize("1985-03-04T12:21:36.5");
+		Date ms500 = (Date) new DateTimeSerializer(false).deserialize("1985-03-04T12:21:36.5");
 		assertEquals(500, ms500.getTime() - new Date(85, 2, 4, 12, 21, 36).getTime());
 	}
 
@@ -121,8 +121,7 @@ public class TestDateTimeSerializer {
 	}
 
 	private void assertDeserializeEquals(Date expected, String toDeserialize) throws Exception {
-		Date date = (Date) new DateTimeSerializer().deserialize(toDeserialize);
-		long diffMs = date.getTime() - expected.getTime();
+		Date date = (Date) new DateTimeSerializer(false).deserialize(toDeserialize);
 		assertEquals(expected, date);
 	}
 }


=====================================
src/test/java/de/timeroes/axmlrpc/TestResponseParser.java → src/test/java/de/timroes/axmlrpc/serializer/TestResponseParser.java
=====================================
@@ -1,6 +1,8 @@
-package de.timeroes.axmlrpc;
+package de.timroes.axmlrpc.serializer;
 
 import java.net.URL;
+import java.util.Date;
+import java.util.TimeZone;
 
 import org.junit.Test;
 
@@ -50,6 +52,26 @@ public class TestResponseParser {
 		assertEquals(false, makeDummyCall());
 	}
 
+	@Test
+	public void canParseDateTime() throws Exception {
+		java.util.TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+
+		setMockWithXmlRpcContent("<value><dateTime.iso8601>2018-03-06T06:21:20Z</dateTime.iso8601></value>");
+		assertEquals("Can parse normal datetime", new Date(118, 2, 6, 6,21,20), makeDummyCall());
+
+		setMockWithXmlRpcContent("<value><dateTime.iso8601/></value>");
+		assertNull("Should get null date because we use the flag to enable this behavior", makeDummyCall(XMLRPCClient.FLAGS_ACCEPT_NULL_DATES));
+
+		boolean didThrow = false;
+		setMockWithXmlRpcContent("<value><dateTime.iso8601/></value>");
+		try {
+			makeDummyCall(XMLRPCClient.FLAGS_NONE);
+		} catch(Exception e){
+			didThrow = true;
+		}
+		assertTrue("Should have thrown because date was empty and we used the default behavior", didThrow);
+	}
+
 	private void setMockWithXmlRpcContent(String content){
 		stubFor(post(urlEqualTo(endPoint))
 				.willReturn(aResponse()


=====================================
src/test/java/de/timroes/axmlrpc/serializer/TestSerializers.java
=====================================
@@ -3,12 +3,28 @@ package de.timroes.axmlrpc.serializer;
 import static org.junit.Assert.*;
 
 import java.util.Date;
+import java.util.TimeZone;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 
 import de.timroes.axmlrpc.xmlcreator.XmlElement;
 
 public class TestSerializers {
+	private TimeZone _previousTZ;
+
+	@Before
+	public void setUp(){
+		_previousTZ = TimeZone.getDefault();
+		TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+	}
+
+	@After
+	public void tearDown(){
+		TimeZone.setDefault(_previousTZ);
+	}
+
 
 	@Test
 	public void canSerializeBase64(){
@@ -29,7 +45,7 @@ public class TestSerializers {
 	@Test
 	public void canSerializeDate(){
 		assertExpectedSerialized("<dateTime.iso8601>19850503T122334</dateTime.iso8601>",
-				new DateTimeSerializer().serialize(new Date(85, 4, 3, 12, 23, 34)));
+				new DateTimeSerializer(false).serialize(new Date(85, 4, 3, 12, 23, 34)));
 	}
 
 	@Test
@@ -56,6 +72,13 @@ public class TestSerializers {
 		assertExpectedSerialized("<string>te<&>st</string>", new StringSerializer(encodeString, true).serialize("te<&>st"));
 	}
 
+	@Test
+	public void canSerializeStringWithCdataClosing(){
+		boolean encodeString = true;
+		XmlElement serialized = new StringSerializer(encodeString, true).serialize("[ ]]>");
+		assertFalse("encoded string shouldn't contain ]]> since it's reserved for CData", serialized.toString().contains("]]>"));
+	}
+
 	private static void assertExpectedSerialized(String expected, XmlElement actual){
 		assertEquals(expected, actual.toString().trim());
 	}


=====================================
src/test/java/de/timeroes/base64/TestBase64.java → src/test/java/de/timroes/base64/TestBase64.java
=====================================
@@ -1,4 +1,4 @@
-package de.timeroes.base64;
+package de.timroes.base64;
 
 import static org.junit.Assert.*;
 



View it on GitLab: https://salsa.debian.org/java-team/axmlrpc/-/compare/4be2b9c68c2b8a5eb283baec6678fe9ea68c1c52...d267598e78288449d343d14279e896b1c6de6d90

-- 
View it on GitLab: https://salsa.debian.org/java-team/axmlrpc/-/compare/4be2b9c68c2b8a5eb283baec6678fe9ea68c1c52...d267598e78288449d343d14279e896b1c6de6d90
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20210118/d8dc8f12/attachment.html>


More information about the pkg-java-commits mailing list