Repository: vert-x3/vertx-web
Issue: StatusCode still remains -1 when catching a runtime exception

### Questions

The status code in failure handler remains -1 when catching a runtime exception

### Version

3.9.2, 4.0.0beta1

### Do you have a reproducer?

try this example:
```java
Route route1 = router.get("/somepath/path1/");
route1.handler(ctx -> {
  // Let's say this throws a RuntimeException
  throw new RuntimeException("something happened!");
});

// Define a failure handler
// This will get called for any failures in the above handlers
Route route3 = router.get("/somepath/*");
route3.failureHandler(failureRoutingContext -> {
  int statusCode = failureRoutingContext.statusCode();
  System.out.println(statusCode); //remains -1 here
  // Status code should be 500 for the RuntimeException
  HttpServerResponse response = failureRoutingContext.response();
  response.setStatusCode(statusCode).end("Sorry! Not today");
});
```


Changed files:
vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java, vertx-web/src/test/java/io/vertx/ext/web/SubRouterTest.java, vertx-web/src/main/java/io/vertx/ext/web/handler/impl/ErrorHandlerImpl.java, vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextImpl.java

diff --git a/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/ErrorHandlerImpl.java b/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/ErrorHandlerImpl.java
index 948941020..2c35e033a 100644
--- a/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/ErrorHandlerImpl.java
+++ b/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/ErrorHandlerImpl.java
@@ -16,9 +16,6 @@
 
 package io.vertx.ext.web.handler.impl;
 
-import java.util.List;
-import java.util.Objects;
-
 import io.vertx.core.http.HttpHeaders;
 import io.vertx.core.http.HttpServerResponse;
 import io.vertx.core.json.JsonArray;
@@ -28,6 +25,9 @@ import io.vertx.ext.web.RoutingContext;
 import io.vertx.ext.web.handler.ErrorHandler;
 import io.vertx.ext.web.impl.Utils;
 
