quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.58k stars 2.63k forks source link

Using value higher than Integer.MAX_VALUE as REST method arg cause 404 Not Found instead of 400 Bad Request #42167

Closed sarxos closed 1 month ago

sarxos commented 1 month ago

Describe the bug

Dear Quarkus Team :)

I found a small problem in how out-of-range numbers are treated in REST endpoints when used as params. When the API caller provides invalid input (and out-of-range value is an example of such), a 404 Not Found is being returned instead of 400 Bad Request. Even if we assume that out-of-range value is treated as null, this case does not work as expected because when I have a @NotNull validator, it's not being used and I still end up with error code 404 instead of 400.

From my analysis, it looks like only parameters annotated with the following annotations are affected by the problem - in all these cases supplying out-of-range numbers results in 404 Not Found (not expected):

Parameters annotated with the following annotations, on the other hand, work well - in all these cases out-of-range numbers results in 400 Bad Request (as expected):

I haven't tested @RestCookie since in runtime it is bound to null.

Example of expected behaviour:

image image

Example of unexpected behaviour:

image image

I can observe the same behaviour in Firefox Network console:

image

Expected behavior

400 Bad Request with a response detailing what is wrong.

Actual behavior

404 Not Found with empty response payload.

How to Reproduce?

Have the following class:

import org.jboss.resteasy.reactive.RestCookie;
import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.RestHeader;
import org.jboss.resteasy.reactive.RestMatrix;
import org.jboss.resteasy.reactive.RestPath;
import org.jboss.resteasy.reactive.RestQuery;

import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;

@Path("test")
public class TestResource {

    @POST
    @Path("{pathvalue}")
    public String getTest(
        final @RestHeader("headervalue") Integer header,
        final @RestQuery("queryvalue") Integer query,
        final @RestPath("pathvalue") Integer path,
        final @RestForm("formvalue") Integer form,
        final @RestCookie("cookievalue") Integer cookie,
        final @RestMatrix("matrixvalue") Integer matrix) {
        return ""
            + "header: " + header + ", "
            + "query: " + query + ", "
            + "path: " + path + ", "
            + "form: " + form + ", "
            + "cookie: " + cookie + ", "
            + "matrix: " + matrix;
    }
}

Open dev-ui, and go to Swagger:

image

Try to supply specific parameter with 2147483648 (out-of-range) while having all others set to 2147483647 (max valid int).

Observe:

Annotation Response Status Is correct?
@RestQuery 404 Not Found No
@RestPath 404 Not Found No
@RestMatrix 404 Not Found No
@RestForm 400 Bad Request Yes
@RestHeader 400 Bad Request Yes

Output of uname -a or ver

Linux WAW-HCD79K3 5.15.0-116-generic #126~20.04.1-Ubuntu SMP Mon Jul 1 15:40:07 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

openjdk version "21" 2023-09-19 OpenJDK Runtime Environment (build 21+35-2513) OpenJDK 64-Bit Server VM (build 21+35-2513, mixed mode, sharing)

Quarkus version or git rev

3.13.0.CR1

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

N/A

Additional information

Tested on Quarkus 3.9.3, 3.12.3, and 3.13.0.CR1. Reproduced on all these versions.

quarkus-bot[bot] commented 1 month ago

/cc @FroMage (resteasy-reactive), @stuartwdouglas (resteasy-reactive)

geoand commented 1 month ago

Thanks for the detailed analysis!

I am actually not sure if what you are seeing is the proper behavior or not... Can you do the same against quarkus-resteasy? If you get the same results, then this behavior is mandated by the JAX-RS / Jakarta REST TCK

sarxos commented 1 month ago

Hi @geoand,

I confirm the same problem can be reproduced on quarkus-resteasy :( thus, it looks like it's an "unfortunate" expected behaviour, as you suggested.

Here is the ode I used for verification:

package org.acme;

import jakarta.ws.rs.CookieParam;
import jakarta.ws.rs.FormParam;
import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.MatrixParam;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.QueryParam;

@Path("test")
public class TestResource {

    @POST
    @Path("{pathvalue}")
    public String getTest(
        final @HeaderParam("headervalue") Integer header,
        final @QueryParam("queryvalue") Integer query,
        final @PathParam("pathvalue") Integer path,
        final @FormParam("formvalue") Integer form,
        final @CookieParam("cookievalue") Integer cookie,
        final @MatrixParam("matrixvalue") Integer matrix) {
        return ""
            + "header: " + header + ", "
            + "query: " + query + ", "
            + "path: " + path + ", "
            + "form: " + form + ", "
            + "cookie: " + cookie + ", "
            + "matrix: " + matrix;
    }
}
geoand commented 1 month ago

Thanks a lot for checking.

I do agree that it is unfortunate, but going against the spec on this could break existing applications, so we'll have to stay with the current behavior.