/*
 * 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.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
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.HttpMethod;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;

Filter that converts posted method parameters into HTTP methods, retrievable via HttpServletRequest.getMethod(). Since browsers currently only support GET and POST, a common technique - used by the Prototype library, for instance - is to use a normal POST with an additional hidden form field (_method) to pass the "real" HTTP method along. This filter reads that parameter and changes the HttpServletRequestWrapper.getMethod() return value accordingly. Only "PUT", "DELETE" and "PATCH" HTTP methods are allowed.

The name of the request parameter defaults to _method, but can be adapted via the methodParam property.

NOTE: This filter needs to run after multipart processing in case of a multipart POST request, due to its inherent need for checking a POST body parameter. So typically, put a Spring MultipartFilter before this HiddenHttpMethodFilter in your web.xml filter chain.

Author:Arjen Poutsma, Juergen Hoeller
Since:3.0
/** * {@link javax.servlet.Filter} that converts posted method parameters into HTTP methods, * retrievable via {@link HttpServletRequest#getMethod()}. Since browsers currently only * support GET and POST, a common technique - used by the Prototype library, for instance - * is to use a normal POST with an additional hidden form field ({@code _method}) * to pass the "real" HTTP method along. This filter reads that parameter and changes * the {@link HttpServletRequestWrapper#getMethod()} return value accordingly. * Only {@code "PUT"}, {@code "DELETE"} and {@code "PATCH"} HTTP methods are allowed. * * <p>The name of the request parameter defaults to {@code _method}, but can be * adapted via the {@link #setMethodParam(String) methodParam} property. * * <p><b>NOTE: This filter needs to run after multipart processing in case of a multipart * POST request, due to its inherent need for checking a POST body parameter.</b> * So typically, put a Spring {@link org.springframework.web.multipart.support.MultipartFilter} * <i>before</i> this HiddenHttpMethodFilter in your {@code web.xml} filter chain. * * @author Arjen Poutsma * @author Juergen Hoeller * @since 3.0 */
public class HiddenHttpMethodFilter extends OncePerRequestFilter { private static final List<String> ALLOWED_METHODS = Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(), HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
Default method parameter: _method.
/** Default method parameter: {@code _method}. */
public static final String DEFAULT_METHOD_PARAM = "_method"; private String methodParam = DEFAULT_METHOD_PARAM;
Set the parameter name to look for HTTP methods.
See Also:
  • DEFAULT_METHOD_PARAM
/** * Set the parameter name to look for HTTP methods. * @see #DEFAULT_METHOD_PARAM */
public void setMethodParam(String methodParam) { Assert.hasText(methodParam, "'methodParam' must not be empty"); this.methodParam = methodParam; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) { String paramValue = request.getParameter(this.methodParam); if (StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH); if (ALLOWED_METHODS.contains(method)) { requestToUse = new HttpMethodRequestWrapper(request, method); } } } filterChain.doFilter(requestToUse, response); }
Simple HttpServletRequest wrapper that returns the supplied method for HttpServletRequest.getMethod().
/** * Simple {@link HttpServletRequest} wrapper that returns the supplied method for * {@link HttpServletRequest#getMethod()}. */
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper { private final String method; public HttpMethodRequestWrapper(HttpServletRequest request, String method) { super(request); this.method = method; } @Override public String getMethod() { return this.method; } } }