Repository: vert-x3/vertx-web
Issue: Pause/Resume missing in AuthorizationHandlerImpl? IllegalStateException: Request has already been read

### Version

4.1.0

### Context

When using async operations in implementations of `AuthorizationProvider.getAuthorizations` then a `BodyHandler` added after an `AuthorizationHandler` that uses that `AuthorizationProvider` (created with `AuthorizationHandler.create`) causes that requests with body may fail due to:

```
java.lang.IllegalStateException: Request has already been read
	at io.vertx.core.http.impl.Http1xServerRequest.checkEnded(Http1xServerRequest.java:627)
	at io.vertx.core.http.impl.Http1xServerRequest.handler(Http1xServerRequest.java:287)
	at io.vertx.ext.web.impl.HttpServerRequestWrapper.handler(HttpServerRequestWrapper.java:97)
	at io.vertx.ext.web.handler.impl.BodyHandlerImpl.handle(BodyHandlerImpl.java:85)
	at io.vertx.ext.web.handler.impl.BodyHandlerImpl.handle(BodyHandlerImpl.java:44)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1127)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:114)
	at io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201)
	at io.vertx.ext.web.handler.impl.AuthorizationHandlerImpl.checkOrFetchAuthorizations(AuthorizationHandlerImpl.java:79)
	at io.vertx.ext.web.handler.impl.AuthorizationHandlerImpl.lambda$checkOrFetchAuthorizations$0(AuthorizationHandlerImpl.java:99)
	at io.vertx.core.impl.future.FutureImpl$3.onSuccess(FutureImpl.java:124)
```

I have noticed that counter measures have been taken in `AuthenticationHandlerImpl` with this [commit]( https://github.com/vert-x3/vertx-web/commit/937d1e73bda0e90789a9ced17ec2c5a800bdbf0b#diff-5b9edb22f0e308c1a7a43e62f17550732cea30ff9215305686994ff27674975d) where `request.pause()` and `request.resume()` are utilized. Unfortunately - as implementer of an `AuthorizationProvider` I have no way of adding this functionality by myself without copying/extending `AuthorizationHandlerImpl`.


Changed files:
vertx-web/src/main/java/io/vertx/ext/web/handler/impl/AuthorizationHandlerImpl.java

diff --git a/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/AuthorizationHandlerImpl.java b/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/AuthorizationHandlerImpl.java
index bdb61f542..d735cf00a 100644
--- a/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/AuthorizationHandlerImpl.java
+++ b/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/AuthorizationHandlerImpl.java
@@ -53,10 +53,22 @@ public class AuthorizationHandlerImpl implements AuthorizationHandler {
     if (routingContext.user() == null) {
       routingContext.fail(FORBIDDEN_CODE, FORBIDDEN_EXCEPTION);
     } else {
-      // create the authorization context
-      AuthorizationContext authorizationContext = getAuthorizationContext(routingContext);
-      // check or fetch authorizations
-      checkOrFetchAuthorizations(routingContext, authorizationContext, authorizationProviders.iterator());
+      // before starting any potential async operation here
+      // pause parsing the request body. The reason is that
+      // we don't want to loose the body or protocol upgrades
+      // for async operations
+      routingContext.request().pause();
+
+      try {
+        // create the authorization context
+        AuthorizationContext authorizationContext = getAuthorizationContext(routingContext);
+        // check or fetch authorizations
+        checkOrFetchAuthorizations(routingContext, authorizationContext, authorizationProviders.iterator());
+      } catch (RuntimeException e) {
+        // resume as the error handler may allow this request to become valid again
+        routingContext.request().resume();
+        routingContext.fail(e);
+      }
     }
   }
 
@@ -76,10 +88,14 @@ public class AuthorizationHandlerImpl implements AuthorizationHandler {
    */
   private void checkOrFetchAuthorizations(RoutingContext routingContext, AuthorizationContext authorizationContext, Iterator<AuthorizationProvider> providers) {
     if (authorization.match(authorizationContext)) {
+      // resume the processing of the request
+      routingContext.request().resume();
       routingContext.next();
       return;
     }
     if (!providers.hasNext()) {
+      // resume as the error handler may allow this request to become valid again
+      routingContext.request().resume();
       routingContext.fail(FORBIDDEN_CODE, FORBIDDEN_EXCEPTION);
       return;
     }