Skip to content

Commit

Permalink
Consistently accept empty Content-Type header and empty character enc…
Browse files Browse the repository at this point in the history
…oding

Issue: SPR-12173
(cherry picked from commit a1c0905)
  • Loading branch information
jhoeller committed Oct 21, 2014
1 parent de3ea5d commit 4ab27d8
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 31 deletions.
@@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down
Expand Up @@ -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;
Expand All @@ -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}.
Expand Down Expand Up @@ -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<String, String> params = new HashMap<String, String>(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<String, String> params = new LinkedCaseInsensitiveMap<String>();
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;
Expand Down
@@ -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.
Expand Down Expand Up @@ -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");
Expand All @@ -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");
Expand All @@ -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<String> 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");
Expand All @@ -106,4 +128,4 @@ public void getFormBody() throws Exception {
assertArrayEquals("Invalid content returned", content, result);
}

}
}
@@ -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.
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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);
Expand All @@ -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();
}
Expand Down

0 comments on commit 4ab27d8

Please sign in to comment.