Browse Source
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4776 50f2f4bb-b051-0410-bef5-90022cba6387pull/2/head
4 changed files with 544 additions and 130 deletions
@ -0,0 +1,151 @@
@@ -0,0 +1,151 @@
|
||||
/* |
||||
* Copyright 2002-2011 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
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.filter; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.nio.charset.Charset; |
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.Enumeration; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.LinkedHashSet; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletRequestWrapper; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
import org.springframework.http.HttpInputMessage; |
||||
import org.springframework.http.converter.FormHttpMessageConverter; |
||||
import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter; |
||||
import org.springframework.http.server.ServletServerHttpRequest; |
||||
import org.springframework.util.LinkedMultiValueMap; |
||||
import org.springframework.util.MultiValueMap; |
||||
|
||||
/** |
||||
* {@link javax.servlet.Filter} that makes form encoded data available through the |
||||
* {@code ServletRequest.getParameter*()} family of methods during HTTP PUT requests. |
||||
* |
||||
* <p>The Servlet spec requires form data to be available for HTTP POST but not for |
||||
* HTTP PUT requests. This filter intercepts HTTP PUT requests |
||||
* where {@code 'Content-Type:application/x-www-form-urlencoded'}, reads the form |
||||
* data from the body of the request, and wraps the ServletRequest in order to make |
||||
* the form data available as request parameters. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
* @since 3.1 |
||||
*/ |
||||
public class HttpPutFormContentFilter extends OncePerRequestFilter { |
||||
|
||||
private static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded"; |
||||
|
||||
private final FormHttpMessageConverter formConverter = new XmlAwareFormHttpMessageConverter(); |
||||
|
||||
/** |
||||
* The default character set to use for reading form data. |
||||
*/ |
||||
public void setCharset(Charset charset) { |
||||
this.formConverter.setCharset(charset); |
||||
} |
||||
|
||||
@Override |
||||
protected void doFilterInternal(final HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) |
||||
throws ServletException, IOException { |
||||
|
||||
if ("PUT".equals(request.getMethod()) && isFormContentType(request)) { |
||||
HttpInputMessage inputMessage = new ServletServerHttpRequest(request) { |
||||
@Override |
||||
public InputStream getBody() throws IOException { |
||||
return request.getInputStream(); |
||||
} |
||||
}; |
||||
MultiValueMap<String, String> formParameters = formConverter.read(null, inputMessage); |
||||
HttpServletRequest wrapper = new HttpPutFormContentRequestWrapper(request, formParameters); |
||||
filterChain.doFilter(wrapper, response); |
||||
} |
||||
else { |
||||
filterChain.doFilter(request, response); |
||||
} |
||||
|
||||
} |
||||
|
||||
private boolean isFormContentType(HttpServletRequest request) { |
||||
String contentType = request.getContentType(); |
||||
return ((contentType != null) && contentType.equals(FORM_CONTENT_TYPE)); |
||||
} |
||||
|
||||
private static class HttpPutFormContentRequestWrapper extends HttpServletRequestWrapper { |
||||
|
||||
private MultiValueMap<String, String> formParameters; |
||||
|
||||
public HttpPutFormContentRequestWrapper(HttpServletRequest request, MultiValueMap<String, String> parameters) { |
||||
super(request); |
||||
this.formParameters = (parameters != null) ? parameters : new LinkedMultiValueMap<String, String>(); |
||||
} |
||||
|
||||
@Override |
||||
public String getParameter(String name) { |
||||
String queryStringValue = super.getParameter(name); |
||||
String formValue = this.formParameters.getFirst(name); |
||||
return (queryStringValue != null) ? queryStringValue : formValue; |
||||
} |
||||
|
||||
@Override |
||||
public Map<String, String[]> getParameterMap() { |
||||
Map<String, String[]> result = new LinkedHashMap<String, String[]>(); |
||||
Enumeration<String> names = this.getParameterNames(); |
||||
while (names.hasMoreElements()) { |
||||
String name = names.nextElement(); |
||||
result.put(name, this.getParameterValues(name)); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public Enumeration<String> getParameterNames() { |
||||
Set<String> names = new LinkedHashSet<String>(); |
||||
names.addAll(Collections.list(super.getParameterNames())); |
||||
names.addAll(this.formParameters.keySet()); |
||||
return Collections.enumeration(names); |
||||
} |
||||
|
||||
@Override |
||||
public String[] getParameterValues(String name) { |
||||
String[] queryStringValues = super.getParameterValues(name); |
||||
List<String> formValues = this.formParameters.get(name); |
||||
if (formValues == null) { |
||||
return queryStringValues; |
||||
} |
||||
else if (queryStringValues == null) { |
||||
return formValues.toArray(new String[formValues.size()]); |
||||
} |
||||
else { |
||||
List<String> result = new ArrayList<String>(); |
||||
result.addAll(Arrays.asList(queryStringValues)); |
||||
result.addAll(formValues); |
||||
return result.toArray(new String[result.size()]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
/* |
||||
* Copyright 2002-2011 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
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.mock.web; |
||||
|
||||
import javax.servlet.FilterChain; |
||||
import javax.servlet.ServletRequest; |
||||
import javax.servlet.ServletResponse; |
||||
|
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* Mock implementation of the {@link javax.servlet.FilterConfig} interface. |
||||
* |
||||
* <p>Used for testing the web framework; also useful for testing |
||||
* custom {@link javax.servlet.Filter} implementations. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 2.0.3 |
||||
* @see MockFilterConfig |
||||
* @see PassThroughFilterChain |
||||
*/ |
||||
public class MockFilterChain implements FilterChain { |
||||
|
||||
private ServletRequest request; |
||||
|
||||
private ServletResponse response; |
||||
|
||||
|
||||
/** |
||||
* Records the request and response. |
||||
*/ |
||||
public void doFilter(ServletRequest request, ServletResponse response) { |
||||
Assert.notNull(request, "Request must not be null"); |
||||
Assert.notNull(response, "Response must not be null"); |
||||
if (this.request != null) { |
||||
throw new IllegalStateException("This FilterChain has already been called!"); |
||||
} |
||||
this.request = request; |
||||
this.response = response; |
||||
} |
||||
|
||||
/** |
||||
* Return the request that {@link #doFilter} has been called with. |
||||
*/ |
||||
public ServletRequest getRequest() { |
||||
return this.request; |
||||
} |
||||
|
||||
/** |
||||
* Return the response that {@link #doFilter} has been called with. |
||||
*/ |
||||
public ServletResponse getResponse() { |
||||
return this.response; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,178 @@
@@ -0,0 +1,178 @@
|
||||
/* |
||||
* Copyright 2002-2011 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
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.web.filter; |
||||
|
||||
import static org.junit.Assert.assertArrayEquals; |
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertNull; |
||||
import static org.junit.Assert.assertSame; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.mock.web.MockFilterChain; |
||||
import org.springframework.mock.web.MockHttpServletRequest; |
||||
import org.springframework.mock.web.MockHttpServletResponse; |
||||
|
||||
/** |
||||
* Test fixture for {@link HttpPutFormContentFilter}. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
*/ |
||||
public class HttpPutFormContentFilterTests { |
||||
|
||||
private HttpPutFormContentFilter filter; |
||||
|
||||
private MockHttpServletRequest request; |
||||
|
||||
private MockHttpServletResponse response; |
||||
|
||||
private MockFilterChain filterChain; |
||||
|
||||
@Before |
||||
public void setup() { |
||||
filter = new HttpPutFormContentFilter(); |
||||
request = new MockHttpServletRequest("PUT", "/"); |
||||
request.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=ISO-8859-1"); |
||||
request.setContentType("application/x-www-form-urlencoded"); |
||||
response = new MockHttpServletResponse(); |
||||
filterChain = new MockFilterChain(); |
||||
} |
||||
|
||||
@Test |
||||
public void wrapPutOnly() throws Exception { |
||||
request.setContent("".getBytes("ISO-8859-1")); |
||||
String[] methods = new String[] {"GET", "POST", "DELETE", "HEAD", "OPTIONS", "TRACE"}; |
||||
for (String method : methods) { |
||||
request.setMethod(method); |
||||
filterChain = new MockFilterChain(); |
||||
filter.doFilter(request, response, filterChain); |
||||
assertSame("Should not wrap for HTTP method " + method, request, filterChain.getRequest()); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void wrapFormEncodedOnly() throws Exception { |
||||
request.setContent("".getBytes("ISO-8859-1")); |
||||
String[] contentTypes = new String[] {"text/plain", "multipart/form-data"}; |
||||
for (String contentType : contentTypes) { |
||||
request.setContentType(contentType); |
||||
filterChain = new MockFilterChain(); |
||||
filter.doFilter(request, response, filterChain); |
||||
assertSame("Should not wrap for content type " + contentType, request, filterChain.getRequest()); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void getParameter() throws Exception { |
||||
request.setContent("name=value".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
assertEquals("value", filterChain.getRequest().getParameter("name")); |
||||
} |
||||
|
||||
@Test |
||||
public void queryStringParam() throws Exception { |
||||
request.addParameter("name", "value1"); |
||||
request.setContent("name=value2".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
assertEquals("Query string parameters should be listed ahead of form parameters", |
||||
"value1", filterChain.getRequest().getParameter("name")); |
||||
} |
||||
|
||||
@Test |
||||
public void nullParameter() throws Exception { |
||||
request.setContent("name=value".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
assertNull(filterChain.getRequest().getParameter("noSuchParam")); |
||||
} |
||||
|
||||
@Test |
||||
public void getParameterNames() throws Exception { |
||||
request.addParameter("name1", "value1"); |
||||
request.addParameter("name2", "value2"); |
||||
request.setContent("name1=value1&name3=value3&name4=value4".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
List<String> names = Collections.list(filterChain.getRequest().getParameterNames()); |
||||
assertEquals(Arrays.asList("name1", "name2", "name3", "name4"), names); |
||||
} |
||||
|
||||
@Test |
||||
public void getParameterValues() throws Exception { |
||||
request.addParameter("name", "value1"); |
||||
request.addParameter("name", "value2"); |
||||
request.setContent("name=value3&name=value4".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
String[] values = filterChain.getRequest().getParameterValues("name"); |
||||
assertArrayEquals(new String[]{"value1", "value2", "value3", "value4"}, values); |
||||
} |
||||
|
||||
@Test |
||||
public void getQueryStringParameterValuesOnly() throws Exception { |
||||
request.addParameter("name", "value1"); |
||||
request.addParameter("name", "value2"); |
||||
request.setContent("anotherName=anotherValue".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
String[] values = filterChain.getRequest().getParameterValues("name"); |
||||
assertArrayEquals(new String[]{"value1", "value2"}, values); |
||||
} |
||||
|
||||
@Test |
||||
public void getFormParameterValuesOnly() throws Exception { |
||||
request.addParameter("name", "value1"); |
||||
request.addParameter("name", "value2"); |
||||
request.setContent("anotherName=anotherValue".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
String[] values = filterChain.getRequest().getParameterValues("anotherName"); |
||||
assertArrayEquals(new String[]{"anotherValue"}, values); |
||||
} |
||||
|
||||
@Test |
||||
public void noParameterValuesOnly() throws Exception { |
||||
request.addParameter("name", "value1"); |
||||
request.addParameter("name", "value2"); |
||||
request.setContent("anotherName=anotherValue".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
String[] values = filterChain.getRequest().getParameterValues("noSuchParameter"); |
||||
assertNull(values); |
||||
} |
||||
|
||||
@Test |
||||
public void getParameterMap() throws Exception { |
||||
request.addParameter("name", "value1"); |
||||
request.addParameter("name", "value2"); |
||||
request.setContent("name=value3&name4=value4".getBytes("ISO-8859-1")); |
||||
filter.doFilter(request, response, filterChain); |
||||
|
||||
Map<String, String[]> parameters = filterChain.getRequest().getParameterMap(); |
||||
assertEquals(2, parameters.size()); |
||||
assertArrayEquals(new String[] {"value1", "value2", "value3"}, parameters.get("name")); |
||||
assertArrayEquals(new String[] {"value4"}, parameters.get("name4")); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue