Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve exception message if MultipartParser can not find end of body #28067

Closed
bsreddy125 opened this issue Feb 17, 2022 · 11 comments
Closed

Improve exception message if MultipartParser can not find end of body #28067

bsreddy125 opened this issue Feb 17, 2022 · 11 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: feedback-provided Feedback has been provided type: enhancement A general enhancement
Milestone

Comments

@bsreddy125
Copy link

bsreddy125 commented Feb 17, 2022

Parts coming as null, where as same working when uploading from postman, but it failing from angular/chrome agent and verified the request b/w postman and chrome both are similar

Code:

public Mono<ServerResponse> uploadDocument(ServerRequest request) {

    return request
        .body(BodyExtractors.toMultipartData())
        .map(
            parts -> {
              log.info("parts size  " + parts.size());
              Map<String, Part> formParts = parts.toSingleValueMap();
              log.error("Form data parts " + formParts.toString());
              FormFieldPart uploadFormField = (FormFieldPart) formParts.get("fileUploadModel");
              log.error("Form field value " + uploadFormField.toString());
              FilePart file = (FilePart) formParts.get("file");
              FileUploadModel fileUpload = fileUploadModelVO(uploadFormField);
              return uploadDocumentService.uploadFile(fileUpload, file).map(this::documentMapper);
            })
        .flatMap(
            document ->
                ServerResponse.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(document, FileUploadModel.class));
  }

Parts coming as null, where as same working when uploading from postman, but it failing from angular/chrome agent and verified the request b/w postman and chrome both are similar

 public Mono<ServerResponse> uploadDocument(ServerRequest request) {

    return request
        .body(BodyExtractors.toMultipartData())
        .map(
            parts -> {
              log.info("parts size  " + parts.size());
              Map<String, Part> formParts = parts.toSingleValueMap();
              log.error("Form data parts " + formParts.toString());
              FormFieldPart uploadFormField = (FormFieldPart) formParts.get("fileUploadModel");
              log.error("Form field value " + uploadFormField.toString());
              FilePart file = (FilePart) formParts.get("file");
              FileUploadModel fileUpload = fileUploadModelVO(uploadFormField);
              return uploadDocumentService.uploadFile(fileUpload, file).map(this::documentMapper);
            })
        .flatMap(
            document ->
                ServerResponse.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(document, FileUploadModel.class));
  }

Postman Request:

