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

MultipartForm is receiving null parameters at the server #27215

Closed
DMaxter opened this issue Aug 10, 2022 · 18 comments
Closed

MultipartForm is receiving null parameters at the server #27215

DMaxter opened this issue Aug 10, 2022 · 18 comments
Labels
area/openapi area/resteasy-reactive kind/bug Something isn't working triage/out-of-date This issue/PR is no longer valid or relevant
Milestone

Comments

@DMaxter
Copy link

DMaxter commented Aug 10, 2022

Describe the bug

When using resteasy-reactive in Kotlin (I didn't test with Java), when I have an endpoint like this:

import org.jboss.resteasy.reactive.MultipartForm


    @POST
    @Path("/image/{id}")
    @RolesAllowed(MANAGER_ROLE, ADMIN_ROLE)
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Operation(summary = "Add images to a brand")
    @APIResponses(
        APIResponse(responseCode = "200", description = "Successful image registration"),
        APIResponse(responseCode = "401", description = "User is not logged in"),
        APIResponse(responseCode = "403", description = "User doesn't have authorization to add images to a brand")
    )
    fun addImage(@PathParam("id") brand: Long, @MultipartForm images: ImageUploadDto): Uni<Response> {
        return identity.deferredIdentity.onItem().transformToUni { id ->
            logger.info("User ${id.principal.name} is adding ${images} image to brand with id $brand")

            return@transformToUni brandService.addImages(brand, images)
        }
    }

With ImageUploadDto being:

import org.eclipse.microprofile.openapi.annotations.enums.SchemaType
import org.eclipse.microprofile.openapi.annotations.media.Schema
import org.jboss.resteasy.reactive.PartType
import org.jboss.resteasy.reactive.RestForm
import java.io.File
import javax.ws.rs.core.MediaType

class ImageUploadDto {
    @RestForm("image")
    @PartType(MediaType.APPLICATION_OCTET_STREAM)
    @Schema(type = SchemaType.STRING, format = "binary")
    var content: String? = null

    @RestForm
    var file: File? = null
}

In swagger, content has a button to allow me to upload a file and there is a file field which is the JSON mapping of the java.io.File class to JSON. I tried with org.jboss.resteasy.reactive.multipart.FileUpload but the behavior was the same as using File (except that FileUpload is an interface so the JSON mapping was empty).

Besides this, when data gets to the server, content is null as well as File (I defined the variables as nullable because I received a NullPointerException otherwise) as it is able to create an ImageUploadDto instance but the properties are null. I followed the example in the documentation (just adapted it to Kotlin) and it doesn't work

Expected behavior

Get the file contents

Actual behavior

Everything is null

How to Reproduce?

Use the example above and try to upload a file

Output of uname -a or ver

Linux zirconium 5.18.16-zen1-1-zen #1 ZEN SMP PREEMPT_DYNAMIC Wed, 03 Aug 2022 11:25:10 +0000 x86_64 GNU/Linux

Output of java -version

openjdk version "18.0.2" 2022-07-19
OpenJDK Runtime Environment (build 18.0.2+9)
OpenJDK 64-Bit Server VM (build 18.0.2+9, mixed mode)

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.11.2.Final

Build tool (ie. output of mvnw --version or gradlew --version)

------------------------------------------------------------
Gradle 7.5.1
------------------------------------------------------------

Build time:   2022-08-06 13:53:45 UTC
Revision:     <unknown>

Kotlin:       1.6.21
Groovy:       3.0.10
Ant:          Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM:          18.0.2 (Oracle Corporation 18.0.2+9)
OS:           Linux 5.18.16-zen1-1-zen amd64

Additional information

No response

@DMaxter DMaxter added the kind/bug Something isn't working label Aug 10, 2022
@quarkus-bot
Copy link

quarkus-bot bot commented Aug 10, 2022

/cc @evanchooly, @geoand

@DMaxter DMaxter changed the title MultipartForm is receiving null at the server MultipartForm is receiving null parameters at the server Aug 10, 2022
@geoand
Copy link
Contributor

geoand commented Aug 10, 2022

Can you also attach what the HTTP request looks like (an easy way to do this is from the browser's developer tools)?

@DMaxter
Copy link
Author

DMaxter commented Aug 10, 2022

The HTTP request looks like this:

POST /brand/image/1 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:103.0) Gecko/20100101 Firefox/103.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://localhost:8080/q/swagger-ui/
Content-Type: multipart/form-data; boundary=---------------------------104025827140925644591275308632
Content-Length: 720
Origin: http://localhost:8080
DNT: 1
Connection: keep-alive
Cookie: identity=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo4MDgwIiwic3ViIjoiYWRtaW4iLCJyb2xlcyI6WyJBRE1JTiJdLCJpYXQiOjE2NjAxMTg0MjUsImV4cCI6MTY2MDEyOTIyNSwianRpIjoiOTZlMWQxZTgtNjU1NC00MGU2LWEzZDItZmM3OGVjNDAwMWRkIn0.U9yGfjNwlQwlCQp66DFFgefpA-XUua049ZfM14YTkStkb2sBe33mgrtJURH1a_8hGYdlphjSCTqw4DHBpmWDih_3nYQnv5WtwSh2uZN-phdoyiO1Cq4hD_X86cadKBAMneUapHdV5ZYBhMi4DhJJmNtwKHrhZkrMssr9DAxVON2-gSsBFD5ieyj0kDS30MNxJIpJ_vIGebA3HZam9SAdZO5RLV7zwi8NfcH-NTVFsjkgBnA2wNCxwzC8EqOqXE13EC69gi8teJf_ir2I4Qr5JdpwyrmyiDBxRflxiULmaFC8YMbj4Arcwgr6ZjIq8StsgR03PN4Y0kUGh9HHdlB0FeM8YYskMEuEkjYLEmxO69pbQFeDMAi19d4EyX5HxR7tMpSMSmec02q1hy8JN3lxEesL_CrpXmhyU1Cj0LaNyPavSh75-hobrXz5Sm_dt2vLuHE--OKwUJwOQtldFwhTZQmX9ad7GI_bESkdofEggIbV0WXP1reF3zWqFTEWkabcPmvjewKvCxkNLd8x-uKW60DF0lqk_suzeUZm8aFhhzsAadNakipLCqp20z_G_qjJ6CihKACMC1ENJ7IcNz_bPN8rAprKLLPBr0QptoH8wht232D5eRZscF8tflhLIZrFtMO4iTZNYMsJ0e1ChEwwEwJ97uSgxSFbkcwqIy_JcXf1suuW_X96yM6iH0nRLMuv6Sv87K2j9g5-W0vH3BBXddHcCUsn9VSl9rkxyQEyS5uDE1qjaumcTbznn1uHAm5sTSne_39APm2vCPPYdzmBda8mdnLvyWQrZAaUGYUcXaIo-WvMNwMlX1FIaXvYkgAXlbOTQtBqNv0INB0sg8zmjocEc2uM_UwUoagaIfgtXLX7DsokM9hlM3gs0Nma53PxXmaKKYtomj1pJQDvXtjBwjfQa3QnQGJ2j8wRjh6mWNSOiYsdPk5NywrYCSceWyOPNetQ01Uze8oUOH2xv1W1tYR9s9Fz7Aar3XRpjhE1DtyOhB85hn4zAQOdMerZH81r2L1WtsGVK5rS-PU-67yf69lHFyuWg6K4DimiJDQO4h5ckktvRURtd60zyfUQPzmFTkn1ay5Edt9tNPIMBBJ0HiMZQKRvunBXnIk1U2hLLqItJjNy9xz0tHNwABNbsBEG-0qIgjcjmVgSk3NVkuIBCSARjb-9cmTQaqJtjoX5b_gSyV28W1sxsz07dAzKAuFqU4rYY0dKGAglnZk3rRsHPvAqXwsxxNZ_xKKMIveTXh3qM6e0k1kWazkjxvJQGeHH0J9Ug4rYElB2p4EZcd-AQeI-HAYmdw3mfO_ADO3r-4FaVS9JVkeIeJa_yR_Gp1dhHO9dFSYsVGAnZ6LttSFoig
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Pragma: no-cache
Cache-Control: no-cache
-----------------------------104025827140925644591275308632
Content-Disposition: form-data; name="image"; filename="tmp"
Content-Type: application/octet-stream

123abcd

-----------------------------104025827140925644591275308632
Content-Disposition: form-data; name="file"

{
  "path": "string",
  "invalid": true,
  "name": "string",
  "parent": "string",
  "parentFile": "string",
  "absolute": true,
  "absolutePath": "string",
  "absoluteFile": "string",
  "canonicalPath": "string",
  "canonicalFile": "string",
  "directory": true,
  "file": true,
  "hidden": true,
  "totalSpace": 0,
  "freeSpace": 0,
  "usableSpace": 0
}
-----------------------------104025827140925644591275308632--

@geoand
Copy link
Contributor

geoand commented Aug 10, 2022

Content-Disposition: form-data; name="file" contains no filename, so using FileUpload or File will not yield any results.

@DMaxter
Copy link
Author

DMaxter commented Aug 10, 2022

The file parameter is the one on ImageUploadDto, it should not appear in swagger at all. It doesn't have a filename because it is showing as a parameter and it shouldn't

@geoand
Copy link
Contributor

geoand commented Aug 10, 2022

So this sounds more like a SwaggerUI issue - which makes sense since I don't think we have any support for RESTEasy Reactive multipart handling in OpenAPI

@DMaxter
Copy link
Author

DMaxter commented Aug 10, 2022

But sending through curl yields the same error, I tried sending a local file with curl and also got null in both parameters

@geoand
Copy link
Contributor

geoand commented Aug 10, 2022

If you do not specify a value for @RestForm the name of the section is assumed to be the field name, so please make sure you are using the proper values.

@DMaxter
Copy link
Author

DMaxter commented Aug 10, 2022

Yes, but that is generated in Swagger, the problem is that the file contents do not get to the backend

@DMaxter
Copy link
Author

DMaxter commented Aug 31, 2022

Any news on this issue?

@geoand
Copy link
Contributor

geoand commented Aug 31, 2022

Not at the moment.

We have a large refactoring of the multipart support we want to get in before making any other changes to it.

@DMaxter
Copy link
Author

DMaxter commented Sep 5, 2022

Are there any alternatives I can use to upload images then?

@geoand
Copy link
Contributor

geoand commented Sep 6, 2022

See my comment above.

@DMaxter
Copy link
Author

DMaxter commented Nov 1, 2022

Is there an estimated date for when the refactoring will be done?

@geoand
Copy link
Contributor

geoand commented Nov 1, 2022

The refactoring has been done and merged in main.

@Sgitario would you like to take another look at this issue?

@Sgitario
Copy link
Contributor

Sgitario commented Nov 2, 2022

I guess you mean #27526 which is already part of 2.14.0.CR1. @DMaxter can you try the Quarkus version 2.14.0.CR1 and see if it works now?

@DMaxter
Copy link
Author

DMaxter commented Nov 3, 2022

The example in the updated docs is generating the following on Swagger:
image

@DMaxter
Copy link
Author

DMaxter commented Nov 3, 2022

With this example, OpenAPI is able to generate an upload button and the content of the file can be read inside my application

    @POST
    @Path("/upload")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    fun upload(@PartType(MediaType.APPLICATION_OCTET_STREAM) @Schema(type = SchemaType.STRING, format = "binary") @RestForm description: FileUpload,
               @RestForm("image") file: File?
    ): Uni<Response> {
        println(description.uploadedFile().toFile().readText())
        println("DONE")
        return Uni.createFrom().item(Response.ok().build())
    }

Thank you

@DMaxter DMaxter closed this as completed Nov 3, 2022
@geoand geoand added the triage/out-of-date This issue/PR is no longer valid or relevant label Nov 3, 2022
@Sgitario Sgitario added this to the 2.14.0.Final milestone Nov 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/openapi area/resteasy-reactive kind/bug Something isn't working triage/out-of-date This issue/PR is no longer valid or relevant
Projects
None yet
Development

No branches or pull requests

3 participants