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}