From 4ab27d83a1e1c89dbd39d0fedd09b64dff603cd3 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 22 Oct 2014 01:04:22 +0200 Subject: [PATCH] Consistently accept empty Content-Type header and empty character encoding Issue: SPR-12173 (cherry picked from commit a1c0905) --- .../mock/web/MockHttpServletRequest.java | 19 +++++----- .../http/server/ServletServerHttpRequest.java | 38 ++++++++++++------- .../server/ServletServerHttpRequestTests.java | 28 ++++++++++++-- .../mock/web/test/MockHttpServletRequest.java | 11 +++--- 4 files changed, 65 insertions(+), 31 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java index 0d29289c77ed..178dffd62c2e 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -47,6 +47,7 @@ import org.springframework.util.Assert; import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.util.StringUtils; /** * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} interface. @@ -210,8 +211,8 @@ public MockHttpServletRequest(String method, String requestURI) { /** * Create a new {@code MockHttpServletRequest} with the supplied {@link ServletContext}. - * @param servletContext the ServletContext that the request runs in (may be - * {@code null} to use a default {@link MockServletContext}) + * @param servletContext the ServletContext that the request runs in + * (may be {@code null} to use a default {@link MockServletContext}) * @see #MockHttpServletRequest(ServletContext, String, String) */ public MockHttpServletRequest(ServletContext servletContext) { @@ -308,9 +309,10 @@ public void setCharacterEncoding(String characterEncoding) { } private void updateContentTypeHeader() { - if (this.contentType != null) { + if (StringUtils.hasLength(this.contentType)) { StringBuilder sb = new StringBuilder(this.contentType); - if (!this.contentType.toLowerCase().contains(CHARSET_PREFIX) && this.characterEncoding != null) { + if (!this.contentType.toLowerCase().contains(CHARSET_PREFIX) && + StringUtils.hasLength(this.characterEncoding)) { sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding); } doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true); @@ -330,8 +332,7 @@ public void setContentType(String contentType) { if (contentType != null) { int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX); if (charsetIndex != -1) { - String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); - this.characterEncoding = encoding; + this.characterEncoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); } updateContentTypeHeader(); } @@ -715,8 +716,8 @@ else if (value instanceof Number) { return ((Number) value).longValue(); } else if (value != null) { - throw new IllegalArgumentException("Value for header '" + name + "' is neither a Date nor a Number: " - + value); + throw new IllegalArgumentException( + "Value for header '" + name + "' is neither a Date nor a Number: " + value); } else { return -1L; diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java index a7a03ea76b8a..a8117f933e51 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java @@ -28,7 +28,6 @@ import java.nio.charset.Charset; import java.util.Arrays; import java.util.Enumeration; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -38,6 +37,8 @@ import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.util.Assert; +import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.util.StringUtils; /** * {@link ServerHttpRequest} implementation that is based on a {@link HttpServletRequest}. @@ -103,21 +104,30 @@ public HttpHeaders getHeaders() { } } // HttpServletRequest exposes some headers as properties: we should include those if not already present - if (this.headers.getContentType() == null && this.servletRequest.getContentType() != null) { - MediaType contentType = MediaType.parseMediaType(this.servletRequest.getContentType()); - this.headers.setContentType(contentType); + MediaType contentType = this.headers.getContentType(); + if (contentType == null) { + String requestContentType = this.servletRequest.getContentType(); + if (StringUtils.hasLength(requestContentType)) { + contentType = MediaType.parseMediaType(requestContentType); + this.headers.setContentType(contentType); + } } - if (this.headers.getContentType() != null && this.headers.getContentType().getCharSet() == null && - this.servletRequest.getCharacterEncoding() != null) { - MediaType oldContentType = this.headers.getContentType(); - Charset charSet = Charset.forName(this.servletRequest.getCharacterEncoding()); - Map params = new HashMap(oldContentType.getParameters()); - params.put("charset", charSet.toString()); - MediaType newContentType = new MediaType(oldContentType.getType(), oldContentType.getSubtype(), params); - this.headers.setContentType(newContentType); + if (contentType != null && contentType.getCharSet() == null) { + String requestEncoding = this.servletRequest.getCharacterEncoding(); + if (StringUtils.hasLength(requestEncoding)) { + Charset charSet = Charset.forName(requestEncoding); + Map params = new LinkedCaseInsensitiveMap(); + params.putAll(contentType.getParameters()); + params.put("charset", charSet.toString()); + MediaType newContentType = new MediaType(contentType.getType(), contentType.getSubtype(), params); + this.headers.setContentType(newContentType); + } } - if (this.headers.getContentLength() == -1 && this.servletRequest.getContentLength() != -1) { - this.headers.setContentLength(this.servletRequest.getContentLength()); + if (this.headers.getContentLength() == -1) { + int requestContentLength = this.servletRequest.getContentLength(); + if (requestContentLength != -1) { + this.headers.setContentLength(requestContentLength); + } } } return this.headers; diff --git a/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpRequestTests.java b/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpRequestTests.java index 9b0555ae57c7..490b0369b034 100644 --- a/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpRequestTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/ServletServerHttpRequestTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -40,12 +40,14 @@ public class ServletServerHttpRequestTests { private MockHttpServletRequest mockRequest; + @Before public void create() throws Exception { mockRequest = new MockHttpServletRequest(); request = new ServletServerHttpRequest(mockRequest); } + @Test public void getMethod() throws Exception { mockRequest.setMethod("POST"); @@ -66,8 +68,8 @@ public void getURI() throws Exception { public void getHeaders() throws Exception { String headerName = "MyHeader"; String headerValue1 = "value1"; - mockRequest.addHeader(headerName, headerValue1); String headerValue2 = "value2"; + mockRequest.addHeader(headerName, headerValue1); mockRequest.addHeader(headerName, headerValue2); mockRequest.setContentType("text/plain"); mockRequest.setCharacterEncoding("UTF-8"); @@ -83,6 +85,26 @@ public void getHeaders() throws Exception { headers.getContentType()); } + @Test + public void getHeadersWithEmptyContentTypeAndEncoding() throws Exception { + String headerName = "MyHeader"; + String headerValue1 = "value1"; + String headerValue2 = "value2"; + mockRequest.addHeader(headerName, headerValue1); + mockRequest.addHeader(headerName, headerValue2); + mockRequest.setContentType(""); + mockRequest.setCharacterEncoding(""); + + HttpHeaders headers = request.getHeaders(); + assertNotNull("No HttpHeaders returned", headers); + assertTrue("Invalid headers returned", headers.containsKey(headerName)); + List headerValues = headers.get(headerName); + assertEquals("Invalid header values returned", 2, headerValues.size()); + assertTrue("Invalid header values returned", headerValues.contains(headerValue1)); + assertTrue("Invalid header values returned", headerValues.contains(headerValue2)); + assertNull(headers.getContentType()); + } + @Test public void getBody() throws Exception { byte[] content = "Hello World".getBytes("UTF-8"); @@ -106,4 +128,4 @@ public void getFormBody() throws Exception { assertArrayEquals("Invalid content returned", content, result); } -} \ No newline at end of file +} diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java index c5dc6d760105..ca858632e642 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -52,6 +52,7 @@ import org.springframework.util.Assert; import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.util.StringUtils; /** * Mock implementation of the {@link javax.servlet.http.HttpServletRequest} @@ -331,9 +332,10 @@ public void setCharacterEncoding(String characterEncoding) { } private void updateContentTypeHeader() { - if (this.contentType != null) { + if (StringUtils.hasLength(this.contentType)) { StringBuilder sb = new StringBuilder(this.contentType); - if (!this.contentType.toLowerCase().contains(CHARSET_PREFIX) && this.characterEncoding != null) { + if (!this.contentType.toLowerCase().contains(CHARSET_PREFIX) && + StringUtils.hasLength(this.characterEncoding)) { sb.append(";").append(CHARSET_PREFIX).append(this.characterEncoding); } doAddHeaderValue(CONTENT_TYPE_HEADER, sb.toString(), true); @@ -354,8 +356,7 @@ public void setContentType(String contentType) { if (contentType != null) { int charsetIndex = contentType.toLowerCase().indexOf(CHARSET_PREFIX); if (charsetIndex != -1) { - String encoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); - this.characterEncoding = encoding; + this.characterEncoding = contentType.substring(charsetIndex + CHARSET_PREFIX.length()); } updateContentTypeHeader(); }