Repository: vert-x3/vertx-web
Issue: SubRouter Mount acting as Exact Path

### 3.8.4

* vert.x web:

### Context

The handlers mounted on sub-router are ignored when the mount point is `"/"`. 
`router.mountSubRouter("/", subRouter);`
Note that, we can't have empty string as mount point.

It was functional until v3.8.1. With v3.8.4 it behaves as exactMatch and ending with slash.

Below table shows the difference between 3.8.1 and 3.8.4 based on the reproducer shared below:

| Path | v3.8.1 | v3.8.4 |
| --- | --- | --- |
| /primary | Success | Resource Not Found |
| /primary?query | Success | Resource Not Found |
| /primary/ | Success | Success |
| /primary/random | Resource Not Found | Resource Not Found |
| With subrouter mounted at `/abc`|
| /primary/abc | Success | Success |
| /primary/abc/ | Success | Success |
| /primary/abc?query | Success | Success |

### Do you have a reproducer?

* https://github.com/ramtech123/pocs/tree/master/vertx-subrouter-test

### Steps to reproduce

By default, Vertx version is set to 3.8.4 in the reproducer. Change it to 3.8.1 to verify the behavior.

1. Build and run the `RouterTestMain` given in the reproducer. Server will start listening on 8443
2. Curl the given paths to observe the behavior. Ex: `curl http://localhost:8443/primary?query`

### References

I have gone through below issues, wondering if this change was intended?
 - https://github.com/vert-x3/vertx-web/issues/1435
 - https://github.com/vert-x3/vertx-web/issues/1441

### Extra

First two scenarios return success response in v3.8.4 also if we attach the handlers directly to the primary router instead of sub router (set `useSubRouters` flag in RouterTestServer.java to `false` to verify the behavior).

However, raising this ticket as the behavior of sub router mounting has changed.


Changed files:
vertx-web/src/test/java/io/vertx/ext/web/SubRouterTest.java, vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextWrapper.java

diff --git a/vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextWrapper.java b/vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextWrapper.java
index 9d8360619..19d777bae 100644
--- a/vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextWrapper.java
+++ b/vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextWrapper.java
@@ -51,11 +51,12 @@ public class RoutingContextWrapper extends RoutingContextImplBase {
       // just use the override
       this.mountPoint = mountPoint;
     } else {
-      if (parentMountPoint.charAt(parentMountPoint.length() - 1) == '/') {
-        // Remove the trailing slash or we won't match
-        this.mountPoint = parentMountPoint.substring(0, parentMountPoint.length() - 1) + mountPoint;
+      // special case: when a sub router is mounting on / basically it's telling
+      // that it wants to use the parent mount, otherwise it's extending the parent
+      // path
+      if ("/".equals(mountPoint)) {
+        this.mountPoint = parentMountPoint;
       } else {
-        // slashes are ok, just concat
         this.mountPoint = parentMountPoint + mountPoint;
       }
     }
diff --git a/vertx-web/src/test/java/io/vertx/ext/web/SubRouterTest.java b/vertx-web/src/test/java/io/vertx/ext/web/SubRouterTest.java
index cd6bfd044..3ed96dea1 100644
--- a/vertx-web/src/test/java/io/vertx/ext/web/SubRouterTest.java
+++ b/vertx-web/src/test/java/io/vertx/ext/web/SubRouterTest.java
@@ -572,4 +572,25 @@ public class SubRouterTest extends WebTestBase {
     testRequest(HttpMethod.POST, "/bank/order/deposit", 200, "OK");
     testRequest(HttpMethod.GET, "/bank/order/deposit", 405, "Method Not Allowed");
   }
+
+
+  @Test
+  public void testMountMultiLevel() throws Exception {
+    Router routerFirstLevel = Router.router(vertx);
+    router.mountSubRouter("/primary", routerFirstLevel);
+
+    Router routerSecondLevel = Router.router(vertx);
+    routerSecondLevel.get("/").handler(ctx -> {
+      ctx.response().setStatusMessage("Hi").end();
+    });
+    routerFirstLevel.mountSubRouter("/", routerSecondLevel);
+
+    // Below two scenarios will fail with 3.8.4 and higher, pass with 3.8.1 and lower.
+    testRequest(HttpMethod.GET, "/primary", 200, "Hi");
+    testRequest(HttpMethod.GET, "/primary?query=1", 200, "Hi");
+
+    // Below scenarios will pass
+    testRequest(HttpMethod.GET, "/primary/", 200, "Hi");
+    testRequest(HttpMethod.GET, "/primary/random", 404, "Not Found");
+  }
 }