diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/support/DefaultHttpHeaderMapper.java b/spring-integration-http/src/main/java/org/springframework/integration/http/support/DefaultHttpHeaderMapper.java index c703635e76..c926a689d0 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/support/DefaultHttpHeaderMapper.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/support/DefaultHttpHeaderMapper.java @@ -32,7 +32,6 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -45,6 +44,7 @@ import org.springframework.http.MediaType; import org.springframework.integration.MessageHeaders; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.mapping.HeaderMapper; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.PatternMatchUtils; @@ -57,6 +57,7 @@ import org.springframework.util.StringUtils; * @author Jeremy Grelle * @author Oleg Zhurakousky * @author Gunnar Hillert + * @author Gary Russell * @since 2.0 */ public class DefaultHttpHeaderMapper implements HeaderMapper, BeanFactoryAware, InitializingBean{ @@ -228,6 +229,12 @@ public class DefaultHttpHeaderMapper implements HeaderMapper, BeanF WWW_AUTHENTICATE }; + private static String[] HTTP_REQUEST_HEADER_NAMES_OUTBOUND_EXCLUSIONS = new String[0]; + + private static String[] HTTP_RESPONSE_HEADER_NAMES_INBOUND_EXCLUSIONS = new String[] { + CONTENT_LENGTH + }; + public static final String HTTP_REQUEST_HEADER_NAME_PATTERN = "HTTP_REQUEST_HEADERS"; public static final String HTTP_RESPONSE_HEADER_NAME_PATTERN = "HTTP_RESPONSE_HEADERS"; @@ -237,6 +244,10 @@ public class DefaultHttpHeaderMapper implements HeaderMapper, BeanF private volatile String[] inboundHeaderNames = new String[0]; + private volatile String[] excludedOutboundStandardRequestHeaderNames = new String[0]; + + private volatile String[] excludedInboundStandardResponseHeaderNames = new String[0]; + private volatile String userDefinedHeaderPrefix = "X-"; public void setBeanFactory(BeanFactory beanFactory) throws BeansException { @@ -268,6 +279,26 @@ public class DefaultHttpHeaderMapper implements HeaderMapper, BeanF this.inboundHeaderNames = (inboundHeaderNames != null) ? inboundHeaderNames : new String[0]; } + /** + * Provide header names from the list of standard headers that should be suppressed when + * mapping outbound endpoint request headers. + * @param excludedOutboundStandardRequestHeaderNames the excludedStandardRequestHeaderNames to set + */ + public void setExcludedOutboundStandardRequestHeaderNames(String[] excludedOutboundStandardRequestHeaderNames) { + Assert.notNull(excludedOutboundStandardRequestHeaderNames, "'excludedOutboundStandardRequestHeaderNames' must not be null"); + this.excludedOutboundStandardRequestHeaderNames = excludedOutboundStandardRequestHeaderNames; + } + + /** + * Provide header names from the list of standard headers that should be suppressed when + * mapping inbound endopoint response headers. + * @param excludedInboundStandardResponseHeaderNames the excludedStandardResponseHeaderNames to set + */ + public void setExcludedInboundStandardResponseHeaderNames(String[] excludedInboundStandardResponseHeaderNames) { + Assert.notNull(excludedInboundStandardResponseHeaderNames, "'excludedInboundStandardResponseHeaderNames' must not be null"); + this.excludedInboundStandardResponseHeaderNames = excludedInboundStandardResponseHeaderNames; + } + /** * Sets the prefix to use with user-defined (non-standard) headers. Default is 'X-'. */ @@ -359,6 +390,30 @@ public class DefaultHttpHeaderMapper implements HeaderMapper, BeanF } private boolean shouldMapOutboundHeader(String headerName) { + if (this.outboundHeaderNames == HTTP_RESPONSE_HEADER_NAMES) { // a default inbound mapper + /* + * When using the default response header name list, suppress the + * mapping of exclusions for specific headers. + */ + if (this.containsElementIgnoreCase(this.excludedInboundStandardResponseHeaderNames, headerName)) { + if (logger.isDebugEnabled()) { + logger.debug(MessageFormat.format("headerName=[{0}] WILL NOT be mapped", headerName)); + } + return false; + } + } + else if (this.outboundHeaderNames == HTTP_REQUEST_HEADER_NAMES) { // a default outbound mapper + /* + * When using the default request header name list, suppress the + * mapping of exclusions for specific headers. + */ + if (this.containsElementIgnoreCase(this.excludedOutboundStandardRequestHeaderNames, headerName)) { + if (logger.isDebugEnabled()) { + logger.debug(MessageFormat.format("headerName=[{0}] WILL NOT be mapped", headerName)); + } + return false; + } + } return this.shouldMapHeader(headerName, this.outboundHeaderNames); } @@ -841,6 +896,7 @@ public class DefaultHttpHeaderMapper implements HeaderMapper, BeanF DefaultHttpHeaderMapper mapper = new DefaultHttpHeaderMapper(); mapper.setOutboundHeaderNames(HTTP_REQUEST_HEADER_NAMES); mapper.setInboundHeaderNames(HTTP_RESPONSE_HEADER_NAMES); + mapper.setExcludedOutboundStandardRequestHeaderNames(HTTP_REQUEST_HEADER_NAMES_OUTBOUND_EXCLUSIONS); return mapper; } @@ -853,6 +909,7 @@ public class DefaultHttpHeaderMapper implements HeaderMapper, BeanF DefaultHttpHeaderMapper mapper = new DefaultHttpHeaderMapper(); mapper.setInboundHeaderNames(HTTP_REQUEST_HEADER_NAMES); mapper.setOutboundHeaderNames(HTTP_RESPONSE_HEADER_NAMES); + mapper.setExcludedInboundStandardResponseHeaderNames(HTTP_RESPONSE_HEADER_NAMES_INBOUND_EXCLUSIONS); return mapper; } } diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/support/DefaultHttpHeaderMapperFromMessageInboundTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/support/DefaultHttpHeaderMapperFromMessageInboundTests.java index 11b8ae08c2..7543afe5d7 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/support/DefaultHttpHeaderMapperFromMessageInboundTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/support/DefaultHttpHeaderMapperFromMessageInboundTests.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertNull; import java.net.URI; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -543,6 +544,18 @@ public class DefaultHttpHeaderMapperFromMessageInboundTests { assertEquals("TestClass.class", headers.get("X-customHeaderB").get(0)); } + @Test + public void dontPropagateContentLength() { + HeaderMapper mapper = DefaultHttpHeaderMapper.inboundMapper(); + HttpHeaders headers = new HttpHeaders(); + // suppressed in response on inbound, by default + headers.put("Content-Length", Arrays.asList(new String[] {"3"})); + Map messageHeaders = mapper.toHeaders(headers); + headers = new HttpHeaders(); + mapper.fromHeaders(new MessageHeaders(messageHeaders), headers); + assertNull(headers.get("Content-Length")); + } + public static class TestClass { } diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/support/DefaultHttpHeaderMapperFromMessageOutboundTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/support/DefaultHttpHeaderMapperFromMessageOutboundTests.java index 2283866211..68194f8b78 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/support/DefaultHttpHeaderMapperFromMessageOutboundTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/support/DefaultHttpHeaderMapperFromMessageOutboundTests.java @@ -32,7 +32,6 @@ import java.util.Locale; import java.util.Map; import org.junit.Test; - import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.integration.MessageHeaders; @@ -646,4 +645,16 @@ public class DefaultHttpHeaderMapperFromMessageOutboundTests { assertEquals(1, headers.get("X-baz").size()); assertEquals(1, headers.get("x-baz").size()); } + @Test + public void dontPropagateContentLength() { + DefaultHttpHeaderMapper mapper = DefaultHttpHeaderMapper.outboundMapper(); + // not suppressed on outbound request, by default + mapper.setExcludedOutboundStandardRequestHeaderNames(new String[] {"Content-Length"}); + Map messageHeaders = new HashMap(); + messageHeaders.put("Content-Length", 4); + + HttpHeaders headers = new HttpHeaders(); + mapper.fromHeaders(new MessageHeaders(messageHeaders), headers); + assertNull(headers.get("Content-Length")); + } }