Use request contentType/encoding in ServletServetHttpRequest/Response

ServletServerHttpRequest now falls back on the contentType and the
the characterEncoding of the ServletRequest, if the headers of the
incoming request don't specify one. Similary ServletServerHttpResponse
sets the contentType and the characterEncoding of the ServletResponse
if not already set.

This allows using the CharacterEncodingFilter to set a character
encoding where the request doesn't specify one and have it be used
in HttpMessageConverter's.

SPR-9096
This commit is contained in:
Arjen Poutsma 2012-02-09 11:20:24 +01:00 committed by Rossen Stoyanchev
parent ff44c9132c
commit edc80ffa95
6 changed files with 62 additions and 11 deletions

View File

@ -42,6 +42,7 @@ Changes in version 3.1.1 (2012-02-13)
* fixed request mapping bug involving direct vs pattern path matches with HTTP methods
* removed check for HTTP "POST" when resolving multipart request controller method arguments
* updated @RequestMapping and reference docs wrt differences between @MVC 3.1 and @MVC 2.5-3.0
* ServletServerHttpRequest/Response fall back on the Content-Type and encoding of the request
Changes in version 3.1 GA (2011-12-12)

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
@ -450,6 +450,14 @@ public class MediaType implements Comparable<MediaType> {
return this.parameters.get(name);
}
/**
* Return all generic parameter values.
* @return a read-only map, possibly empty, never <code>null</code>
*/
public Map<String, String> getParameters() {
return parameters;
}
/**
* Indicate whether this {@code MediaType} includes the given media type.
* <p>For instance, {@code text/*} includes {@code text/plain} and {@code text/html}, and {@code application/*+xml}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
@ -25,15 +25,19 @@ import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
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;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
/**
@ -90,14 +94,31 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
public HttpHeaders getHeaders() {
if (this.headers == null) {
this.headers = new HttpHeaders();
for (Enumeration headerNames = this.servletRequest.getHeaderNames(); headerNames.hasMoreElements();) {
for (Enumeration<?> headerNames = this.servletRequest.getHeaderNames(); headerNames.hasMoreElements();) {
String headerName = (String) headerNames.nextElement();
for (Enumeration headerValues = this.servletRequest.getHeaders(headerName);
for (Enumeration<?> headerValues = this.servletRequest.getHeaders(headerName);
headerValues.hasMoreElements();) {
String headerValue = (String) headerValues.nextElement();
this.headers.add(headerName, headerValue);
}
}
// 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);
}
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 (this.headers.getContentLength() == -1 && this.servletRequest.getContentLength() != -1) {
this.headers.setContentLength(this.servletRequest.getContentLength());
}
}
return this.headers;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
@ -83,6 +83,14 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
this.servletResponse.addHeader(headerName, headerValue);
}
}
// HttpServletResponse exposes some headers as properties: we should include those if not already present
if (this.servletResponse.getContentType() == null && this.headers.getContentType() != null) {
this.servletResponse.setContentType(this.headers.getContentType().toString());
}
if (this.servletResponse.getCharacterEncoding() == null && this.headers.getContentType() != null &&
this.headers.getContentType().getCharSet() != null) {
this.servletResponse.setCharacterEncoding(this.headers.getContentType().getCharSet().name());
}
this.headersWritten = true;
}
}

View File

@ -1,11 +1,11 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2012 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -17,6 +17,7 @@
package org.springframework.http.server;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.List;
import org.junit.Before;
@ -24,6 +25,7 @@ import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.util.FileCopyUtils;
@ -67,6 +69,8 @@ public class ServletServerHttpRequestTests {
mockRequest.addHeader(headerName, headerValue1);
String headerValue2 = "value2";
mockRequest.addHeader(headerName, headerValue2);
mockRequest.setContentType("text/plain");
mockRequest.setCharacterEncoding("UTF-8");
HttpHeaders headers = request.getHeaders();
assertNotNull("No HttpHeaders returned", headers);
@ -75,6 +79,8 @@ public class ServletServerHttpRequestTests {
assertEquals("Invalid header values returned", 2, headerValues.size());
assertTrue("Invalid header values returned", headerValues.contains(headerValue1));
assertTrue("Invalid header values returned", headerValues.contains(headerValue2));
assertEquals("Invalid Content-Type", new MediaType("text", "plain", Charset.forName("UTF-8")),
headers.getContentType());
}
@Test

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2012 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.
@ -16,16 +16,19 @@
package org.springframework.http.server;
import java.nio.charset.Charset;
import java.util.List;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.FileCopyUtils;
import static org.junit.Assert.*;
/**
* @author Arjen Poutsma
@ -56,12 +59,16 @@ public class ServletServerHttpResponseTests {
headers.add(headerName, headerValue1);
String headerValue2 = "value2";
headers.add(headerName, headerValue2);
headers.setContentType(new MediaType("text", "plain", Charset.forName("UTF-8")));
response.close();
assertTrue("Header not set", mockResponse.getHeaderNames().contains(headerName));
List headerValues = mockResponse.getHeaders(headerName);
assertTrue("Header not set", headerValues.contains(headerValue1));
assertTrue("Header not set", headerValues.contains(headerValue2));
assertEquals("Invalid Content-Type", "text/plain;charset=UTF-8", mockResponse.getHeader("Content-Type"));
assertEquals("Invalid Content-Type", "text/plain;charset=UTF-8", mockResponse.getContentType());
assertEquals("Invalid Content-Type", "UTF-8", mockResponse.getCharacterEncoding());
}
@Test