Search code examples
springspring-bootmultipartform-dataservlet-3.0apache-commons-fileupload

Cannot configure CommonsMultipartResolver with Spring Boot 1.2.8


I am trying to use CommonsMultipartResolver in my Spring Boot application. I cannot use the StandardServletMultipartResolver, as I want to handle exceptions (e.g. exceeding file size).

I have set up a dependency to commons-fileupload. My spring configuration is:

    @Autowired
    private MultipartProperties multipartProperties = new MultipartProperties();

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        return this.multipartProperties.createMultipartConfig();
    }

    @Bean
    public MultipartResolver multipartResolver() {
        LOG.debug("initializing MultipartResolver");
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        return multipartResolver;
    }

    @Bean
    public FilterRegistrationBean multipartFilterRegistrationBean() {
        final MultipartFilter multipartFilter = new MultipartFilter();
        final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(multipartFilter);
        multipartFilter.setMultipartResolverBeanName("multipartResolver");
        filterRegistrationBean.setOrder(OrderedHiddenHttpMethodFilter.DEFAULT_ORDER-1);
        return filterRegistrationBean;
    }

When I set up the MultipartFilter to be executed prior to the HiddenHttpMethodFilter I get an IOException:

Caused by: java.io.IOException: Missing content for multipart request
at org.eclipse.jetty.util.MultiPartInputStreamParser.parse(MultiPartInputStreamParser.java:491)
at org.eclipse.jetty.util.MultiPartInputStreamParser.getParts(MultiPartInputStreamParser.java:400)
at org.eclipse.jetty.server.Request.getParts(Request.java:2139)
at org.eclipse.jetty.server.Request.extractMultipartParameters(Request.java:385)
... 35 common frames omitted

Otherwise, I get an exception that the part parameter is not present in the request.

I believe I need to disable the servlet 3.0 handling of multipart requests, but I cannot figure out how to do it in spring boot.


Solution

  • The issue was caused by DefaultMultipartHttpServletRequest throwing an exception on getParameter which was called by HiddenHttpMethodFilter, because the stream was already processed in MultipartFilter:

    @Override
    protected void doFilterInternal(HttpServletRequest request, >HttpServletResponse response, FilterChain filterChain)
          throws ServletException, IOException {
    
      String paramValue = request.getParameter(this.methodParam);
      if ("POST".equals(request.getMethod()) && >StringUtils.hasLength(paramValue)) {
          String method = paramValue.toUpperCase(Locale.ENGLISH);
          HttpServletRequest wrapper = new >HttpMethodRequestWrapper(request, method);
          filterChain.doFilter(wrapper, response);
      }
      else {
          filterChain.doFilter(request, response);
      }
    }
    

    My solution to this was to disable MultipartAutoConfiguration, not define a MultipartConfigElement bean in order to disable servlet 3.0 multipart parsing and not use the MultipartFiler.

    Now the configuration looks like the following:

    @Autowired
    private MultipartProperties multipartProperties = new MultipartProperties();
    
    @Bean
    public MultipartResolver multipartResolver() {
        LOG.debug("initializing MultipartResolver");
        MultipartConfigElement config = multipartProperties.createMultipartConfig();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setResolveLazily(true);
        multipartResolver.setMaxUploadSize(config.getMaxRequestSize());
        multipartResolver.setMaxUploadSizePerFile(config.getMaxFileSize());
        return multipartResolver;
    }
    

    Now it is even possible to use @ExceptionHandler advice to return the correct HTTP code when a file exceeds the maximum size allowed.