[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 & and the "less then" sign to <.
* 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