From 6926b6daa293a2c94a65cf6c07aa58b79595aa59 Mon Sep 17 00:00:00 2001
From: George Gastaldi <gegastaldi@gmail.com>
Date: Fri, 29 Oct 2021 16:40:18 -0300
Subject: [PATCH] Introduce quarkus.http.headers

This allows to explicitly set fixed headers on HTTP responses
---
 docs/src/main/asciidoc/http-reference.adoc    | 12 +++++++
 .../vertx/http/runtime/HttpConfiguration.java |  6 ++++
 .../vertx/http/runtime/VertxHttpRecorder.java | 11 +++++++
 .../io/quarkus/it/vertx/SimpleResource.java   | 13 ++++++++
 .../src/main/resources/application.properties |  3 +-
 .../io/quarkus/it/vertx/HeadersTestCase.java  | 32 +++++++++++++++++++
 6 files changed, 76 insertions(+), 1 deletion(-)
 create mode 100644 integration-tests/vertx-http/src/test/java/io/quarkus/it/vertx/HeadersTestCase.java

diff --git a/docs/src/main/asciidoc/http-reference.adoc b/docs/src/main/asciidoc/http-reference.adoc
index 35bf5b1b76922e..afda147eb766ac 100644
--- a/docs/src/main/asciidoc/http-reference.adoc
+++ b/docs/src/main/asciidoc/http-reference.adoc
@@ -143,6 +143,18 @@ values:
 
 NOTE: if you use `redirect` or `disabled` and have not added a SSL certificate or keystore, your server will not start!
 
+== Additional HTTP Headers
+
+To enable HTTP headers to be sent on every response, add the following properties:
+
+[source, properties]
+----
+quarkus.http.headers.foo=bar
+----
+
+This will return the `foo: bar` HTTP Header for requests performed on any resource in the application.
+
+
 == HTTP/2 Support
 
 HTTP/2 is enabled by default, and will be used by browsers if SSL is in use on JDK11 or higher. JDK8 does not support
diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpConfiguration.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpConfiguration.java
index e957143cd6ee85..8b62916ecf73f3 100644
--- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpConfiguration.java
+++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpConfiguration.java
@@ -245,6 +245,12 @@ public class HttpConfiguration {
     @ConfigItem
     public Optional<PayloadHint> unhandledErrorContentTypeDefault;
 
+    /**
+     * Additional HTTP Headers always sent in the response
+     */
+    @ConfigItem
+    public Map<String, String> headers;
+
     public ProxyConfig proxy;
 
     public int determinePort(LaunchMode launchMode) {
diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java
index 34c916ad5d043b..85f94367495a6f 100644
--- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java
+++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java
@@ -360,6 +360,17 @@ public void handle(Void e) {
                 }
             });
         }
+        // Headers sent on any request, regardless of the response
+        Map<String, String> headers = httpConfiguration.headers;
+        if (!headers.isEmpty()) {
+            httpRouteRouter.route().order(-1).handler(new Handler<RoutingContext>() {
+                @Override
+                public void handle(RoutingContext event) {
+                    event.response().headers().addAll(headers);
+                    event.next();
+                }
+            });
+        }
 
         Handler<HttpServerRequest> root;
         if (rootPath.equals("/")) {
diff --git a/integration-tests/vertx-http/src/main/java/io/quarkus/it/vertx/SimpleResource.java b/integration-tests/vertx-http/src/main/java/io/quarkus/it/vertx/SimpleResource.java
index 39571998edd90f..32c1fb948c8e19 100644
--- a/integration-tests/vertx-http/src/main/java/io/quarkus/it/vertx/SimpleResource.java
+++ b/integration-tests/vertx-http/src/main/java/io/quarkus/it/vertx/SimpleResource.java
@@ -2,6 +2,7 @@
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
 
 /**
  *
@@ -13,4 +14,16 @@ public class SimpleResource {
     public String accessLogTest() {
         return "passed";
     }
+
+    @GET
+    @Path("/headers")
+    public String headers() {
+        return "ok";
+    }
+
+    @GET
+    @Path("/headers-override")
+    public Response headersOverride() {
+        return Response.ok("ok").header("foo", "abc").build();
+    }
 }
diff --git a/integration-tests/vertx-http/src/main/resources/application.properties b/integration-tests/vertx-http/src/main/resources/application.properties
index dbdf680151b6e4..78cc3afa2b2151 100644
--- a/integration-tests/vertx-http/src/main/resources/application.properties
+++ b/integration-tests/vertx-http/src/main/resources/application.properties
@@ -11,4 +11,5 @@ quarkus.http.access-log.enabled=true
 quarkus.http.access-log.log-to-file=true
 quarkus.http.access-log.base-file-name=quarkus-access-log
 quarkus.http.access-log.log-directory=target
-quarkus.native.additional-build-args=-H:IncludeResources=.*\\.jks,-H:EnableURLProtocols=http\\,https
\ No newline at end of file
+quarkus.http.headers.foo=bar
+quarkus.native.additional-build-args=-H:IncludeResources=.*\\.jks,-H:EnableURLProtocols=http\\,https
diff --git a/integration-tests/vertx-http/src/test/java/io/quarkus/it/vertx/HeadersTestCase.java b/integration-tests/vertx-http/src/test/java/io/quarkus/it/vertx/HeadersTestCase.java
new file mode 100644
index 00000000000000..ef8d611d5aaae2
--- /dev/null
+++ b/integration-tests/vertx-http/src/test/java/io/quarkus/it/vertx/HeadersTestCase.java
@@ -0,0 +1,32 @@
+package io.quarkus.it.vertx;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.is;
+
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+
+@QuarkusTest
+public class HeadersTestCase {
+
+    @Test
+    void testAdditionalHeaders() {
+        given()
+                .get("/simple/headers")
+                .then()
+                .header("foo", is("bar"))
+                .body(is("ok"));
+
+    }
+
+    @Test
+    void testAdditionalHeadersOverride() {
+        given()
+                .get("/simple/headers-override")
+                .then()
+                .header("foo", is("abc"))
+                .body(is("ok"));
+
+    }
+}