Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected EOF read on the socket during file upload with Spring Boot 2.0

I am working on webapp, which is using Spring Boot 2.0 on back-end. For some amount of users I am seeing this kind of error:

Failed to parse multipart servlet request; nested exception is 
java.io.IOException: 
org.apache.tomcat.util.http.fileupload.FileUploadBase
$IOFileUploadException: Processing of multipart/form-data request 
failed. Unexpected EOF read on the socket]
org.springframework.web.multipart.MultipartException: Failed to parse 
multipart servlet request; nested exception is java.io.IOException: 
org.apache.tomcat.util.http.fileupload.FileUploadBase
$IOFileUploadException: Processing of multipart/form-data request 
failed. Unexpected EOF read on the socket at 
org.springframework.web.multipart.support.
StandardMultipartHttpServletRequest.
handleParseFailure(StandardMultipartHttpServletRequest.java:122) at 
org.springframework.web.multipart.support.
StandardMultipartHttpServletRequest.
parseRequest(StandardMultipartHttpServletRequest.java:113) at 
org.springframework.web.multipart.support.
StandardMultipartHttpServletRequest.<init 
(StandardMultipartHttpServletRequest.java:86) at 
org.springframework.web.multipart.support.
StandardServletMultipartResolver.
resolveMultipart(StandardServletMultipartResolver.java:93) at 
org.springframework.web.servlet.DispatcherServlet.
checkMultipart(DispatcherServlet.java:1128) at 
org.springframework.web.servlet.DispatcherServlet.
doDispatch(DispatcherServlet.java:960) at 
org.springframework.web.servlet.DispatcherServlet.
doService(DispatcherServlet.java:925)...

Could you help me to understand the root of this problem. I am using this code on server, which looks fine:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public ResponseEntity<String> upload(HttpSession session, 
MultipartHttpServletRequest request) {

MultipartFile multipartFile = request.getFiles("file");
try (InputStream inputStream = multipartFile.getInputStream()) {
    //logic ...
}

}

As I see from logs, request even don't call server endpoint and fails during sending data from UI side. Looks like some network problem?

Another strange thing is that this kind of error happens like random. Just for ~2-4% jof users requests. Even if user that had problem with upload tries to upload a few more times, often it works fine after that

Thanks for any answers!

like image 649
Andrii Mudrevskyi Avatar asked Jun 12 '18 21:06

Andrii Mudrevskyi


1 Answers

I experince the same problem with a Spring Boot 1.5.14.RELEASE.

I managed to reproduce the problem by using a custom throtlling (20KB/s) mode on Chrome. When I upload a big picture (8MB) I get a timeout after 30 seconds.

Please note that I am doing the upload via ajax using Dropbox.

I investigated a bit and I saw that the Tomcat Connector has a default value for async requests timeout:

/**
 * Default timeout for asynchronous requests (ms).
 */
protected long asyncTimeout = 30000;

I tried to increment this limit using the property that Spring Boot provides:

# SPRING MVC (WebMvcProperties)
spring.mvc.async.request-timeout= # Amount of time before asynchronous request handling times out.

Unfortunately, in my case that did not work. So I tried to configure the timeout programatically:

@Configuration
public class ServerConfiguration {

  @Bean
  public EmbeddedServletContainerFactory servletContainer() {
    TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
    factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {

      @Override
      public void customize(Connector connector) {
        connector.setAsyncTimeout(60000);
        connector.getExecutorName();
      }
    });
    return factory;
  }

}

That did not work, but I'm pretty sure that is the problem. I saw other people that configured the Connector timeout this way and it worked for them...

I still have no idea why in my case the default value is still being used. Try it and tell me how it went please.

Update

I figured out what was happening. It turns out that Dropzone had a timeout itself.

https://www.dropzonejs.com/#config-timeout

I set that to the value I wanted and everything worked fine.

Spring boot was setting the value of the property:

spring.mvc.async.request-timeout= # Amount of time before asynchronous request handling times out.

perfectly.

like image 119
Peter Catalin Avatar answered Sep 21 '22 07:09

Peter Catalin