Warning: Self signed certificate in certificate chain
POST /eap/consultation/document/uploadDocument/ HTTP/1.1
User-Agent: PostmanRuntime/7.28.4
Accept: */*
Postman-Token: f98a5224-a2f3-4609-b2e5-219a03cc6b82
Host: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: multipart/form-data; boundary=------------------------- -019436366390284846853277
Content-Length: 178369
----------------------------019436366390284846853277
Content-Disposition: form-data; name="file"; filename="Gmail - Your Zomato order from Pista House (1).PDF"
<Gmail - Your Zomato order from Pista House (1).PDF>
----------------------------019436366390284846853277
Content-Disposition: form-data; name="fileUploadModel" { "fileName":"fileee2ff333", "description": "url changes", "caseId":"50" }
----------------------------019436366390284846853277--

Chrome Request:

POST /eap/consultation/document/uploadDocument HTTP/1.1
Host: xxxxxxxxxxxxxxxxxxxxxx
Connection: keep-alive
Content-Length: 178351
sec-ch-ua: "Google Chrome";v="95", "Chromium";v="95", ";Not A Brand";v="99"
Accept: */*
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarySwprz3OeLnKlYLf8
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36 sec-ch-ua-platform: "Windows"
Origin: https:/*********************
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://***************************
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
------WebKitFormBoundaryCXUDq20q3OAAg1eO
Content-Disposition: form-data; name="file"; filename="Food-bill.pdf"
Content-Type: application/pdf
------WebKitFormBoundaryCXUDq20q3OAAg1eO
Content-Disposition: form-data; name="fileUploadModel"
{"caseId":1011,"description":"","fileName":"Food-bill.pdf"}
------WebKitFormBoundaryCXUDq20q3OAAg1eO--

Service configuration:

@Configuration
@EnableWebFlux
public class ConsultationServWebConfig implements WebFluxConfigurer {

  @Override
  public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
    SynchronossPartHttpMessageReader partReader = new SynchronossPartHttpMessageReader();
    partReader.setEnableLoggingRequestDetails(true);

    MultipartHttpMessageReader multipartReader = new MultipartHttpMessageReader(partReader);
    multipartReader.setEnableLoggingRequestDetails(true);

    configurer.defaultCodecs().multipartReader(multipartReader);
  }

  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**").allowedHeaders("*").allowedMethods("*").allowedOrigins("*");
  }
}

With SynchronossPartHttpMessageReader parts coming as null from angular where as same working from postman.

DefaultPartHttpMessageReader giving decoding exception could not find end of the body where as same working from postman

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Feb 17, 2022
@bclozel bclozel transferred this issue from spring-projects/spring-boot Feb 17, 2022
@bclozel bclozel added the in: web Issues in web modules (web, webmvc, webflux, websocket) label Feb 17, 2022
@bsreddy125 bsreddy125 changed the title Spring webflux fucntional route multipart file upload not working from angular/chrome/browser agents Spring-boot webflux fucntional route multipart file upload not working from angular/chrome/browser agents Feb 18, 2022
@poutsma
Copy link
Contributor

poutsma commented Feb 18, 2022

Which version of Spring Framework are you using? There have been several fixes to the DefaultPartHttpMessageReader recently (i.e. #27939, #27612).

@poutsma poutsma added the status: waiting-for-feedback We need additional information before we can continue label Feb 18, 2022
@bsreddy125
Copy link
Author

bsreddy125 commented Feb 19, 2022

Which version of Spring Framework are you using? There have been several fixes to the DefaultPartHttpMessageReader recently (i.e. #27939, #27612).

2.6.2 and 2.5.5 versions, tried with both are causing same. Is any configuration required in filters?

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Feb 19, 2022
@bsreddy125 bsreddy125 changed the title Spring-boot webflux fucntional route multipart file upload not working from angular/chrome/browser agents decoding exception "Could not find end of the body" Spring-boot webflux fucntional route multipart file upload not working from angular/chrome/browser agents Feb 21, 2022
@poutsma
Copy link
Contributor

poutsma commented Feb 22, 2022

2.6.2 and 2.5.5 versions, tried with both are causing same.

That's Spring Boot 2.6.2, so Spring Framework 5.3.14.

I think this issue might related to #27939, which was fixed in Spring Framework 5.3.16 and will be in Spring Boot 2.6.4, due out this Thursday.

If you want to try the fix now, you can upgrade to Spring Boot 2.6.3, and set the spring-framework.version property to 5.3.16 in your pom.xml or build.gradle.

@poutsma poutsma self-assigned this Feb 22, 2022
@bsreddy125
Copy link
Author

bsreddy125 commented Feb 22, 2022

2.6.2 and 2.5.5 versions, tried with both are causing same.

That's Spring Boot 2.6.2, so Spring Framework 5.3.14.

I think this issue might related to #27939, which was fixed in Spring Framework 5.3.16 and will be in Spring Boot 2.6.4, due out this Thursday.

If you want to try the fix now, you can upgrade to Spring Boot 2.6.3, and set the spring-framework.version property to 5.3.16 in your pom.xml or build.gradle.

With the mentioned versions experiencing some other error
"trace": "org.springframework.core.codec.DecodingException: Could not find first boundary\n\tat org.springframework.http.codec.multipart.MultipartParser$PreambleState.onComplete(MultipartParser.java:321)\

Is multipart upload dependent with server connection time out, initially i got 504 error then tried with10kb file then noticed decoding error

application.yml config

  webflux:
    basepath: eap/consultation
    multipart:
      max-in-memory-size: 10MB
  data:
    mongodb:
      uri: ${MONGO_DB_URI:mongodb://localhost:27017/eap}
  codec:
    max-in-memory-size: 10MB
    log-request-details: true
  servlet:
    multipart:
      enabled: true
      max-file-size: 10MB
      max-request-size: 10MB

server:
  port: 9103
  netty:
    initial-buffer-size: 10MB
    max-chunk-size: 10MB 
    connection-timeout: 300000
#logging.level.org.springframework.web.reactive.function.client.ExchangeFunctions: TRACE
#logging.level.reactor.netty.http.client.HttpClient: DEBUG
  
spring.mongodb.embedded.version: 5.0.5```

@poutsma poutsma added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Feb 23, 2022
@poutsma poutsma added this to the 5.3.17 milestone Feb 23, 2022
@poutsma poutsma added status: waiting-for-triage An issue we've not yet triaged or decided on and removed type: bug A general bug labels Feb 23, 2022
@poutsma poutsma removed this from the 5.3.17 milestone Feb 23, 2022
@poutsma
Copy link
Contributor

poutsma commented Feb 23, 2022

In an earlier comment (now deleted) I wrote that I could reproduce this, but I was wrong. Uploading multipart data from Chrome works fine for me.

From your comments I gather that both the DefaultPartHttpMessageReader and the SynchronossPartHttpMessageReader have problems with the data submitted by Angular, and that both work fine with data submitted from Postman. This suggest to me that Angular is sending malformed multipart data, but I cannot be sure unless I can reproduce the issue.

So if you'd like us to spend some time investigating, please take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.

@bsreddy125
Copy link
Author

In an earlier comment (now deleted) I wrote that I could reproduce this, but I was wrong. Uploading multipart data from Chrome works fine for me.

From your comments I gather that both the DefaultPartHttpMessageReader and the SynchronossPartHttpMessageReader have problems with the data submitted by Angular, and that both work fine with data submitted from Postman. This suggest to me that Angular is sending malformed multipart data, but I cannot be sure unless I can reproduce the issue.

So if you'd like us to spend some time investigating, please take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.

We are having this issue only in non prod environments. Its happening in when service deployed in docker containers in linux environments. In local its working. Is any decoding configuration or server level configuration required?

@poutsma
Copy link
Contributor

poutsma commented Feb 24, 2022

We are having this issue only in non prod environments. Its happening in when service deployed in docker containers in linux environments. In local its working. Is any decoding configuration or server level configuration required?

No additional configuration should be required, given that the size of the files you are sending are not that large (178,351 bytes, looking at the Content-Length header).

It's interesting that the bug only occurs in production. That would suggest that the HTTP headers or body are manipulated somehow in this environment.
To give a better indication of what's goin on, you can try setting the org.springframework.http.codec.multipart log level to TRACE. That can give a lot of output, so I would suggest only doing that temporarily.

@bsreddy125
Copy link
Author

bsreddy125 commented Mar 1, 2022

We are having this issue only in non prod environments. Its happening in when service deployed in docker containers in linux environments. In local its working. Is any decoding configuration or server level configuration required?

No additional configuration should be required, given that the size of the files you are sending are not that large (178,351 bytes, looking at the Content-Length header).

It's interesting that the bug only occurs in production. That would suggest that the HTTP headers or body are manipulated somehow in this environment. To give a better indication of what's goin on, you can try setting the org.springframework.http.codec.multipart log level to TRACE. That can give a lot of output, so I would suggest only doing that temporarily.

Postman request trace logs:

2022-03-01 18:52:02.925 TRACE 1 --- [tor-thread-1255] o.s.h.codec.multipart.MultipartParser : First boundary found @51 in DefaultDataBuffer (r: 0, w: 158, c: 158)
2022-03-01 18:52:02.927 TRACE 1 --- [tor-thread-1255] o.s.h.codec.multipart.MultipartParser : Changed state: PREAMBLE -> HEADERS
2022-03-01 18:52:02.928 TRACE 1 --- [tor-thread-1255] o.s.h.codec.multipart.MultipartParser : End of headers found @105 in DefaultDataBuffer (r: 0, w: 106, c: 106)
2022-03-01 18:52:02.928 TRACE 1 --- [tor-thread-1255] o.s.h.codec.multipart.MultipartParser : Emitting headers: [Content-Disposition:"form-data; name="file"; filename="Food-bill.pdf"", Content-Type:"application/pdf"]
2022-03-01 18:52:02.929 TRACE 1 --- [tor-thread-1255] o.s.http.codec.multipart.PartGenerator : Changed state: INITIAL -> IN-MEMORY
2022-03-01 18:52:02.929 TRACE 1 --- [tor-thread-1255] o.s.h.codec.multipart.MultipartParser : Changed state: HEADERS -> BODY
2022-03-01 18:52:03.859 TRACE 1 --- [tor-thread-1262] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 5977, c: 5977)
2022-03-01 18:52:03.862 TRACE 1 --- [tor-thread-1262] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 18:52:03.864 TRACE 1 --- [tor-thread-1262] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 18:52:03.865 TRACE 1 --- [tor-thread-1262] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:12.714 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : First boundary found @51 in DefaultDataBuffer (r: 0, w: 153, c: 153)
2022-03-01 19:03:12.715 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Changed state: PREAMBLE -> HEADERS
2022-03-01 19:03:12.716 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : End of headers found @100 in DefaultDataBuffer (r: 0, w: 101, c: 101)
2022-03-01 19:03:12.717 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting headers: [Content-Disposition:"form-data; name="file"; filename="June.pdf"", Content-Type:"application/pdf"]
2022-03-01 19:03:12.717 TRACE 1 --- [tor-thread-1365] o.s.http.codec.multipart.PartGenerator : Changed state: INITIAL -> IN-MEMORY
2022-03-01 19:03:12.717 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Changed state: HEADERS -> BODY
2022-03-01 19:03:13.303 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 5982, c: 5982)
2022-03-01 19:03:13.305 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.306 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.307 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.308 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.309 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.310 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.310 TRACE 1 --- [tor-thread-1365] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.617 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.620 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.621 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.623 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.624 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.626 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.627 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.629 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.630 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.632 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.633 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.635 TRACE 1 --- [tor-thread-1344] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.920 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.922 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.923 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.924 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.925 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.925 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Boundary found @1851 in DefaultDataBuffer (r: 0, w: 2080, c: 2080)
2022-03-01 19:03:13.926 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:03:13.926 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 1798, c: 1798)
2022-03-01 19:03:13.927 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Changed state: BODY -> HEADERS
2022-03-01 19:03:13.927 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : End of headers found @91 in DefaultDataBuffer (r: 0, w: 228, c: 228)
2022-03-01 19:03:13.928 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting headers: [Content-Disposition:"form-data; name="fileUploadModel"", Content-Type:"application/json"]
2022-03-01 19:03:13.929 TRACE 1 --- [tor-thread-1372] o.s.http.codec.multipart.PartGenerator : Emitting: DefaultFilePart{file (June.pdf)}
2022-03-01 19:03:13.929 TRACE 1 --- [tor-thread-1372] o.s.http.codec.multipart.PartGenerator : Changed state: IN-MEMORY -> IN-MEMORY
2022-03-01 19:03:13.930 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Changed state: HEADERS -> BODY
2022-03-01 19:03:13.930 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Boundary found @131 in DefaultDataBuffer (r: 0, w: 136, c: 136)
2022-03-01 19:03:13.931 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 78, c: 78)
2022-03-01 19:03:13.931 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Changed state: BODY -> HEADERS
2022-03-01 19:03:13.931 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Last boundary found in DefaultDataBuffer (r: 0, w: 4, c: 4)
2022-03-01 19:03:13.932 TRACE 1 --- [tor-thread-1372] o.s.h.codec.multipart.MultipartParser : Changed state: HEADERS -> DISPOSED
2022-03-01 19:03:13.932 TRACE 1 --- [tor-thread-1372] o.s.http.codec.multipart.PartGenerator : Emitting: DefaultPart{fileUploadModel}
2022-03-01 19:03:13.933 TRACE 1 --- [tor-thread-1372] o.s.h.c.m.MultipartHttpMessageReader : [f01d3c1] Parsed {file=[DefaultFilePart{file (June.pdf)}], fileUploadModel=[DefaultPart{fileUploadModel}]}

===============================
Web Request trace logs:

2022-03-01 19:08:44.787 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : First boundary found @38 in DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:44.788 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Changed state: PREAMBLE -> HEADERS
2022-03-01 19:08:44.788 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : End of headers found @100 in DefaultDataBuffer (r: 0, w: 8153, c: 8153)
2022-03-01 19:08:44.789 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Emitting headers: [Content-Disposition:"form-data; name="file"; filename="June.pdf"", Content-Type:"application/pdf"]
2022-03-01 19:08:44.790 TRACE 1 --- [tor-thread-1431] o.s.http.codec.multipart.PartGenerator : Changed state: INITIAL -> IN-MEMORY
2022-03-01 19:08:44.790 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Changed state: HEADERS -> BODY
2022-03-01 19:08:44.791 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8052, c: 8052)
2022-03-01 19:08:44.792 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:44.793 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.093 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.095 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.095 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.096 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.398 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.399 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.400 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.401 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.403 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.404 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.405 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.405 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.407 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.407 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.408 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.409 TRACE 1 --- [tor-thread-1417] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.473 TRACE 1 --- [tor-thread-1429] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.474 TRACE 1 --- [tor-thread-1429] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.475 TRACE 1 --- [tor-thread-1429] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.476 TRACE 1 --- [tor-thread-1429] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.710 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.711 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Emitting body: DefaultDataBuffer (r: 0, w: 8192, c: 8192)
2022-03-01 19:08:45.712 TRACE 1 --- [tor-thread-1431] o.s.h.codec.multipart.MultipartParser : Changed state: BODY -> DISPOSED
2022-03-01 19:08:45.712 TRACE 1 --- [tor-thread-1431] o.s.http.codec.multipart.PartGenerator : Changed state: IN-MEMORY -> DISPOSED
2022-03-01 19:08:45.716 ERROR 1 --- [tor-thread-1431] a.w.r.e.AbstractErrorWebExceptionHandler : [ed723985] 500 Server Error for HTTP POST "/upload/documentupload"
org.springframework.core.codec.DecodingException: Could not find end of body
at org.springframework.http.codec.multipart.MultipartParser$BodyState.onComplete(MultipartParser.java:553) ~[spring-web-5.3.14.jar:5.3.14]

@yelouarti
Copy link

yelouarti commented Sep 9, 2022

@bsreddy125 I faced a similar issue, where locally (Windows) it worked fine, but the same code remotely on a linux machine throwed an "org.springframework.core.codec.DecodingException: Could not find end of body". Given however, this behavior was observed during an integration test and not in production (i.e. with synthetic data).

The Setup

A total of 3 application are involved:

  • Wiremock docker container that provides a response in multipart-data format
  • Unit test that sets up the wiremock instance by feeding it the response multipart data and that calls the service-under-test (SuT).
  • Service (i.e. the SuT) that consumes multipart data (from the wiremock) and which ultimately throws the DecodingException

An important detail is that locally I'm working on Windows and Docker Desktop (enables docker under Windows).

(Disclaimer: This was my setup, you can achieve the error without a wiremock!)

Reason for the Error

The multipart data that the unit test used was created under Windows, which per default uses CRLF for line breaks. This is also how line breaks have to be implemented in multipart data according to RFC. This is also what the DefaultPartHttpMessageReader expects.

Unfortunately I didn't realize, that Git was set up to automatically change in CRLF to linux style LF (here is a SO answer that explains this very nicely). In short, the test data with which the mock was fed was different locally and remotely on linux:

  • locally: Unit test reads file with CRLF -> feeds wiremock -> SuT gets the unmodified file with CRLF -> ✔
  • remotely: Pushed data was modified by Git -> unit test feeds "corrupt data" to mock -> SuT is looking for CRLF but can't find it -> ❌

How to Bypass the Error

  • You could either change the settings of your version control
  • Encode your data with CRLF e.g. in Base64 and push it to your repository. Now it can be decoded by your SuT or unit tests regardless of the OS and it will always contain the desired line breaks as the line breaks weren't modified because they were encoded.

You could fix this in more than the suggested ways honestly. It could as well be, that you have a similar, but not necessarily identical, issue @bsreddy125.

Suggestion for Spring

Regardless of whether OP has the same issue, I think it would be at least appreciated, if the exception details could hint a possible issue regarding line breaks. If not a single CRLF was found, chances are the data is corrupt, especially if LFs are available. I spent days looking for the error. However, I don't think this is an issue on Springs end to be honest.

@mukeshj13
Copy link

Facing the same issue on MacOS local for a pdf file. Not sending the Content-Type header through postman, it is automatically adding that.
DecodeException: Could not find first boundary
at org.springframework.http.codec.multipart.MultipartParser$PreambleState.onComplete(MultipartParser.java:306)
at org.springframework.http.codec.multipart.MultipartParser.hookOnComplete(MultipartParser.java:109)
at reactor.core.publisher.BaseSubscriber.onComplete(BaseSubscriber.java:197)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:259)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:142)
at reactor.core.publisher.Operators.complete(Operators.java:136)......

@poutsma poutsma changed the title decoding exception "Could not find end of the body" Spring-boot webflux fucntional route multipart file upload not working from angular/chrome/browser agents Improve exception message if MultipartParser can not find end of body Oct 10, 2022
@poutsma poutsma added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Oct 10, 2022
@poutsma
Copy link
Contributor

poutsma commented Oct 10, 2022

Resolved by changing the exception message so that it shows the exact string that the multipart parser is looking for (i.e. ␍␊--<boundary>).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: feedback-provided Feedback has been provided type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

6 participants