Repository: quarkusio/quarkus
Issue: Redirect for /metrics sub paths is not working

Redirect for /metrics sub paths is not working

http://127.0.0.1:8080/metrics after merging https://github.com/quarkusio/quarkus/pull/13601 gets redirected to http://127.0.0.1:8080/q/metrics

But that redirect is not working for `/metrics` sub paths, 404 Not Found is returned

`/metrics` sub path:
```
curl -v http://127.0.0.1:8080/metrics/application
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /metrics/application HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Content-Length: 0
< Content-Type: application/json
<
* Connection #0 to host 127.0.0.1 left intact
* Closing connection 0
```

`/metrics` path:
```
 curl -v http://127.0.0.1:8080/metrics
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /metrics HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< location: http://127.0.0.1:8080/q/metrics
< content-length: 0
<
* Connection #0 to host 127.0.0.1 left intact
* Closing connection 0
```

Changed files:
integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java
extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java

diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
index 7f1a38cc0d7..920981089dc 100644
--- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
+++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/VertxHttpProcessor.java
@@ -130,22 +130,25 @@ VertxWebRouterBuildItem initializeRouter(VertxHttpRecorder recorder,
         RuntimeValue<Router> router = recorder.initializeRouter(vertx.getVertx());
         RuntimeValue<Router> frameworkRouter = recorder.initializeRouter(vertx.getVertx());
         boolean frameworkRouterFound = false;
+        recorder.setNonApplicationRedirectHandler(nonApplicationRootPath.getFrameworkRootPath());
 
         for (RouteBuildItem route : routes) {
             if (nonApplicationRootPath.isSeparateRoot() && route.isFrameworkRoute()) {
                 frameworkRouterFound = true;
                 recorder.addRoute(frameworkRouter, route.getRouteFunction(), route.getHandler(), route.getType());
+
+                // Handle redirects from old paths to new non application endpoint root
+                if (httpBuildTimeConfig.redirectToNonApplicationRootPath) {
+                    recorder.addRoute(router, route.getRouteFunction(),
+                            recorder.getNonApplicationRedirectHandler(),
+                            route.getType());
+                }
             } else {
                 recorder.addRoute(router, route.getRouteFunction(), route.getHandler(), route.getType());
             }
         }
 
-        if (frameworkRouterFound && nonApplicationRootPath.isSeparateRoot()) {
-            // Handle redirects from old paths to new non application endpoint root
-            if (httpBuildTimeConfig.redirectToNonApplicationRootPath) {
-                recorder.addNonApplicationPathRedirect(router, frameworkRouter, nonApplicationRootPath.getFrameworkRootPath());
-            }
-
+        if (frameworkRouterFound) {
             frameworkRouterBuildProducer.produce(new VertxNonApplicationRouterBuildItem(frameworkRouter));
         }
 
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 81c4eebbac6..351a031ee4b 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
@@ -120,6 +120,8 @@ public class VertxHttpRecorder {
 
     private static volatile Handler<HttpServerRequest> rootHandler;
 
+    private static volatile Handler<RoutingContext> nonApplicationRedirectHandler;
+
     private static volatile int actualHttpPort = -1;
     private static volatile int actualHttpsPort = -1;
 
@@ -798,11 +800,8 @@ public void addRoute(RuntimeValue<Router> router, Function<Router, Route> route,
         }
     }
 
-    public void addNonApplicationPathRedirect(RuntimeValue<Router> mainRouter, RuntimeValue<Router> nonApplicationRouter,
-            String nonApplicationPath) {
-        List<Route> allRoutes = nonApplicationRouter.getValue().getRoutes();
-
-        Handler<RoutingContext> handler = new Handler<RoutingContext>() {
+    public void setNonApplicationRedirectHandler(String nonApplicationPath) {
+        nonApplicationRedirectHandler = new Handler<RoutingContext>() {
             @Override
             public void handle(RoutingContext context) {
                 String absoluteURI = context.request().absoluteURI();
@@ -816,10 +815,10 @@ public void handle(RoutingContext context) {
                         .end();
             }
         };
+    }
 
-        for (Route route : allRoutes) {
-            addRoute(mainRouter, router -> router.route(route.getPath()), handler, HandlerType.NORMAL);
-        }
+    public Handler<RoutingContext> getNonApplicationRedirectHandler() {
+        return nonApplicationRedirectHandler;
     }
 
     public GracefulShutdownFilter createGracefulShutdownHandler() {
diff --git a/integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java b/integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java
index 0ffc3daec8c..3f4e20f9829 100644
--- a/integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java
+++ b/integration-tests/smallrye-metrics/src/test/java/io/quarkus/it/metrics/MetricsTestCase.java
@@ -101,6 +101,13 @@ public void testScopes() {
         RestAssured.when().get("/q/metrics/application").then().statusCode(200);
     }
 
+    @Test
+    public void testScopesRedirect() {
+        RestAssured.when().get("/metrics/base").then().statusCode(200);
+        RestAssured.when().get("/metrics/vendor").then().statusCode(200);
+        RestAssured.when().get("/metrics/application").then().statusCode(200);
+    }
+
     @Test
     public void testMetricWithAbsoluteName() {
         invokeCounterWithAbsoluteName();