I'm running my application with spring-boot-starter-jetty: 2.1.4 (and tried with 2.1.7). My build.gradle contains:

    // Spring Boot starters
    compile "org.springframework.boot:spring-boot-starter-web:2.1.4.RELEASE"
    compile "org.springframework.boot:spring-boot-starter-jetty:2.1.4.RELEASE"
    compile "org.springframework.boot:spring-boot-devtools:2.1.4.RELEASE"

    configurations {
        compile.exclude module: 'spring-boot-starter-tomcat'
    }

My JettyConfig:

@Configuration
@Profile("default")
public class JettyConfiguration {

    @Value("classpath:jetty-env.xml")
    private Resource jettyEnvResource;

    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        JettyServletWebServerFactory jettyContainer = new JettyServletWebServerFactory();
        jettyContainer.addServerCustomizers(jettyServerCustomizer());
        return jettyContainer;
    }

    private JettyServerCustomizer jettyServerCustomizer() {
        return server -> {
            try {
                WebAppContext webAppContext = (WebAppContext) server.getHandler();
                new XmlConfiguration(new FileInputStream(jettyEnvResource.getFile()))
                        .configure(webAppContext);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        };
    }
}

and jetty-env.xml:

<?xml version="1.0"?>

<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="WebAppContext" class="org.eclipse.jetty.webapp.WebAppContext">
    <Call class="java.lang.System" name="setProperties">
        <Arg>
            <New class="java.util.Properties">
                <Call name="putAll">
                    <Arg>
                        <Call class="java.lang.System" name="getProperties"/>
                    </Arg>
                </Call>
            </New>
        </Arg>
    </Call>
    <New id="DataSource" class="org.eclipse.jetty.plus.jndi.Resource">
        <Arg>jdbc/source</Arg>
        <Arg>
            <New class="oracle.jdbc.pool.OracleDataSource">
                <Set name="DriverType">thin</Set>
                <Set name="URL">@url@</Set>
                <Set name="User">@db_user@</Set>
                <Set name="Password">@db_password@</Set>
                <Set name="connectionCachingEnabled">true</Set>
                <Set name="connectionCacheProperties">
                    <New class="java.util.Properties">
                        <Call name="setProperty">
                            <Arg>MinLimit</Arg>
                            <Arg>5</Arg>
                        </Call>
                    </New>
                </Set>
            </New>
        </Arg>
    </New>
    <New class="org.eclipse.jetty.plus.jndi.EnvEntry">
        <Arg></Arg>
        <Arg>application.encryption.key</Arg>
        <Arg type="java.lang.String">@key@</Arg>
        <Arg type="boolean">true</Arg>
    </New>
</Configure>

My application.yml contains:

spring:
    servlet:
        multipart:
            enabled: true
            max-file-size: 20971520 #20 MB
            max-request-size: 26214400 #25 MB

I'm trying to handle MaxUploadSizeExceededException using ResponseEntityExceptionHandler as follows:

@ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
    @Value("${spring.servlet.multipart.max-file-size}")
    private Long maxAllowedSize;

    @ResponseBody
    @ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE)
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ResponseEntity<String> handleMaxUploadSizeExceededException(final MaxUploadSizeExceededException exception) {
        String message = "Attempt to upload file with the size exceeded max allowed value = " + maxAllowedSize + " byte(s).");

        return ResponseEntity.status(HttpStatus.PAYLOAD_TOO_LARGE).body(message);
    }
}

But Spring's org.springframework.web.multipart.MultipartException is not thrown. Instead I see in logs org.eclipse.jetty.http.BadMessageException: 400: Unable to parse form content with rootCause java.lang.IllegalStateException: Multipart Mime part query exceeds max filesize

Comment From: wilkinsona

Thanks for the report. Unfortunately, we can't afford to investigate a problem when we have to make guesses about how it occurs. Can you please turn the code snippets into a complete and minimal sample that reproduces the problem, zip it up, and attach it to this issue? As far as I can tell, there's no connection between file upload and the use of Oracle so I suspect that the Jetty configuration isn't needed. There's also no endpoint that appears to consume file uploads.

Comment From: zenonwch

Hi @wilkinsona, below you can find the link to the repo with the minimal sample of the problem (with maven instead of gradle but still reproduced): https://github.com/zenonwch/SpringBootStarterJettyMaxUploadSizeIssue

And the link to the working minimal sample with tomcat container: https://github.com/zenonwch/FileSizeErrorHandlingTomcat

Comment From: wilkinsona

Thanks for the sample.

The problem is caused by HiddenHttpMethodFilter. It uses the request's parameters, and therefore triggers parsing of its multipart payload, before the request reaches Spring MVC's dispatcher servlet. The parsing fails due to the upload being too big, but, because the request has not reached Spring MVC, its exception handling and controller advice has no effect. You can avoid the problem by disabling the hidden HTTP method filter:

spring.mvc.hiddenmethod.filter.enabled: false

With this change in place, you'll get the expected response:

 http -f POST :8080/upload file@large.txt
HTTP/1.1 413 Payload Too Large
Content-Length: 79
Content-Type: text/plain;charset=utf-8
Date: Mon, 02 Sep 2019 18:04:43 GMT

Attempt to upload file with the size exceeded max allowed value = 1024 byte(s).

HiddenHttpMethodFilter is disabled by default as of Spring Boot 2.2.0.M5 to avoid this sort of problem.

Comment From: zenonwch

Thanks for the quick response. With the spring.mvc.hiddenmethod.filter.enabled: false works as expected.

Comment From: elouataoui

Sorry to dig this up, but it appears that the same issue happens when using spring-security-oauth2. At one point up the filter chain (and before reaching the DispatcherServlet) the BearerTokenExtractor calls request#getParameter triggering the parsing of the multipart payload. As we can't disable the OAuth2 security filter, I'm not sure where to report this issue. Any pointers would be welcome.

Comment From: philwebb

@elouataoui BearerTokenExtractor is part of https://github.com/spring-projects/spring-security-oauth which is in maintenance mode (see this blog post. I'd suggest migrating to new module that's in Spring Security itself to see if that fixes things.

Comment From: AkhilKandi

@philwebb Hello,

Even I am facing the same issue when trying to upload a file greater than 1MB getting this error.

{
    "timestamp": 1588794695638,
    "status": 500,
    "error": "Internal Server Error",
    "exception": "java.lang.IllegalStateException",
    "message": "java.lang.IllegalStateException: Multipart Mime part file exceeds max filesize",
    "path": "/cogs-core-engine/flatFileUpload"
}

The API worked fine when I tested in my local workspace. When committed to oneops dev environment I am getting this error. I have tried multiple workarounds but none of them is working.

Comment From: philwebb

@AkhilKandi If you're using spring-security-oauth then I'm afraid the answer will be the same as the comment above yours.

Comment From: AkhilKandi

I am not using spring-security-oauth in my application. But I am not sure when the file is more than 1 MB the request is not even reaching till the API endpoint/ Dispatcherservlet.

Comment From: philwebb

@AkhilKandi It's hard to say if that's a bug, a configuration issue or an environmental problem. The fact that it works locally but not when pushed to "oneops dev environment" (I'm not familiar with what that is) makes me think it's something specific to your environment. If you're able to find a way to reproduce the problem is a sample application then please open a new issue and we'll take a look.