diff --git a/spring-web/src/main/java/org/springframework/web/util/ContentCachingRequestWrapper.java b/spring-web/src/main/java/org/springframework/web/util/ContentCachingRequestWrapper.java index 888341c1c8c..27a1c441a9c 100644 --- a/spring-web/src/main/java/org/springframework/web/util/ContentCachingRequestWrapper.java +++ b/spring-web/src/main/java/org/springframework/web/util/ContentCachingRequestWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -20,6 +20,14 @@ import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; @@ -36,6 +44,10 @@ import javax.servlet.http.HttpServletRequestWrapper; */ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper { + private static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded"; + + private static final String METHOD_POST = "POST"; + private final ByteArrayOutputStream cachedContent; private ServletInputStream inputStream; @@ -80,9 +92,46 @@ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper { * Return the cached request content as a byte array. */ public byte[] getContentAsByteArray() { + if(this.cachedContent.size() == 0 && isFormPost()) { + writeRequestParamsToContent(); + } return this.cachedContent.toByteArray(); } + private boolean isFormPost() { + return (getContentType() != null && getContentType().contains(FORM_CONTENT_TYPE) && + METHOD_POST.equalsIgnoreCase(getMethod())); + } + + private void writeRequestParamsToContent() { + try { + if (this.cachedContent.size() == 0) { + String requestEncoding = getCharacterEncoding(); + Map form = getParameterMap(); + for (Iterator nameIterator = form.keySet().iterator(); nameIterator.hasNext(); ) { + String name = nameIterator.next(); + List values = Arrays.asList(form.get(name)); + for (Iterator valueIterator = values.iterator(); valueIterator.hasNext(); ) { + String value = valueIterator.next(); + cachedContent.write(URLEncoder.encode(name, requestEncoding).getBytes()); + if (value != null) { + cachedContent.write('='); + cachedContent.write(URLEncoder.encode(value, requestEncoding).getBytes()); + if (valueIterator.hasNext()) { + cachedContent.write('&'); + } + } + } + if (nameIterator.hasNext()) { + cachedContent.write('&'); + } + } + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + } private class ContentCachingInputStream extends ServletInputStream { diff --git a/spring-web/src/test/java/org/springframework/web/util/ContentCachingRequestWrapperTests.java b/spring-web/src/test/java/org/springframework/web/util/ContentCachingRequestWrapperTests.java new file mode 100644 index 00000000000..45e383efbdd --- /dev/null +++ b/spring-web/src/test/java/org/springframework/web/util/ContentCachingRequestWrapperTests.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2015 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.util; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.mock.web.test.MockHttpServletRequest; +import org.springframework.util.FileCopyUtils; + +/** + * @author Brian Clozel + */ +public class ContentCachingRequestWrapperTests { + + protected static final String FORM_CONTENT_TYPE = "application/x-www-form-urlencoded"; + + protected static final String CHARSET = "UTF-8"; + + private MockHttpServletRequest request; + + @Before + public void setup() throws Exception { + this.request = new MockHttpServletRequest(); + } + + @Test + public void cachedContent() throws Exception { + this.request.setMethod("GET"); + this.request.setCharacterEncoding(CHARSET); + this.request.setContent("Hello World".getBytes(CHARSET)); + + ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper(this.request); + byte[] response = FileCopyUtils.copyToByteArray(wrapper.getInputStream()); + Assert.assertArrayEquals(response, wrapper.getContentAsByteArray()); + } + + @Test + public void requestParams() throws Exception { + this.request.setMethod("POST"); + this.request.setContentType(FORM_CONTENT_TYPE); + this.request.setCharacterEncoding(CHARSET); + this.request.setParameter("first", "value"); + this.request.setParameter("second", new String[] {"foo", "bar"}); + + ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper(this.request); + // getting request parameters will consume the request body + Assert.assertFalse(wrapper.getParameterMap().isEmpty()); + Assert.assertEquals("first=value&second=foo&second=bar", new String(wrapper.getContentAsByteArray())); + } + +}