Merge pull request #59 from artem-smotrakov/better-xml-parsing
Better XML parsing
This commit is contained in:
commit
3cf93d5e06
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue