简体   繁体   中英

Undertow throws RuntimeException when uploading multipart file exceeding the setting value

I'm running the complete version of Spring boot Upload file guide at Spring Guide , but I used Undertow as embedded servlet instead of Tomcat default. And it worked.

When I try to upload file with size larger than the value in config file

spring.http.multipart.max-file-size=128KB
spring.http.multipart.max-request-size=128KB

It raises exception. That is expected behavior

With Tomcat embedded servlet, it can be easily handled by catching SizeLimitExceededException or MultipartException

But with Undertow, it throws RuntimeException event I catch it in global handler:

@ControllerAdvice
public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler {
    @ExceptionHandler({RuntimeException.class, Exception.class, IOException.class})
    ResponseEntity<?> handleControllerException(Exception exc, HttpServletRequest request, Throwable ex) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }
}

The Exception message:

java.lang.RuntimeException: java.io.IOException: UT000020: Connection terminated as request was larger than 131072
    at io.undertow.servlet.spec.HttpServletRequestImpl.parseFormData(HttpServletRequestImpl.java:779) ~[undertow-servlet-1.4.20.Final.jar:1.4.20.Final]
    at io.undertow.servlet.spec.HttpServletRequestImpl.getParameter(HttpServletRequestImpl.java:653) ~[undertow-servlet-1.4.20.Final.jar:1.4.20.Final]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:75) ~[spring-web-4.3.12.RELEASE.jar:4.3.12.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.12.RELEASE.jar:4.3.12.RELEASE]

Here is the codes:

The controller

@PostMapping("/")
public String handleFileUpload(@RequestParam("file") MultipartFile file,
        RedirectAttributes redirectAttributes) {

    storageService.store(file);
    redirectAttributes.addFlashAttribute("message",
            "You successfully uploaded " + file.getOriginalFilename() + "!");

    return "redirect:/";
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.springframework</groupId>
    <artifactId>gs-uploading-files</artifactId>
    <version>0.1.0</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.8.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <version>1.3.0.RELEASE</version>
        </dependency>
    </dependencies>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Anyone get the same problem with me? How can I catch the exception when maximum file size upload is exceeded?

Any help would be greatly appreciated

Maybe it is able to help in some particular case.

I have the same problem with undertow and exception handling.

My case is a little bit different, I also have spring-security, so the exceptions like RequestTooBigException are caused in spring-security filters when some of them try to read information from the request.

As a solution, I use an additional filter that is added before the first security filter that is caused that exception. (For my it is BearerTokenAuthenticationFilter.class )

There is an additional filter that handles these exceptions:

 @Component
 @Slf4j
 public class SecurityRequestToBigExceptionHandlerFilter extends OncePerRequestFilter {

   @Override
   public void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
       FilterChain filterChain) throws ServletException, IOException {
     try {
       filterChain.doFilter(request, response);
     } catch (IllegalStateException | RequestTooBigException | MultiPartParserDefinition.FileTooLargeException ex) {

       if (ex instanceof RequestTooBigException
           || ex instanceof MultiPartParserDefinition.FileTooLargeException) {
         writeResponse(response, ex);
         return;
       }

       Throwable causeException = ex.getCause();
       if (nonNull(causeException)
           && (causeException instanceof RequestTooBigException
           || causeException instanceof MultiPartParserDefinition.FileTooLargeException)) {
         writeResponse(response, causeException);
         return;
       }

       throw ex;
     }
   }

   private void writeResponse(HttpServletResponse response, Throwable ex) throws IOException {
     log.debug("Handle RequestToBig Exception with {}", ex.getMessage());
     response.setStatus(HttpStatus.BAD_REQUEST.value());
     response.getWriter().write(ex.getMessage());
  }
 }

Next what we need to change is security configuration.

There is my simplified security config:

 @EnableWebSecurity
 @RequiredArgsConstructor
 public class SecurityConfig extends WebSecurityConfigurerAdapter {

   @Autowired
   private final SecurityRequestToBigExceptionHandlerFilter requestToBigExceptionHandlerFilter;

   @Override
   public void configure(HttpSecurity http) throws Exception {
     http 
         .addFilterBefore(requestToBigExceptionHandlerFilter, BearerTokenAuthenticationFilter.class)
         .csrf().disable()
         .cors()
         .and()
         .authorizeRequests()
         .anyRequest().authenticated()
         .and()
         .oauth2ResourceServer().jwt();
   }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM