Repository: eclipse-vertx/vert.x

Problem statement:
HttpServerRequest exception handler is not called when the connection is closed
`HttpServerRequest` extends `ReadStream<Buffer>`. When there is an ongoing file upload and the connection closes abruptly, the exception handler on the `HttpServerRequest` should be called to signal that the stream an error occured




Hints:
note : works with HTTP/2 not HTTP/1.x

Patch:
diff --git a/src/main/java/io/vertx/core/http/impl/ServerConnection.java b/src/main/java/io/vertx/core/http/impl/ServerConnection.java
--- a/src/main/java/io/vertx/core/http/impl/ServerConnection.java
+++ b/src/main/java/io/vertx/core/http/impl/ServerConnection.java
@@ -43,6 +43,7 @@
 import io.vertx.core.AsyncResult;
 import io.vertx.core.Handler;
 import io.vertx.core.Vertx;
+import io.vertx.core.VertxException;
 import io.vertx.core.buffer.Buffer;
 import io.vertx.core.http.HttpConnection;
 import io.vertx.core.http.HttpServerOptions;
@@ -345,6 +346,9 @@ synchronized protected void handleClosed() {
     if (ws != null) {
       ws.handleClosed();
     }
+    if (currentRequest != null) {
+      currentRequest.handleException(new VertxException("Connection was closed"));
+    }
     if (pendingResponse != null) {
       if (METRICS_ENABLED && metrics != null) {
         metrics.requestReset(requestMetric);


Test patch:
diff --git a/src/test/java/io/vertx/test/core/Http1xTest.java b/src/test/java/io/vertx/test/core/Http1xTest.java
--- a/src/test/java/io/vertx/test/core/Http1xTest.java
+++ b/src/test/java/io/vertx/test/core/Http1xTest.java
@@ -3397,7 +3397,7 @@ public void testInvalidTrailerInHttpServerRequest() throws Exception {
         so.write("01234567");
       }
     }, errors -> {
-      assertEquals(1, errors.size());
+      assertEquals(2, errors.size());
       assertEquals(TooLongFrameException.class, errors.get(0).getClass());
     });
   }
@@ -3407,7 +3407,7 @@ public void testInvalidChunkInHttpServerRequest() throws Exception {
     testHttpServerRequestDecodeError(so -> {
       so.write("invalid\r\n"); // Empty chunk
     }, errors -> {
-      assertEquals(1, errors.size());
+      assertEquals(2, errors.size());
       assertEquals(NumberFormatException.class, errors.get(0).getClass());
     });
   }
diff --git a/src/test/java/io/vertx/test/core/HttpTest.java b/src/test/java/io/vertx/test/core/HttpTest.java
--- a/src/test/java/io/vertx/test/core/HttpTest.java
+++ b/src/test/java/io/vertx/test/core/HttpTest.java
@@ -1304,6 +1304,26 @@ public void testNoExceptionHandlerCalledWhenResponseReceivedOK() throws Exceptio
     await();
   }
 
+  @Test
+  public void testServerRequestExceptionHandlerCalledWhenConnectionClosed() throws Exception {
+    CountDownLatch closeLatch = new CountDownLatch(1);
+    server.requestHandler(request -> {
+      request.exceptionHandler(err -> {
+        testComplete();
+      });
+      request.handler(buff -> {
+        closeLatch.countDown();
+      });
+    });
+    startServer();
+    AtomicReference<HttpConnection> conn = new AtomicReference<>();
+    client.post(DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, DEFAULT_TEST_URI, resp -> {
+    }).connectionHandler(conn::set).setChunked(true).write("some_chunk");
+    awaitLatch(closeLatch);
+    conn.get().close();
+    await();
+  }
+
   @Test
   public void testDefaultStatus() {
     testStatusCode(-1, null);