+import java.util.List;
+import java.util.Objects;
+
 /**
  * @author <a href="http://pmlopes@gmail.com">Paulo Lopes</a>
  * @author <a href="http://tfox.org">Tim Fox</a>
@@ -58,48 +58,48 @@ public class ErrorHandlerImpl implements ErrorHandler {
     Throwable failure = context.failure();
 
     int errorCode = context.statusCode();
-    String errorMessage = null;
-    if (errorCode != -1) {
-      context.response().setStatusCode(errorCode);
-      errorMessage = context.response().getStatusMessage();
-    } else {
+
+    // force default error code
+    if (errorCode == -1) {
       errorCode = 500;
-      if (displayExceptionDetails) {
-        errorMessage = failure.getMessage();
-      }
-      if (errorMessage == null) {
-        errorMessage = "Internal Server Error";
+    }
+
+    response.setStatusCode(errorCode);
+    String errorMessage = response.getStatusMessage();
+
+    if (displayExceptionDetails) {
+      errorMessage = failure.getMessage();
+      if (errorMessage != null) {
+        // no new lines are allowed in the status message
+        errorMessage = errorMessage.replaceAll("\\\\r|\\\\n", " ");
+        // apply the newly desired message
+        response.setStatusMessage(errorMessage);
       }
-      // no new lines are allowed in the status message
-      response.setStatusMessage(errorMessage.replaceAll("\\\\r|\\\\n", " "));
     }
 
     answerWithError(context, errorCode, errorMessage);
   }
 
-  private void answerWithError(RoutingContext context, int errorCode, String errorMessage){
-    context.response().setStatusCode(errorCode);
-    if( !sendErrorResponseMIME(context, errorCode, errorMessage) &&
-        !sendErrorAcceptMIME(context, errorCode, errorMessage)
-      ){
+  private void answerWithError(RoutingContext context, int errorCode, String errorMessage) {
+    if (!sendErrorResponseMIME(context, errorCode, errorMessage) && !sendErrorAcceptMIME(context, errorCode, errorMessage)) {
       // fallback plain/text
       sendError(context, "text/plain", errorCode, errorMessage);
     }
   }
 
-  private boolean sendErrorResponseMIME(RoutingContext context, int errorCode, String errorMessage){
+  private boolean sendErrorResponseMIME(RoutingContext context, int errorCode, String errorMessage) {
     // does the response already set the mime type?
     String mime = context.response().headers().get(HttpHeaders.CONTENT_TYPE);
 
-    if(mime == null) {
+    if (mime == null) {
       // does the route have an acceptable content type?
       mime = context.getAcceptableContentType();
     }
-    
+
     return mime != null && sendError(context, mime, errorCode, errorMessage);
   }
 
-  private boolean sendErrorAcceptMIME(RoutingContext context, int errorCode, String errorMessage){
+  private boolean sendErrorAcceptMIME(RoutingContext context, int errorCode, String errorMessage) {
     // respect the client accept order
     List<MIMEHeader> acceptableMimes = context.parsedHeaders().accept();
 
@@ -120,11 +120,11 @@ public class ErrorHandlerImpl implements ErrorHandler {
     if (mime.startsWith("text/html")) {
       StringBuilder stack = new StringBuilder();
       if (context.failure() != null && displayExceptionDetails) {
-        for (StackTraceElement elem: context.failure().getStackTrace()) {
+        for (StackTraceElement elem : context.failure().getStackTrace()) {
           stack.append("<li>").append(elem).append("</li>");
         }
       }
-      response.putHeader(HttpHeaders.CONTENT_TYPE,"text/html");
+      response.putHeader(HttpHeaders.CONTENT_TYPE, "text/html");
       response.end(
         errorTemplate.replace("{title}", title)
           .replace("{errorCode}", Integer.toString(errorCode))
@@ -139,7 +139,7 @@ public class ErrorHandlerImpl implements ErrorHandler {
       jsonError.put("error", new JsonObject().put("code", errorCode).put("message", errorMessage));
       if (context.failure() != null && displayExceptionDetails) {
         JsonArray stack = new JsonArray();
-        for (StackTraceElement elem: context.failure().getStackTrace()) {
+        for (StackTraceElement elem : context.failure().getStackTrace()) {
           stack.add(elem.toString());
         }
         jsonError.put("stack", stack);
@@ -157,7 +157,7 @@ public class ErrorHandlerImpl implements ErrorHandler {
       sb.append(": ");
       sb.append(errorMessage);
       if (context.failure() != null && displayExceptionDetails) {
-        for (StackTraceElement elem: context.failure().getStackTrace()) {
+        for (StackTraceElement elem : context.failure().getStackTrace()) {
           sb.append("\\tat ").append(elem).append("\\n");
         }
       }
diff --git a/vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextImpl.java b/vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextImpl.java
index f11afb8f8..8dc8f729e 100644
--- a/vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextImpl.java
+++ b/vertx-web/src/main/java/io/vertx/ext/web/impl/RoutingContextImpl.java
@@ -163,7 +163,11 @@ public class RoutingContextImpl extends RoutingContextImplBase {
 
   @Override
   public void fail(Throwable t) {
-    this.fail(-1, t);
+    if (t instanceof HttpStatusException) {
+      this.fail(((HttpStatusException) t).getStatusCode(), t);
+    } else {
+      this.fail(500, t);
+    }
   }
 
   @Override
diff --git a/vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java b/vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java
index 354ce7837..fb10dc6db 100644
--- a/vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java
+++ b/vertx-web/src/test/java/io/vertx/ext/web/RouterTest.java
@@ -616,7 +616,7 @@ public class RouterTest extends WebTestBase {
     String path = "/blah";
     Throwable failure = new Throwable();
     router.route(path).handler(rc -> rc.fail(failure)).failureHandler(frc -> {
-      assertEquals(-1, frc.statusCode());
+      assertEquals(500, frc.statusCode());
       assertSame(failure, frc.failure());
       frc.response().setStatusCode(500).setStatusMessage("Internal Server Error").end();
     });
@@ -627,7 +627,7 @@ public class RouterTest extends WebTestBase {
   public void testFailureWithNullThrowable() throws Exception {
     String path = "/blah";
     router.route(path).handler(rc -> rc.fail(null)).failureHandler(frc -> {
-      assertEquals(-1, frc.statusCode());
+      assertEquals(500, frc.statusCode());
       assertTrue(frc.failure() instanceof NullPointerException);
       frc.response().setStatusCode(500).setStatusMessage("Internal Server Error").end();
     });
@@ -2767,4 +2767,27 @@ public class RouterTest extends WebTestBase {
 
     testRequest(HttpMethod.MKCOL, "/", 200, "socks");
   }
+
+  @Test
+  public void testStatusCodeUncatchedException() throws Exception {
+    Route route1 = router.get("/somepath/path1");
+    route1.handler(ctx -> {
+      // Let's say this throws a RuntimeException
+      throw new RuntimeException("something happened!");
+    });
+
+// Define a failure handler
+// This will get called for any failures in the above handlers
+    Route route3 = router.get("/somepath/*");
+    route3.failureHandler(failureRoutingContext -> {
+      int statusCode = failureRoutingContext.statusCode();
+      // Status code should be 500 for the RuntimeException
+      assertEquals(500, statusCode);
+      HttpServerResponse response = failureRoutingContext.response();
+      response.setStatusCode(statusCode).end("Sorry! Not today");
+    });
+
+    testRequest(HttpMethod.GET, "/somepath/path1", 500, "Internal Server Error");
+
+  }
 }
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 4b9e87aad..a6ee31031 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
@@ -310,7 +310,7 @@ public class SubRouterTest extends WebTestBase {
     });
 
     router.route("/subpath/*").failureHandler(rc -> {
-      assertEquals(-1, rc.statusCode());
+      assertEquals(500, rc.statusCode());
       assertEquals("Balderdash!", rc.failure().getMessage());
       rc.response().setStatusCode(555).setStatusMessage("Badgers").end();
     });
@@ -329,7 +329,7 @@ public class SubRouterTest extends WebTestBase {
     });
 
     subRouter.route("/foo/*").failureHandler(rc -> {
-      assertEquals(-1, rc.statusCode());
+      assertEquals(500, rc.statusCode());
       assertEquals("Balderdash!", rc.failure().getMessage());
       rc.response().setStatusCode(555).setStatusMessage("Badgers").end();
     });