Browse Source

Support for Servlet request params with HTTP DELETE

This commit adds FormContentFilter, which is the same as the
HttpPutFormContentFilter but also supports DELETE.

The HttpPutFormContentFilter is now deprecated.

Issue: SPR-16874
pull/1858/head
Rossen Stoyanchev 7 years ago
parent
commit
124d4c833c
  1. 8
      spring-test/src/test/java/org/springframework/test/web/servlet/samples/spr/FormContentTests.java
  2. 188
      spring-web/src/main/java/org/springframework/web/filter/FormContentFilter.java
  3. 5
      spring-web/src/main/java/org/springframework/web/filter/HttpPutFormContentFilter.java
  4. 218
      spring-web/src/test/java/org/springframework/web/filter/FormContentFilterTests.java
  5. 218
      spring-web/src/test/java/org/springframework/web/filter/HttpPutFormContentFilterTests.java
  6. 8
      src/docs/asciidoc/web/webmvc.adoc

8
spring-test/src/test/java/org/springframework/test/web/servlet/samples/spr/FormContentTests.java

@ -23,10 +23,10 @@ import org.springframework.test.web.servlet.MockMvc; @@ -23,10 +23,10 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.filter.HttpPutFormContentFilter;
import org.springframework.web.filter.FormContentFilter;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* Test for issues related to form content.
@ -39,7 +39,7 @@ public class FormContentTests { @@ -39,7 +39,7 @@ public class FormContentTests {
public void formContentIsNotDuplicated() throws Exception {
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new Spr15753Controller())
.addFilter(new HttpPutFormContentFilter())
.addFilter(new FormContentFilter())
.build();
mockMvc.perform(put("/").content("d1=a&d2=s").contentType(MediaType.APPLICATION_FORM_URLENCODED))

188
spring-web/src/main/java/org/springframework/web/filter/FormContentFilter.java

@ -0,0 +1,188 @@ @@ -0,0 +1,188 @@
/*
* Copyright 2002-2018 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.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
/**
* {@code Filter} that parses form data for HTTP PUT, PATCH, and DELETE requests
* and exposes it as Servlet request parameters. By default the Servlet spec
* only requires this for HTTP POST.
*
* @author Rossen Stoyanchev
* @since 5.1
*/
public class FormContentFilter extends OncePerRequestFilter {
private static final List<String> HTTP_METHODS = Arrays.asList("PUT", "PATCH", "DELETE");
private FormHttpMessageConverter formConverter = new AllEncompassingFormHttpMessageConverter();
/**
* Set the converter to use for parsing form content.
* <p>By default this is an instance of {@link AllEncompassingFormHttpMessageConverter}.
*/
public void setFormConverter(FormHttpMessageConverter converter) {
Assert.notNull(converter, "FormHttpMessageConverter is required.");
this.formConverter = converter;
}
public FormHttpMessageConverter getFormConverter() {
return this.formConverter;
}
/**
* The default character set to use for reading form data.
* This is a shortcut for:<br>
* {@code getFormConverter.setCharset(charset)}.
*/
public void setCharset(Charset charset) {
this.formConverter.setCharset(charset);
}
@Override
protected void doFilterInternal(final HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
MultiValueMap<String, String> params = parseIfNecessary(request);
if (params != null && !params.isEmpty()) {
filterChain.doFilter(new FormContentRequestWrapper(request, params), response);
}
else {
filterChain.doFilter(request, response);
}
}
@Nullable
private MultiValueMap<String, String> parseIfNecessary(HttpServletRequest request) throws IOException {
if (!shouldParse(request)) {
return null;
}
HttpInputMessage inputMessage = new ServletServerHttpRequest(request) {
@Override
public InputStream getBody() throws IOException {
return request.getInputStream();
}
};
return this.formConverter.read(null, inputMessage);
}
private boolean shouldParse(HttpServletRequest request) {
if (!HTTP_METHODS.contains(request.getMethod())) {
return false;
}
try {
MediaType mediaType = MediaType.parseMediaType(request.getContentType());
return MediaType.APPLICATION_FORM_URLENCODED.includes(mediaType);
}
catch (IllegalArgumentException ex) {
return false;
}
}
private static class FormContentRequestWrapper extends HttpServletRequestWrapper {
private MultiValueMap<String, String> formParams;
public FormContentRequestWrapper(HttpServletRequest request, MultiValueMap<String, String> params) {
super(request);
this.formParams = params;
}
@Override
@Nullable
public String getParameter(String name) {
String queryStringValue = super.getParameter(name);
String formValue = this.formParams.getFirst(name);
return (queryStringValue != null ? queryStringValue : formValue);
}
@Override
public Map<String, String[]> getParameterMap() {
Map<String, String[]> result = new LinkedHashMap<>();
Enumeration<String> names = getParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
result.put(name, getParameterValues(name));
}
return result;
}
@Override
public Enumeration<String> getParameterNames() {
Set<String> names = new LinkedHashSet<>();
names.addAll(Collections.list(super.getParameterNames()));
names.addAll(this.formParams.keySet());
return Collections.enumeration(names);
}
@Override
@Nullable
public String[] getParameterValues(String name) {
String[] parameterValues = super.getParameterValues(name);
List<String> formParam = this.formParams.get(name);
if (formParam == null) {
return parameterValues;
}
if (parameterValues == null || getQueryString() == null) {
return StringUtils.toStringArray(formParam);
}
else {
List<String> result = new ArrayList<>(parameterValues.length + formParam.size());
result.addAll(Arrays.asList(parameterValues));
result.addAll(formParam);
return StringUtils.toStringArray(result);
}
}
}
}

5
spring-web/src/main/java/org/springframework/web/filter/HttpPutFormContentFilter.java

@ -58,7 +58,10 @@ import org.springframework.util.StringUtils; @@ -58,7 +58,10 @@ import org.springframework.util.StringUtils;
*
* @author Rossen Stoyanchev
* @since 3.1
* @deprecated as of 5.1 in favor of {@link FormContentFilter} which is the same
* but also handles DELETE.
*/
@Deprecated
public class HttpPutFormContentFilter extends OncePerRequestFilter {
private FormHttpMessageConverter formConverter = new AllEncompassingFormHttpMessageConverter();
@ -66,7 +69,7 @@ public class HttpPutFormContentFilter extends OncePerRequestFilter { @@ -66,7 +69,7 @@ public class HttpPutFormContentFilter extends OncePerRequestFilter {
/**
* Set the converter to use for parsing form content.
* <p>By default this is an instnace of {@link AllEncompassingFormHttpMessageConverter}.
* <p>By default this is an instance of {@link AllEncompassingFormHttpMessageConverter}.
*/
public void setFormConverter(FormHttpMessageConverter converter) {
Assert.notNull(converter, "FormHttpMessageConverter is required.");

218
spring-web/src/test/java/org/springframework/web/filter/FormContentFilterTests.java

@ -0,0 +1,218 @@ @@ -0,0 +1,218 @@
/*
* Copyright 2002-2018 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.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.http.HttpMethod;
import org.springframework.mock.web.test.MockFilterChain;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import static org.junit.Assert.*;
/**
* Test fixture for {@link FormContentFilter}.
*
* @author Rossen Stoyanchev
*/
public class FormContentFilterTests {
private final FormContentFilter filter = new FormContentFilter();
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MockFilterChain filterChain;
@Before
public void setup() {
this.request = new MockHttpServletRequest("PUT", "/");
this.request.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=ISO-8859-1");
this.request.setContentType("application/x-www-form-urlencoded; charset=ISO-8859-1");
this.response = new MockHttpServletResponse();
this.filterChain = new MockFilterChain();
}
@Test
public void wrapPutPatchAndDeleteOnly() throws Exception {
this.request.setContent("foo=bar".getBytes("ISO-8859-1"));
for (HttpMethod method : HttpMethod.values()) {
this.request.setMethod(method.name());
this.filterChain = new MockFilterChain();
this.filter.doFilter(this.request, this.response, this.filterChain);
if (method == HttpMethod.PUT || method == HttpMethod.PATCH || method == HttpMethod.DELETE) {
assertNotSame(this.request, this.filterChain.getRequest());
}
else {
assertSame(this.request, this.filterChain.getRequest());
}
}
}
@Test
public void wrapFormEncodedOnly() throws Exception {
this.request.setContent("".getBytes("ISO-8859-1"));
String[] contentTypes = new String[] {"text/plain", "multipart/form-data"};
for (String contentType : contentTypes) {
this.request.setContentType(contentType);
this.filterChain = new MockFilterChain();
this.filter.doFilter(this.request, this.response, this.filterChain);
assertSame(this.request, this.filterChain.getRequest());
}
}
@Test
public void invalidMediaType() throws Exception {
this.request.setContent("".getBytes("ISO-8859-1"));
this.request.setContentType("foo");
this.filterChain = new MockFilterChain();
this.filter.doFilter(this.request, this.response, this.filterChain);
assertSame(this.request, this.filterChain.getRequest());
}
@Test
public void getParameter() throws Exception {
this.request.setContent("name=value".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
assertEquals("value", this.filterChain.getRequest().getParameter("name"));
}
@Test
public void getParameterFromQueryString() throws Exception {
this.request.addParameter("name", "value1");
this.request.setContent("name=value2".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
assertNotSame("Request not wrapped", this.request, this.filterChain.getRequest());
assertEquals("Query string parameters should be listed ahead of form parameters",
"value1", this.filterChain.getRequest().getParameter("name"));
}
@Test
public void getParameterNullValue() throws Exception {
this.request.setContent("name=value".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
assertNotSame("Request not wrapped", this.request, this.filterChain.getRequest());
assertNull(this.filterChain.getRequest().getParameter("noSuchParam"));
}
@Test
public void getParameterNames() throws Exception {
this.request.addParameter("name1", "value1");
this.request.addParameter("name2", "value2");
this.request.setContent("name1=value1&name3=value3&name4=value4".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
List<String> names = Collections.list(this.filterChain.getRequest().getParameterNames());
assertNotSame("Request not wrapped", this.request, this.filterChain.getRequest());
assertEquals(Arrays.asList("name1", "name2", "name3", "name4"), names);
}
@Test
public void getParameterValues() throws Exception {
this.request.setQueryString("name=value1&name=value2");
this.request.addParameter("name", "value1");
this.request.addParameter("name", "value2");
this.request.setContent("name=value3&name=value4".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
String[] values = this.filterChain.getRequest().getParameterValues("name");
assertNotSame("Request not wrapped", this.request, filterChain.getRequest());
assertArrayEquals(new String[]{"value1", "value2", "value3", "value4"}, values);
}
@Test
public void getParameterValuesFromQueryString() throws Exception {
this.request.setQueryString("name=value1&name=value2");
this.request.addParameter("name", "value1");
this.request.addParameter("name", "value2");
this.request.setContent("anotherName=anotherValue".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
String[] values = this.filterChain.getRequest().getParameterValues("name");
assertNotSame("Request not wrapped", this.request, this.filterChain.getRequest());
assertArrayEquals(new String[]{"value1", "value2"}, values);
}
@Test
public void getParameterValuesFromFormContent() throws Exception {
this.request.addParameter("name", "value1");
this.request.addParameter("name", "value2");
this.request.setContent("anotherName=anotherValue".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
String[] values = this.filterChain.getRequest().getParameterValues("anotherName");
assertNotSame("Request not wrapped", this.request, this.filterChain.getRequest());
assertArrayEquals(new String[]{"anotherValue"}, values);
}
@Test
public void getParameterValuesInvalidName() throws Exception {
this.request.addParameter("name", "value1");
this.request.addParameter("name", "value2");
this.request.setContent("anotherName=anotherValue".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
String[] values = this.filterChain.getRequest().getParameterValues("noSuchParameter");
assertNotSame("Request not wrapped", this.request, this.filterChain.getRequest());
assertNull(values);
}
@Test
public void getParameterMap() throws Exception {
this.request.setQueryString("name=value1&name=value2");
this.request.addParameter("name", "value1");
this.request.addParameter("name", "value2");
this.request.setContent("name=value3&name4=value4".getBytes("ISO-8859-1"));
this.filter.doFilter(this.request, this.response, this.filterChain);
Map<String, String[]> parameters = this.filterChain.getRequest().getParameterMap();
assertNotSame("Request not wrapped", this.request, this.filterChain.getRequest());
assertEquals(2, parameters.size());
assertArrayEquals(new String[] {"value1", "value2", "value3"}, parameters.get("name"));
assertArrayEquals(new String[] {"value4"}, parameters.get("name4"));
}
@Test // SPR-15835
public void hiddenHttpMethodFilterFollowedByHttpPutFormContentFilter() throws Exception {
this.request.addParameter("_method", "PUT");
this.request.addParameter("hiddenField", "testHidden");
this.filter.doFilter(this.request, this.response, this.filterChain);
assertArrayEquals(new String[]{"testHidden"},
this.filterChain.getRequest().getParameterValues("hiddenField"));
}
}

218
spring-web/src/test/java/org/springframework/web/filter/HttpPutFormContentFilterTests.java

@ -1,218 +0,0 @@ @@ -1,218 +0,0 @@
/*
* Copyright 2002-2018 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.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.http.HttpMethod;
import org.springframework.mock.web.test.MockFilterChain;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
import static org.junit.Assert.*;
/**
* 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; charset=ISO-8859-1");
response = new MockHttpServletResponse();
filterChain = new MockFilterChain();
}
@Test
public void wrapPutAndPatchOnly() throws Exception {
request.setContent("foo=bar".getBytes("ISO-8859-1"));
for (HttpMethod method : HttpMethod.values()) {
request.setMethod(method.name());
filterChain = new MockFilterChain();
filter.doFilter(request, response, filterChain);
if (method == HttpMethod.PUT || method == HttpMethod.PATCH) {
assertNotSame("Should wrap HTTP method " + method, request, filterChain.getRequest());
}
else {
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 invalidMediaType() throws Exception {
request.setContent("".getBytes("ISO-8859-1"));
request.setContentType("foo");
filterChain = new MockFilterChain();
filter.doFilter(request, response, filterChain);
assertSame(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 getParameterFromQueryString() throws Exception {
request.addParameter("name", "value1");
request.setContent("name=value2".getBytes("ISO-8859-1"));
filter.doFilter(request, response, filterChain);
assertNotSame("Request not wrapped", request, filterChain.getRequest());
assertEquals("Query string parameters should be listed ahead of form parameters",
"value1", filterChain.getRequest().getParameter("name"));
}
@Test
public void getParameterNullValue() throws Exception {
request.setContent("name=value".getBytes("ISO-8859-1"));
filter.doFilter(request, response, filterChain);
assertNotSame("Request not wrapped", request, filterChain.getRequest());
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());
assertNotSame("Request not wrapped", request, filterChain.getRequest());
assertEquals(Arrays.asList("name1", "name2", "name3", "name4"), names);
}
@Test
public void getParameterValues() throws Exception {
request.setQueryString("name=value1&name=value2");
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");
assertNotSame("Request not wrapped", request, filterChain.getRequest());
assertArrayEquals(new String[]{"value1", "value2", "value3", "value4"}, values);
}
@Test
public void getParameterValuesFromQueryString() throws Exception {
request.setQueryString("name=value1&name=value2");
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");
assertNotSame("Request not wrapped", request, filterChain.getRequest());
assertArrayEquals(new String[]{"value1", "value2"}, values);
}
@Test
public void getParameterValuesFromFormContent() 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");
assertNotSame("Request not wrapped", request, filterChain.getRequest());
assertArrayEquals(new String[]{"anotherValue"}, values);
}
@Test
public void getParameterValuesInvalidName() 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");
assertNotSame("Request not wrapped", request, filterChain.getRequest());
assertNull(values);
}
@Test
public void getParameterMap() throws Exception {
request.setQueryString("name=value1&name=value2");
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();
assertNotSame("Request not wrapped", request, filterChain.getRequest());
assertEquals(2, parameters.size());
assertArrayEquals(new String[] {"value1", "value2", "value3"}, parameters.get("name"));
assertArrayEquals(new String[] {"value4"}, parameters.get("name4"));
}
@Test // SPR-15835
public void hiddenHttpMethodFilterFollowedByHttpPutFormContentFilter() throws Exception {
request.addParameter("_method", "PUT");
request.addParameter("hiddenField", "testHidden");
filter.doFilter(request, response, filterChain);
assertArrayEquals(new String[]{"testHidden"}, filterChain.getRequest().getParameterValues("hiddenField"));
}
}

8
src/docs/asciidoc/web/webmvc.adoc

@ -1046,14 +1046,14 @@ The `spring-web` module provides some useful filters. @@ -1046,14 +1046,14 @@ The `spring-web` module provides some useful filters.
[[filters-http-put]]
=== HTTP PUT Form
=== Form Data
Browsers can only submit form data via HTTP GET or HTTP POST but non-browser clients can also
use HTTP PUT and PATCH. The Servlet API requires `ServletRequest.getParameter{asterisk}()`
use HTTP PUT, PATCH, and DELETE. The Servlet API requires `ServletRequest.getParameter{asterisk}()`
methods to support form field access only for HTTP POST.
The `spring-web` module provides `HttpPutFormContentFilter` that intercepts HTTP PUT and
PATCH requests with content type `application/x-www-form-urlencoded`, reads the form data from
The `spring-web` module provides `FormContentFilter` that intercepts HTTP PUT, PATCH, and DELETE
requests with 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 through the `ServletRequest.getParameter{asterisk}()` family of methods.

Loading…
Cancel
Save