From afd93a0b52441d2ecf23242850ed8c1776524e0b Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 5 Jan 2017 14:48:35 +0100 Subject: [PATCH] Disable streaming when reading to Resources in RestTemplate Prior to this commit, the `ResourceHttpMessageConverter` would support converting from an `HttpInputMessage` to a `InputStreamResource`. This is valid when reading resources on the server side, but it's not compatible with the way `RestTemplate` works. The API exposed by `RestOperations` imply that the HTTP server response should be fully consumed and properly closed by the time the `exchange` method returns. In other words, this HTTP client does not support streaming the HTTP response. This commit allows the `ResourceHttpMessageConverter` to be configured to disable read streaming when used in `RestTemplate`. Issue: SPR-14882 --- .../ResourceHttpMessageConverter.java | 22 +++++++++++++++++-- .../web/client/RestTemplate.java | 4 ++-- .../ResourceHttpMessageConverterTests.java | 18 ++++++++++++++- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java b/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java index 5e7a321d8b..c19e136cd2 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java +++ b/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.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. @@ -49,9 +49,27 @@ public class ResourceHttpMessageConverter extends AbstractHttpMessageConverter clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { - if (InputStreamResource.class == clazz) { + if (supportsReadStreaming && InputStreamResource.class == clazz) { return new InputStreamResource(inputMessage.getBody()); } else if (clazz.isAssignableFrom(ByteArrayResource.class)) { diff --git a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java index 358ffc4011..316a5d2c80 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestTemplate.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestTemplate.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. @@ -161,7 +161,7 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat public RestTemplate() { this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(new StringHttpMessageConverter()); - this.messageConverters.add(new ResourceHttpMessageConverter()); + this.messageConverters.add(new ResourceHttpMessageConverter(false)); this.messageConverters.add(new SourceHttpMessageConverter<>()); this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); diff --git a/spring-web/src/test/java/org/springframework/http/converter/ResourceHttpMessageConverterTests.java b/spring-web/src/test/java/org/springframework/http/converter/ResourceHttpMessageConverterTests.java index 573744deff..5169bcb9c4 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/ResourceHttpMessageConverterTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/ResourceHttpMessageConverterTests.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. @@ -21,7 +21,9 @@ import java.io.IOException; import java.io.InputStream; import java.util.Arrays; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; @@ -47,6 +49,9 @@ public class ResourceHttpMessageConverterTests { private final ResourceHttpMessageConverter converter = new ResourceHttpMessageConverter(); + @Rule + public ExpectedException thrown = ExpectedException.none(); + @Test public void canReadResource() { @@ -79,6 +84,17 @@ public class ResourceHttpMessageConverterTests { } } + @Test // SPR-14882 + public void shouldNotReadInputStreamResource() throws IOException { + ResourceHttpMessageConverter noStreamConverter = new ResourceHttpMessageConverter(false); + try (InputStream body = getClass().getResourceAsStream("logo.jpg") ) { + this.thrown.expect(IllegalStateException.class); + MockHttpInputMessage inputMessage = new MockHttpInputMessage(body); + inputMessage.getHeaders().setContentType(MediaType.IMAGE_JPEG); + noStreamConverter.read(InputStreamResource.class, inputMessage); + } + } + @Test public void shouldWriteImageResource() throws IOException { MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();