You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2019/11/18 08:02:56 UTC
[olingo-odata4] branch master updated: [OLINGO-1409] Better XML
parsing
This is an automated email from the ASF dual-hosted git repository.
mibo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/olingo-odata4.git
The following commit(s) were added to refs/heads/master by this push:
new c3f982d [OLINGO-1409] Better XML parsing
new 3cf93d5 Merge pull request #59 from artem-smotrakov/better-xml-parsing
c3f982d is described below
commit c3f982db3d97e395d313ae8f231202bb2139882c
Author: Artem Smotrakov <ar...@sap.com>
AuthorDate: Wed Nov 13 10:55:48 2019 +0100
[OLINGO-1409] Better XML parsing
---
.../org/apache/olingo/fit/metadata/Metadata.java | 4 +
.../olingo/fit/utils/XMLEventReaderWrapper.java | 4 +
.../org/apache/olingo/fit/utils/XMLUtilities.java | 4 +
.../apache/olingo/fit/metadata/MetadataTest.java | 168 +++++++++++++++++++++
.../apache/olingo/fit/metadata/TestHttpServer.java | 79 ++++++++++
.../core/serialization/AtomDeserializer.java | 9 +-
.../apache/olingo/server/core/MetadataParser.java | 2 +-
.../deserializer/xml/ODataXmlDeserializer.java | 2 +-
8 files changed, 268 insertions(+), 4 deletions(-)
diff --git a/fit/src/main/java/org/apache/olingo/fit/metadata/Metadata.java b/fit/src/main/java/org/apache/olingo/fit/metadata/Metadata.java
index 0d88b1d..940d692 100644
--- a/fit/src/main/java/org/apache/olingo/fit/metadata/Metadata.java
+++ b/fit/src/main/java/org/apache/olingo/fit/metadata/Metadata.java
@@ -40,6 +40,8 @@ import org.apache.olingo.fit.utils.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static javax.xml.stream.XMLInputFactory.*;
+
public class Metadata extends AbstractMetadataElement {
/**
@@ -57,6 +59,8 @@ public class Metadata extends AbstractMetadataElement {
try {
final XMLInputFactory ifactory = XMLInputFactory.newInstance();
+ ifactory.setProperty(SUPPORT_DTD, false);
+ ifactory.setProperty(IS_SUPPORTING_EXTERNAL_ENTITIES, false);
final XMLEventReader reader = ifactory.createXMLEventReader(is, org.apache.olingo.commons.api.Constants.UTF8);
try {
diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/XMLEventReaderWrapper.java b/fit/src/main/java/org/apache/olingo/fit/utils/XMLEventReaderWrapper.java
index 14936fc..61803e3 100644
--- a/fit/src/main/java/org/apache/olingo/fit/utils/XMLEventReaderWrapper.java
+++ b/fit/src/main/java/org/apache/olingo/fit/utils/XMLEventReaderWrapper.java
@@ -31,6 +31,8 @@ import javax.xml.stream.events.XMLEvent;
import org.apache.commons.io.IOUtils;
+import static javax.xml.stream.XMLInputFactory.*;
+
public class XMLEventReaderWrapper implements XMLEventReader {
private static final Charset ENCODING = Charset.forName(org.apache.olingo.commons.api.Constants.UTF8);
@@ -58,6 +60,8 @@ public class XMLEventReaderWrapper implements XMLEventReader {
CONTENT_STAG = startBuilder.toString();
final XMLInputFactory factory = XMLInputFactory.newInstance();
+ factory.setProperty(SUPPORT_DTD, false);
+ factory.setProperty(IS_SUPPORTING_EXTERNAL_ENTITIES, false);
final InputStreamReader reader = new InputStreamReader(
new ByteArrayInputStream((CONTENT_STAG
diff --git a/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java b/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java
index c7930f0..293d631 100644
--- a/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java
+++ b/fit/src/main/java/org/apache/olingo/fit/utils/XMLUtilities.java
@@ -60,6 +60,8 @@ import org.apache.commons.vfs2.FileSystemException;
import org.apache.olingo.fit.metadata.Metadata;
import org.apache.olingo.fit.metadata.NavigationProperty;
+import static javax.xml.stream.XMLInputFactory.*;
+
public class XMLUtilities extends AbstractUtilities {
private static final Pattern ENTITY_URI_PATTERN = Pattern.compile(".*\\/.*\\(.*\\)");
@@ -80,6 +82,8 @@ public class XMLUtilities extends AbstractUtilities {
protected XMLEventReader getEventReader(final InputStream is) throws XMLStreamException {
if (ifactory == null) {
ifactory = XMLInputFactory.newInstance();
+ ifactory.setProperty(SUPPORT_DTD, false);
+ ifactory.setProperty(IS_SUPPORTING_EXTERNAL_ENTITIES, false);
}
return ifactory.createXMLEventReader(new InputStreamReader(is, Constants.DECODER));
diff --git a/fit/src/test/java/org/apache/olingo/fit/metadata/MetadataTest.java b/fit/src/test/java/org/apache/olingo/fit/metadata/MetadataTest.java
new file mode 100644
index 0000000..3f4824d
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/metadata/MetadataTest.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.fit.metadata;
+
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import static org.junit.Assert.fail;
+
+public class MetadataTest {
+
+ @Test
+ public void testExternalEntity() throws IOException {
+ TestHttpServer server = new TestHttpServer("secret");
+ try {
+ String xml = String.format(
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ + "<!DOCTYPE oops [\n"
+ + " <!ENTITY foo SYSTEM \"%s\" >\n"
+ + "]>\n"
+ + "<oops>&foo;</oops>",
+ server.url());
+
+ new Metadata(new ByteArrayInputStream(xml.getBytes()));
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ } finally {
+ server.close();
+ }
+
+ if (server.accepted()) {
+ fail("Oops! The server has been reached!");
+ }
+ }
+
+ @Test
+ public void testExternalSchema() throws IOException {
+ TestHttpServer server = new TestHttpServer("secret");
+ try {
+ String xml = String.format(
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ + "<!DOCTYPE oops SYSTEM ā%sā>\n"
+ + "<oops>&foo;</oops>",
+ server.url());
+
+ new Metadata(new ByteArrayInputStream(xml.getBytes()));
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ } finally {
+ server.close();
+ }
+
+ if (server.accepted()) {
+ fail("Oops! The server has been reached!");
+ }
+ }
+
+ @Test
+ public void testExternalEntityParameter() throws IOException {
+ TestHttpServer server = new TestHttpServer("secret");
+ try {
+ String xml = String.format(
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ + "<!DOCTYPE oops [\n"
+ + " <!ENTITY %% sp SYSTEM \"%s\">\n"
+ + "%%sp;"
+ + "]>\n"
+ + "<oops></oops>",
+ server.url());
+
+ new Metadata(new ByteArrayInputStream(xml.getBytes()));
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ } finally {
+ server.close();
+ }
+
+ if (server.accepted()) {
+ fail("Oops! The server has been reached!");
+ }
+ }
+
+ @Test
+ public void billionLaughs() {
+ String xml =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<!DOCTYPE lolz [\n" +
+ " <!ENTITY lol \"lol\">\n" +
+ " <!ELEMENT lolz (#PCDATA)>\n" +
+ " <!ENTITY lol1 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">\n" +
+ " <!ENTITY lol2 \"&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;\">\n" +
+ " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">\n" +
+ " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">\n" +
+ " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">\n" +
+ " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">\n" +
+ " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">\n" +
+ " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">\n" +
+ " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">\n" +
+ "]>\n" +
+ "<lolz>&lol9;</lolz>";
+
+ new Metadata(new ByteArrayInputStream(xml.getBytes()));
+ }
+
+ @Test
+ public void testExternalXInclude() throws IOException {
+ TestHttpServer server = new TestHttpServer("secret");
+ try {
+ String xml = String.format(
+ "<root xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n" +
+ " <xi:include href=\"%s\" parse=\"text\" />\n" +
+ "</root>",
+ server.url());
+
+ new Metadata(new ByteArrayInputStream(xml.getBytes()));
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ } finally {
+ server.close();
+ }
+
+ if (server.accepted()) {
+ fail("Oops! The server has been reached!");
+ }
+ }
+
+ @Test
+ public void testExternalSchemaLocation() throws IOException {
+ TestHttpServer server = new TestHttpServer("secret");
+ try {
+ String xml = String.format(
+ "<ead xmlns=\"urn:isbn:1-931666-22-9\"\n" +
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
+ " xsi:schemaLocation=\"urn:isbn:1-931666-22-9 %s\">\n" +
+ "</ead>",
+ server.url());
+
+ new Metadata(new ByteArrayInputStream(xml.getBytes()));
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ } finally {
+ server.close();
+ }
+
+ if (server.accepted()) {
+ fail("Oops! The server has been reached!");
+ }
+ }
+
+}
diff --git a/fit/src/test/java/org/apache/olingo/fit/metadata/TestHttpServer.java b/fit/src/test/java/org/apache/olingo/fit/metadata/TestHttpServer.java
new file mode 100644
index 0000000..2acbda5
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/metadata/TestHttpServer.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.fit.metadata;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+
+/**
+ * Simple HTTP server.
+ */
+public class TestHttpServer implements HttpHandler, AutoCloseable {
+
+ private final String content;
+ private final HttpServer server;
+
+ /**
+ * This flag indicates if the server accepted a connection.
+ */
+ private boolean accepted = false;
+
+ public TestHttpServer(String content) throws IOException {
+ server = HttpServer.create(new InetSocketAddress(0), 0);
+ server.createContext("/test", this);
+ server.setExecutor(null);
+ server.start();
+ this.content = content;
+ }
+
+ public String url() {
+ return String.format("http://localhost:%d/test", server.getAddress().getPort());
+ }
+
+ @Override
+ public void handle(HttpExchange t) throws IOException {
+ System.out.println("server: accepted a request");
+ synchronized (this) {
+ accepted = true;
+ }
+ byte[] response = content.getBytes();
+ t.sendResponseHeaders(200, response.length);
+ try (OutputStream os = t.getResponseBody()) {
+ os.write(response);
+ }
+ }
+
+ /**
+ * @return True if the server accepted a connection, false otherwise.
+ */
+ public boolean accepted() {
+ synchronized (this) {
+ return accepted;
+ }
+ }
+
+ @Override
+ public void close() {
+ server.stop(0);
+ }
+}
\ No newline at end of file
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
index a1b25a5..0136a10 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
@@ -66,6 +66,8 @@ import org.apache.olingo.commons.core.edm.EdmTypeInfo;
import com.fasterxml.aalto.stax.InputFactoryImpl;
import org.apache.olingo.commons.api.ex.ODataErrorDetail;
+import static javax.xml.stream.XMLInputFactory.*;
+
public class AtomDeserializer implements ODataDeserializer {
protected static final QName etagQName = new QName(Constants.NS_METADATA, Constants.ATOM_ATTR_ETAG);
@@ -92,12 +94,15 @@ public class AtomDeserializer implements ODataDeserializer {
new QName(Constants.NS_ATOM_TOMBSTONE, Constants.ATOM_ELEM_DELETED_ENTRY);
protected static final XMLInputFactory FACTORY = new InputFactoryImpl();
+ static {
+ FACTORY.setProperty(IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+ FACTORY.setProperty(SUPPORT_DTD, false);
+ FACTORY.setProperty(IS_REPLACING_ENTITY_REFERENCES, false);
+ }
private final AtomGeoValueDeserializer geoDeserializer;
protected XMLEventReader getReader(final InputStream input) throws XMLStreamException {
- FACTORY.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
- FACTORY.setProperty("javax.xml.stream.isReplacingEntityReferences", false);
return FACTORY.createXMLEventReader(input);
}
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
index 3eeaef3..5cfbfd8 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MetadataParser.java
@@ -254,7 +254,7 @@ public class MetadataParser {
private XMLInputFactory createXmlInputFactory() {
XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- factory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
+ factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
return factory;
}
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
index 8356cba..3854875 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
@@ -95,7 +95,7 @@ public class ODataXmlDeserializer implements ODataDeserializer {
protected XMLEventReader getReader(final InputStream input) throws XMLStreamException {
FACTORY.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- FACTORY.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
+ FACTORY.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
return FACTORY.createXMLEventReader(input);
}