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