001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.multipart.support; 018 019import java.io.IOException; 020import javax.servlet.FilterChain; 021import javax.servlet.ServletException; 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.HttpServletResponse; 024 025import org.springframework.web.context.WebApplicationContext; 026import org.springframework.web.context.support.WebApplicationContextUtils; 027import org.springframework.web.filter.OncePerRequestFilter; 028import org.springframework.web.multipart.MultipartHttpServletRequest; 029import org.springframework.web.multipart.MultipartResolver; 030 031/** 032 * Servlet Filter that resolves multipart requests via a {@link MultipartResolver}. 033 * in the root web application context. 034 * 035 * <p>Looks up the MultipartResolver in Spring's root web application context. 036 * Supports a "multipartResolverBeanName" filter init-param in {@code web.xml}; 037 * the default bean name is "filterMultipartResolver". 038 * 039 * <p>If no MultipartResolver bean is found, this filter falls back to a default 040 * MultipartResolver: {@link StandardServletMultipartResolver} for Servlet 3.0, 041 * based on a multipart-config section in {@code web.xml}. 042 * Note however that at present the Servlet specification only defines how to 043 * enable multipart configuration on a Servlet and as a result multipart request 044 * processing is likely not possible in a Filter unless the Servlet container 045 * provides a workaround such as Tomcat's "allowCasualMultipartParsing" property. 046 * 047 * <p>MultipartResolver lookup is customizable: Override this filter's 048 * {@code lookupMultipartResolver} method to use a custom MultipartResolver 049 * instance, for example if not using a Spring web application context. 050 * Note that the lookup method should not create a new MultipartResolver instance 051 * for each call but rather return a reference to a pre-built instance. 052 * 053 * <p>Note: This filter is an <b>alternative</b> to using DispatcherServlet's 054 * MultipartResolver support, for example for web applications with custom web views 055 * which do not use Spring's web MVC, or for custom filters applied before a Spring MVC 056 * DispatcherServlet (e.g. {@link org.springframework.web.filter.HiddenHttpMethodFilter}). 057 * In any case, this filter should not be combined with servlet-specific multipart resolution. 058 * 059 * @author Juergen Hoeller 060 * @since 08.10.2003 061 * @see #setMultipartResolverBeanName 062 * @see #lookupMultipartResolver 063 * @see org.springframework.web.multipart.MultipartResolver 064 * @see org.springframework.web.servlet.DispatcherServlet 065 */ 066public class MultipartFilter extends OncePerRequestFilter { 067 068 public static final String DEFAULT_MULTIPART_RESOLVER_BEAN_NAME = "filterMultipartResolver"; 069 070 private final MultipartResolver defaultMultipartResolver = new StandardServletMultipartResolver(); 071 072 private String multipartResolverBeanName = DEFAULT_MULTIPART_RESOLVER_BEAN_NAME; 073 074 075 /** 076 * Set the bean name of the MultipartResolver to fetch from Spring's 077 * root application context. Default is "filterMultipartResolver". 078 */ 079 public void setMultipartResolverBeanName(String multipartResolverBeanName) { 080 this.multipartResolverBeanName = multipartResolverBeanName; 081 } 082 083 /** 084 * Return the bean name of the MultipartResolver to fetch from Spring's 085 * root application context. 086 */ 087 protected String getMultipartResolverBeanName() { 088 return this.multipartResolverBeanName; 089 } 090 091 092 /** 093 * Check for a multipart request via this filter's MultipartResolver, 094 * and wrap the original request with a MultipartHttpServletRequest if appropriate. 095 * <p>All later elements in the filter chain, most importantly servlets, benefit 096 * from proper parameter extraction in the multipart case, and are able to cast to 097 * MultipartHttpServletRequest if they need to. 098 */ 099 @Override 100 protected void doFilterInternal( 101 HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 102 throws ServletException, IOException { 103 104 MultipartResolver multipartResolver = lookupMultipartResolver(request); 105 106 HttpServletRequest processedRequest = request; 107 if (multipartResolver.isMultipart(processedRequest)) { 108 if (logger.isDebugEnabled()) { 109 logger.debug("Resolving multipart request [" + processedRequest.getRequestURI() + 110 "] with MultipartFilter"); 111 } 112 processedRequest = multipartResolver.resolveMultipart(processedRequest); 113 } 114 else { 115 // A regular request... 116 if (logger.isDebugEnabled()) { 117 logger.debug("Request [" + processedRequest.getRequestURI() + "] is not a multipart request"); 118 } 119 } 120 121 try { 122 filterChain.doFilter(processedRequest, response); 123 } 124 finally { 125 if (processedRequest instanceof MultipartHttpServletRequest) { 126 multipartResolver.cleanupMultipart((MultipartHttpServletRequest) processedRequest); 127 } 128 } 129 } 130 131 /** 132 * Look up the MultipartResolver that this filter should use, 133 * taking the current HTTP request as argument. 134 * <p>The default implementation delegates to the {@code lookupMultipartResolver} 135 * without arguments. 136 * @return the MultipartResolver to use 137 * @see #lookupMultipartResolver() 138 */ 139 protected MultipartResolver lookupMultipartResolver(HttpServletRequest request) { 140 return lookupMultipartResolver(); 141 } 142 143 /** 144 * Look for a MultipartResolver bean in the root web application context. 145 * Supports a "multipartResolverBeanName" filter init param; the default 146 * bean name is "filterMultipartResolver". 147 * <p>This can be overridden to use a custom MultipartResolver instance, 148 * for example if not using a Spring web application context. 149 * @return the MultipartResolver instance, or {@code null} if none found 150 */ 151 protected MultipartResolver lookupMultipartResolver() { 152 WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); 153 String beanName = getMultipartResolverBeanName(); 154 if (wac != null && wac.containsBean(beanName)) { 155 if (logger.isDebugEnabled()) { 156 logger.debug("Using MultipartResolver '" + beanName + "' for MultipartFilter"); 157 } 158 return wac.getBean(beanName, MultipartResolver.class); 159 } 160 else { 161 return this.defaultMultipartResolver; 162 } 163 } 164 165}