From 78c85c2510bf0bc4d4960196409a483bace248e4 Mon Sep 17 00:00:00 2001 From: Gunnar Hillert Date: Thu, 2 Aug 2012 16:46:42 -0400 Subject: [PATCH] INT-2680 - Duplicate Content-Type header For reference please see: https://jira.springsource.org/browse/INT-2680 --- build.gradle | 12 +++- .../HttpRequestHandlingController.java | 5 +- .../HttpRequestHandlingEndpointSupport.java | 23 +++++-- .../HttpRequestHandlingMessagingGateway.java | 9 ++- ...pRequestHandlingMessagingGatewayTests.java | 65 +++++++++++++++++++ 5 files changed, 103 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 0a01834b25..79e81a0f62 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,9 @@ subprojects { subproject -> mockitoVersion = '1.9.0' // When changing Spring Versions - don't forget to update bundlor ranges - springVersion = project.hasProperty('springVersion') ? getProperty('springVersion') : '3.1.2.RELEASE' + springVersionDefault = '3.1.2.RELEASE' + springVersion = project.hasProperty('springVersion') ? getProperty('springVersion') : springVersionDefault + springAmqpVersion = '1.1.1.RELEASE' springDataMongoVersion = '1.1.0.M1' springDataRedisVersion = '1.0.1.RELEASE' @@ -356,7 +358,13 @@ project('spring-integration-http') { dependencies { compile project(":spring-integration-core") compile "org.springframework:spring-webmvc:$springVersion" - compile("javax.servlet:javax.servlet-api:3.0.1", provided) + + if (springVersionDefault.equalsIgnoreCase(springVersion)) { + compile("javax.servlet:javax.servlet-api:3.0.1", provided) + } else { + compile("javax.servlet:servlet-api:2.5", provided) + } + compile("commons-httpclient:commons-httpclient:3.1") { dep -> optional dep exclude group: 'junit', module: 'junit' diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingController.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingController.java index 0a43cf3ef4..d60baf1b0e 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingController.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingController.java @@ -27,6 +27,7 @@ import org.springframework.context.MessageSource; import org.springframework.expression.Expression; import org.springframework.expression.common.LiteralExpression; import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.integration.Message; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -140,7 +141,9 @@ public class HttpRequestHandlingController extends HttpRequestHandlingEndpointSu try { Message replyMessage = super.doHandleRequest(servletRequest, servletResponse); if (replyMessage != null) { - Object reply = setupResponseAndConvertReply(servletResponse, replyMessage); + ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse); + Object reply = setupResponseAndConvertReply(response, replyMessage); + response.close(); modelAndView.addObject(this.replyKey, reply); } if (this.viewExpression != null) { diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java index fb55f9e776..f9538fc0e4 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java @@ -432,25 +432,38 @@ public abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewa /** * Converts the reply message to the appropriate HTTP reply object and - * sets up the servlet response. - * @param servletResponse The servlet response. + * sets up the {@link ServletServerHttpResponse}. + * + * @param response The ServletServerHttpResponse. * @param replyMessage The reply message. * @return The message payload (if {@link #extractReplyPayload}) otherwise the * message. */ - protected final Object setupResponseAndConvertReply(HttpServletResponse servletResponse, Message replyMessage) { - ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse); + protected final Object setupResponseAndConvertReply(ServletServerHttpResponse response, Message replyMessage) { + this.headerMapper.fromHeaders(replyMessage.getHeaders(), response.getHeaders()); HttpStatus httpStatus = this.resolveHttpStatusFromHeaders(((Message) replyMessage).getHeaders()); if (httpStatus != null) { response.setStatusCode(httpStatus); } - response.close(); + Object reply = replyMessage; if (this.extractReplyPayload) { reply = replyMessage.getPayload(); } return reply; + + } + + /** + * @deprecated As of release 2.2, please use {@link #setupResponseAndConvertReply(ServletServerHttpResponse, Message)} instead. + */ + @Deprecated + protected final Object setupResponseAndConvertReply(HttpServletResponse servletResponse, Message replyMessage) { + ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse); + Object reply = setupResponseAndConvertReply(response, replyMessage); + response.close(); + return reply; } /** diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGateway.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGateway.java index c41c03c457..edbf4f3dae 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGateway.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGateway.java @@ -93,18 +93,21 @@ public class HttpRequestHandlingMessagingGateway extends HttpRequestHandlingEndp throws ServletException, IOException { Object responseContent = null; Message responseMessage; + + final ServletServerHttpRequest request = new ServletServerHttpRequest(servletRequest); + final ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse); + try { responseMessage = super.doHandleRequest(servletRequest, servletResponse); if (responseMessage != null) { - responseContent = setupResponseAndConvertReply(servletResponse, responseMessage); + responseContent = setupResponseAndConvertReply(response, responseMessage); } } catch (Exception e) { responseContent = handleExceptionInternal(e); } if (responseContent != null) { - ServletServerHttpRequest request = new ServletServerHttpRequest(servletRequest); - ServletServerHttpResponse response = new ServletServerHttpResponse(servletResponse); + if (responseContent instanceof HttpStatus) { response.setStatusCode((HttpStatus) responseContent); } diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayTests.java index e66984be20..6fa61090e5 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/inbound/HttpRequestHandlingMessagingGatewayTests.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull; import java.io.IOException; import java.io.PrintWriter; import java.io.Serializable; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -30,6 +31,7 @@ import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.AbstractHttpMessageConverter; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; @@ -37,6 +39,7 @@ import org.springframework.integration.Message; import org.springframework.integration.channel.DirectChannel; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.handler.AbstractReplyProducingMessageHandler; +import org.springframework.integration.support.MessageBuilder; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.util.LinkedMultiValueMap; @@ -218,6 +221,68 @@ public class HttpRequestHandlingMessagingGatewayTests { assertEquals(84, result.age); } + @Test + public void INT2680DuplicateContentTypeHeader() throws Exception { + + final DirectChannel requestChannel = new DirectChannel(); + requestChannel.subscribe(new AbstractReplyProducingMessageHandler() { + @Override + protected Object handleRequestMessage(Message requestMessage) { + return MessageBuilder.withPayload("Cartman".getBytes()) + .setHeader("Content-type", "text/plain") + .build(); + } + + }); + + final List supportedMediaTypes = new ArrayList(); + supportedMediaTypes.add(MediaType.TEXT_HTML); + + final ByteArrayHttpMessageConverter messageConverter = new ByteArrayHttpMessageConverter(); + messageConverter.setSupportedMediaTypes(supportedMediaTypes); + + final List> messageConverters = new ArrayList>(); + messageConverters.add(messageConverter); + + final HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(true); + gateway.setMessageConverters(messageConverters); + gateway.setRequestChannel(requestChannel); + + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("GET"); + request.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + + final ContentTypeCheckingMockHttpServletResponse response = new ContentTypeCheckingMockHttpServletResponse(); + gateway.handleRequest(request, response); + + assertEquals("Cartman", response.getContentAsString()); + + /* Before fixing INT2680, 2 content type headers were being written. */ + final List contentTypes = response.getContentTypeList(); + + assertEquals("Exptecting only 1 content type being set.", Integer.valueOf(1), Integer.valueOf(contentTypes.size())); + assertEquals("text/plain", contentTypes.get(0)); + } + + private class ContentTypeCheckingMockHttpServletResponse extends MockHttpServletResponse { + + private List contentTypeList = new ArrayList(); + + @Override + public void addHeader(String name, String value) { + + if ("Content-Type".equalsIgnoreCase(name)) { + this.contentTypeList.add(value); + } + + super.addHeader(name, value); + } + + public List getContentTypeList() { + return contentTypeList; + } + + } private static class TestHttpMessageConverter extends AbstractHttpMessageConverter {