From e4651d6b50c5bc85c84ff537859c212ac4e33434 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 20 Jul 2017 13:17:27 +0200 Subject: [PATCH] XmlEventDecoder uses common defensive XMLInputFactory (now in StaxUtils) Issue: SPR-15797 --- .../springframework/util/xml/StaxUtils.java | 32 ++++++++++++++++--- .../http/codec/xml/XmlEventDecoder.java | 3 +- .../json/Jackson2ObjectMapperBuilder.java | 27 ++++------------ .../Jaxb2CollectionHttpMessageConverter.java | 23 ++++--------- .../xml/SourceHttpMessageConverter.java | 25 +++++---------- 5 files changed, 50 insertions(+), 60 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java b/spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java index 3bc7dffe156..1b22191c27e 100644 --- a/spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java +++ b/spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java @@ -20,6 +20,8 @@ import java.util.List; import javax.xml.stream.XMLEventFactory; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLResolver; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; @@ -33,13 +35,15 @@ import org.xml.sax.ContentHandler; import org.xml.sax.XMLReader; import org.springframework.lang.Nullable; +import org.springframework.util.StreamUtils; /** - * Convenience methods for working with the StAX API. Partly historic due to JAXP 1.3 compatibility; - * as of Spring 4.0, relying on JAXP 1.4 as included in JDK 1.6 and higher. + * Convenience methods for working with the StAX API. Partly historic due to JAXP 1.3 + * compatibility; as of Spring 4.0, relying on JAXP 1.4 as included in JDK 1.6 and higher. * - *

In particular, methods for using StAX ({@code javax.xml.stream}) in combination with the TrAX API - * ({@code javax.xml.transform}), and converting StAX readers/writers into SAX readers/handlers and vice-versa. + *

In particular, methods for using StAX ({@code javax.xml.stream}) in combination with + * the TrAX API ({@code javax.xml.transform}), and converting StAX readers/writers into SAX + * readers/handlers and vice-versa. * * @author Arjen Poutsma * @author Juergen Hoeller @@ -47,6 +51,24 @@ import org.springframework.lang.Nullable; */ public abstract class StaxUtils { + private static final XMLResolver NO_OP_XML_RESOLVER = + (publicID, systemID, base, ns) -> StreamUtils.emptyInput(); + + + /** + * Create an {@link XMLInputFactory} with Spring's defensive setup, + * i.e. no support for the resolution of DTDs and external entities. + * @return a new input factory to use + * @since 5.0 + */ + public static XMLInputFactory createDefensiveInputFactory() { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); + inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); + inputFactory.setXMLResolver(NO_OP_XML_RESOLVER); + return inputFactory; + } + /** * Create a JAXP 1.4 {@link StAXSource} for the given {@link XMLStreamReader}. * @param streamReader the StAX stream reader @@ -57,7 +79,7 @@ public abstract class StaxUtils { } /** - * Create a JAXP 1.4 a {@link StAXSource} for the given {@link XMLEventReader}. + * Create a JAXP 1.4 {@link StAXSource} for the given {@link XMLEventReader}. * @param eventReader the StAX event reader * @return a source wrapping the {@code eventReader} */ diff --git a/spring-web/src/main/java/org/springframework/http/codec/xml/XmlEventDecoder.java b/spring-web/src/main/java/org/springframework/http/codec/xml/XmlEventDecoder.java index a2640b7d3e1..1d5e44005bc 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/xml/XmlEventDecoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/xml/XmlEventDecoder.java @@ -44,6 +44,7 @@ import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.MimeType; import org.springframework.util.MimeTypeUtils; +import org.springframework.util.xml.StaxUtils; /** * Decodes a {@link DataBuffer} stream into a stream of {@link XMLEvent}s. @@ -77,7 +78,7 @@ import org.springframework.util.MimeTypeUtils; */ public class XmlEventDecoder extends AbstractDecoder { - private static final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + private static final XMLInputFactory inputFactory = StaxUtils.createDefensiveInputFactory(); private static final boolean aaltoPresent = ClassUtils.isPresent( "com.fasterxml.aalto.AsyncXMLStreamReader", XmlEventDecoder.class.getClassLoader()); diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java index 499122a855c..997ff919f7b 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java @@ -26,8 +26,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLResolver; import com.fasterxml.jackson.annotation.JsonFilter; import com.fasterxml.jackson.annotation.JsonInclude; @@ -62,8 +60,8 @@ import org.springframework.context.ApplicationContext; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; +import org.springframework.util.xml.StaxUtils; /** * A builder used to create {@link ObjectMapper} instances with a fluent API. @@ -827,38 +825,27 @@ public class Jackson2ObjectMapperBuilder { private static class XmlObjectMapperInitializer { public ObjectMapper create() { - return new XmlMapper(xmlInputFactory()); + return new XmlMapper(StaxUtils.createDefensiveInputFactory()); } public ObjectMapper create(boolean defaultUseWrapper) { JacksonXmlModule module = new JacksonXmlModule(); module.setDefaultUseWrapper(defaultUseWrapper); - return new XmlMapper(new XmlFactory(xmlInputFactory()), module); + return new XmlMapper(new XmlFactory(StaxUtils.createDefensiveInputFactory()), module); } - - private static XMLInputFactory xmlInputFactory() { - XMLInputFactory inputFactory = XMLInputFactory.newInstance(); - inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); - inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); - inputFactory.setXMLResolver(NO_OP_XML_RESOLVER); - return inputFactory; - } - - private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() { - @Override - public Object resolveEntity(String publicID, String systemID, String base, String ns) { - return StreamUtils.emptyInput(); - } - }; } + private static class SmileFactoryInitializer { + public JsonFactory create() { return new SmileFactory(); } } + private static class CborFactoryInitializer { + public JsonFactory create() { return new CBORFactory(); } diff --git a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java index 73ad629718a..706c715a350 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java @@ -31,7 +31,6 @@ import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLResolver; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Result; @@ -47,7 +46,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.lang.Nullable; import org.springframework.util.ReflectionUtils; -import org.springframework.util.StreamUtils; +import org.springframework.util.xml.StaxUtils; /** * An {@code HttpMessageConverter} that can read XML collections using JAXB2. @@ -242,25 +241,15 @@ public class Jaxb2CollectionHttpMessageConverter } /** - * Create a {@code XMLInputFactory} that this converter will use to create {@link - * javax.xml.stream.XMLStreamReader} and {@link javax.xml.stream.XMLEventReader} objects. + * Create an {@code XMLInputFactory} that this converter will use to create + * {@link javax.xml.stream.XMLStreamReader} and {@link javax.xml.stream.XMLEventReader} + * objects. *

Can be overridden in subclasses, adding further initialization of the factory. * The resulting factory is cached, so this method will only be called once. + * @see StaxUtils#createDefensiveInputFactory() */ protected XMLInputFactory createXmlInputFactory() { - XMLInputFactory inputFactory = XMLInputFactory.newInstance(); - inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); - inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); - inputFactory.setXMLResolver(NO_OP_XML_RESOLVER); - return inputFactory; + return StaxUtils.createDefensiveInputFactory(); } - - private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() { - @Override - public Object resolveEntity(String publicID, String systemID, String base, String ns) { - return StreamUtils.emptyInput(); - } - }; - } diff --git a/spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java index 36574e1a61d..dd8e96aa997 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -66,7 +66,13 @@ import org.springframework.util.StreamUtils; */ public class SourceHttpMessageConverter extends AbstractHttpMessageConverter { - private static final Set> SUPPORTED_CLASSES = new HashSet<>(5); + private static final EntityResolver NO_OP_ENTITY_RESOLVER = + (publicId, systemId) -> new InputSource(new StringReader("")); + + private static final XMLResolver NO_OP_XML_RESOLVER = + (publicID, systemID, base, ns) -> StreamUtils.emptyInput(); + + private static final Set> SUPPORTED_CLASSES = new HashSet<>(8); static { SUPPORTED_CLASSES.add(DOMSource.class); @@ -279,19 +285,4 @@ public class SourceHttpMessageConverter extends AbstractHttpMe } } - - private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() { - @Override - public InputSource resolveEntity(String publicId, String systemId) { - return new InputSource(new StringReader("")); - } - }; - - private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() { - @Override - public Object resolveEntity(String publicID, String systemID, String base, String ns) { - return StreamUtils.emptyInput(); - } - }; - }