diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/CustomHeaderResponse.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/CustomHeaderResponse.java new file mode 100644 index 000000000..6db2a053e --- /dev/null +++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/CustomHeaderResponse.java @@ -0,0 +1,13 @@ +package io.quarkus.ts.http.advanced.reactive; + +public class CustomHeaderResponse { + private final String content; + + public CustomHeaderResponse(String content) { + this.content = content; + } + + public String getContent() { + return content; + } +} diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersMessageBodyWriter.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersMessageBodyWriter.java new file mode 100644 index 000000000..3e78f71a8 --- /dev/null +++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersMessageBodyWriter.java @@ -0,0 +1,29 @@ +package io.quarkus.ts.http.advanced.reactive; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Provider; + +@Provider +public class HeadersMessageBodyWriter implements MessageBodyWriter { + + @Override + public boolean isWriteable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return CustomHeaderResponse.class.isAssignableFrom(aClass) && MediaType.TEXT_PLAIN_TYPE.isCompatible(mediaType); + } + + @Override + public void writeTo(CustomHeaderResponse customHeaderResponse, Class aClass, Type type, Annotation[] annotations, + MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) + throws IOException, WebApplicationException { + final String content = "Headers response: " + customHeaderResponse.getContent(); + outputStream.write(content.getBytes()); + } +} diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersResource.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersResource.java index 985646487..bdf5fd034 100644 --- a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersResource.java +++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersResource.java @@ -2,6 +2,8 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import io.smallrye.mutiny.Uni; @@ -28,4 +30,11 @@ public Uni headersOverride() { return Uni.createFrom().item(response); } + @GET + @Path("/no-accept") + @Produces(MediaType.TEXT_PLAIN) + public Uni okHeaders() { + return Uni.createFrom().item("ok headers"); + } + } diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/BaseHttpAdvancedReactiveIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/BaseHttpAdvancedReactiveIT.java index fd8f9168a..df954181b 100644 --- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/BaseHttpAdvancedReactiveIT.java +++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/BaseHttpAdvancedReactiveIT.java @@ -98,7 +98,12 @@ public void httpServer() { @Test @DisplayName("GRPC Server test") public void testGrpc() { - getApp().given().when().get("/api/grpc/trinity").then().statusCode(SC_OK).body(is("Hello trinity")); + getApp().given() + .when() + .get("/api/grpc/trinity") + .then() + .statusCode(SC_OK) + .body(is("Hello trinity")); } @Test diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeGrpcIntegrationReactiveIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeGrpcIntegrationReactiveIT.java index 9517aae89..364a00055 100644 --- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeGrpcIntegrationReactiveIT.java +++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeGrpcIntegrationReactiveIT.java @@ -70,7 +70,12 @@ public void testGrpcAsClient() throws ExecutionException, InterruptedException { @Test public void testGrpcViaRest() { - app.given().when().get("/api/grpc/trinity").then().statusCode(HttpStatus.SC_OK).body(is("Hello trinity")); + app.given() + .when() + .get("/api/grpc/trinity") + .then() + .statusCode(HttpStatus.SC_OK) + .body(is("Hello trinity")); } @Test diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HeadersIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HeadersIT.java index 5be721a99..1b158412d 100644 --- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HeadersIT.java +++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HeadersIT.java @@ -10,6 +10,8 @@ import java.util.List; +import io.restassured.http.Header; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @@ -22,6 +24,8 @@ public class HeadersIT { @QuarkusApplication(classes = { PathSpecificHeadersResource.class, + HeadersMessageBodyWriter.class, + CustomHeaderResponse.class, HeadersResource.class }, properties = "headers.properties") static RestService app = new RestService(); @@ -100,6 +104,20 @@ private ValidatableResponse whenGet(String path) { .body(is("ok")); } + @Disabled("https://github.com/quarkusio/quarkus/issues/42854") + @Test + @Tag("https://github.com/quarkusio/quarkus/pull/41411") + void testWithNoAcceptHeader() { + Header header = new Header("Accept", null); + given() + .when() + .header(header) + .get("/headers/no-accept") + .then() + .statusCode(200) + .body(is("Headers response: ok headers")); + } + /** * Cache-Control header may be present multiple times in the response, e.g. in an OpenShift deployment. That is why we need * to look for a specific value among all headers of the same name, and not just match the last one of them, which is what diff --git a/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/CustomHeaderResponse.java b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/CustomHeaderResponse.java new file mode 100644 index 000000000..d6a21773b --- /dev/null +++ b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/CustomHeaderResponse.java @@ -0,0 +1,14 @@ +package io.quarkus.ts.http.advanced; + +public class CustomHeaderResponse { + + private final String content; + + public CustomHeaderResponse(String content) { + this.content = content; + } + + public String getContent() { + return content; + } +} diff --git a/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersMessageBodyWriter.java b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersMessageBodyWriter.java new file mode 100644 index 000000000..b3cbbb8fc --- /dev/null +++ b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersMessageBodyWriter.java @@ -0,0 +1,29 @@ +package io.quarkus.ts.http.advanced; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.ext.Provider; + +@Provider +public class HeadersMessageBodyWriter implements MessageBodyWriter { + + @Override + public boolean isWriteable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) { + return CustomHeaderResponse.class.isAssignableFrom(aClass) && MediaType.TEXT_PLAIN_TYPE.isCompatible(mediaType); + } + + @Override + public void writeTo(CustomHeaderResponse customHeaderResponse, Class aClass, Type type, Annotation[] annotations, + MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) + throws IOException, WebApplicationException { + final String content = "Headers response: " + customHeaderResponse.getContent(); + outputStream.write(content.getBytes()); + } +} diff --git a/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersResource.java b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersResource.java index 64d8aeadd..e9cf956b8 100644 --- a/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersResource.java +++ b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersResource.java @@ -2,6 +2,8 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @Path("/headers") @@ -13,6 +15,13 @@ public String headers() { return "ok"; } + @GET + @Path("/no-accept") + @Produces(MediaType.TEXT_PLAIN) + public CustomHeaderResponse noAcceptheaders() { + return new CustomHeaderResponse("ok"); + } + @GET @Path("/pragma") public String pragmaHeaderMustBeSet() { diff --git a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/BaseHttpAdvancedIT.java b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/BaseHttpAdvancedIT.java index df22cdc50..4f34bb95d 100644 --- a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/BaseHttpAdvancedIT.java +++ b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/BaseHttpAdvancedIT.java @@ -111,7 +111,13 @@ public void clientHostAddress(TestInfo testInfo) { @Test @DisplayName("GRPC Server test") public void testGrpc() { - getApp().given().when().get("/api/grpc/trinity").then().statusCode(HttpStatus.SC_OK).body(is("Hello trinity")); + getApp() + .given() + .when() + .get("/api/grpc/trinity") + .then() + .statusCode(HttpStatus.SC_OK) + .body(is("Hello trinity")); } @Test diff --git a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/DevModeGrpcIntegrationIT.java b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/DevModeGrpcIntegrationIT.java index 7a3d5b323..cf0581de0 100644 --- a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/DevModeGrpcIntegrationIT.java +++ b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/DevModeGrpcIntegrationIT.java @@ -68,7 +68,12 @@ public void testGrpcAsClient() { @Test public void testGrpcViaRest() { - app.given().when().get("/api/grpc/trinity").then().statusCode(HttpStatus.SC_OK).body(is("Hello trinity")); + app.given() + .when() + .get("/api/grpc/trinity") + .then() + .statusCode(HttpStatus.SC_OK) + .body(is("Hello trinity")); } @Test diff --git a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HeadersIT.java b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HeadersIT.java index 741d94622..8f928d0ad 100644 --- a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HeadersIT.java +++ b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HeadersIT.java @@ -16,12 +16,15 @@ import io.quarkus.test.bootstrap.RestService; import io.quarkus.test.scenarios.QuarkusScenario; import io.quarkus.test.services.QuarkusApplication; +import io.restassured.http.Header; import io.restassured.response.ValidatableResponse; @QuarkusScenario public class HeadersIT { @QuarkusApplication(classes = { PathSpecificHeadersResource.class, + HeadersMessageBodyWriter.class, + CustomHeaderResponse.class, HeadersResource.class }, properties = "headers.properties") static RestService app = new RestService(); @@ -93,6 +96,19 @@ void testPathSpecificHeaderRulesOrder() { cacheControlMatches(response, "max-age=1"); } + @Test + @Tag("https://github.com/quarkusio/quarkus/pull/41411") + void testWithNoAcceptHeader() { + Header header = new Header("Accept", null); + given() + .when() + .header(header) + .get("/headers/no-accept") + .then() + .statusCode(200) + .body(is("Headers response: ok")); + } + private ValidatableResponse whenGet(String path) { return given() .get(path)