Undertow throws RuntimeException when uploading multipart file exceeding the setting value

只谈情不闲聊 提交于 2020-07-21 06:33:11

问题


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


回答1:


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();
   }
 }


来源:https://stackoverflow.com/questions/46968098/undertow-throws-runtimeexception-when-uploading-multipart-file-exceeding-the-set

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!