Repository: eclipse-vertx/vert.x

Problem statement:
How to capture http request in vertx?
A code like this not works
![image](https://cloud.githubusercontent.com/assets/9106804/25076246/8b410bc0-2351-11e7-9ba1-159701ee2ee4.png)

But this works.
![image](https://cloud.githubusercontent.com/assets/9106804/25076255/9acd0e5e-2351-11e7-9ad6-03e8a915ffe2.png)

Anyone can help me?
Thanks.

I am using fiddler to capture this traffic and my vertx version is 3.2.1



Hints:
vertx http client has a proxy settings on its own - did you try use those instead of setting the system properties?  something like: 

```java 
vertx.createHttpClient(new HttpClientOptions()
    .setProxyOptions(new ProxyOptions()
        .setPort(9999).setHost("localhost")))
```
this works in 3.4.1 but not works for 3.2.1. thanks for you answer~

Patch:
diff --git a/src/main/java/io/vertx/core/http/impl/Http1xConnectionBase.java b/src/main/java/io/vertx/core/http/impl/Http1xConnectionBase.java
--- a/src/main/java/io/vertx/core/http/impl/Http1xConnectionBase.java
+++ b/src/main/java/io/vertx/core/http/impl/Http1xConnectionBase.java
@@ -119,17 +119,17 @@ public HttpConnection goAwayHandler(@Nullable Handler<GoAway> handler) {
 
   @Override
   public HttpConnection shutdownHandler(@Nullable Handler<Void> handler) {
-    throw new UnsupportedOperationException("HTTP/1.x connections don't support GOAWAY");
+    throw new UnsupportedOperationException("HTTP/1.x connections cannot be shutdown");
   }
 
   @Override
   public void shutdown(long timeout, Handler<AsyncResult<Void>> handler) {
-    throw new UnsupportedOperationException("HTTP/1.x connections don't support GOAWAY");
+    throw new UnsupportedOperationException("HTTP/1.x connections cannot be shutdown");
   }
 
   @Override
   public Future<Void> shutdown(long timeoutMs) {
-    throw new UnsupportedOperationException("HTTP/1.x connections don't support GOAWAY");
+    throw new UnsupportedOperationException("HTTP/1.x connections cannot be shutdown");
   }
 
   @Override
diff --git a/src/main/java/io/vertx/core/http/impl/Http2UpgradedClientConnection.java b/src/main/java/io/vertx/core/http/impl/Http2UpgradedClientConnection.java
--- a/src/main/java/io/vertx/core/http/impl/Http2UpgradedClientConnection.java
+++ b/src/main/java/io/vertx/core/http/impl/Http2UpgradedClientConnection.java
@@ -99,10 +99,12 @@ public long lastResponseReceivedTimestamp() {
    * The first stream that will send the request using HTTP/1, upgrades the connection when the protocol
    * switches and receives the response with HTTP/2 frames.
    */
-  private class UpgradingStream implements HttpClientStream {
+  private static class UpgradingStream implements HttpClientStream {
 
-    private final Http1xClientConnection conn;
-    private final HttpClientStream stream;
+    private final Http1xClientConnection upgradingConnection;
+    private final HttpClientStream upgradingStream;
+    private final Http2UpgradedClientConnection upgradedConnection;
+    private HttpClientStream upgradedStream;
     private Handler<HttpResponseHead> headHandler;
     private Handler<Buffer> chunkHandler;
     private Handler<MultiMap> endHandler;
@@ -113,16 +115,16 @@ private class UpgradingStream implements HttpClientStream {
     private Handler<HttpClientPush> pushHandler;
     private Handler<HttpFrame> unknownFrameHandler;
     private Handler<Void> closeHandler;
-    private HttpClientStream upgradedStream;
 
-    UpgradingStream(HttpClientStream stream, Http1xClientConnection conn) {
-      this.conn = conn;
-      this.stream = stream;
+    UpgradingStream(HttpClientStream stream, Http2UpgradedClientConnection upgradedConnection, Http1xClientConnection upgradingConnection) {
+      this.upgradedConnection = upgradedConnection;
+      this.upgradingConnection = upgradingConnection;
+      this.upgradingStream = stream;
     }
 
     @Override
     public HttpClientConnection connection() {
-      return Http2UpgradedClientConnection.this;
+      return upgradedConnection;
     }
 
     /**
@@ -136,7 +138,7 @@ public void writeHead(HttpRequestHead request,
                           StreamPriority priority,
                           boolean connect,
                           Handler<AsyncResult<Void>> handler) {
-      ChannelPipeline pipeline = conn.channel().pipeline();
+      ChannelPipeline pipeline = upgradingConnection.channel().pipeline();
       HttpClientCodec httpCodec = pipeline.get(HttpClientCodec.class);
 
       class UpgradeRequestHandler extends ChannelInboundHandlerAdapter {
@@ -146,7 +148,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc
           ChannelPipeline pipeline = ctx.pipeline();
           if (evt == HttpClientUpgradeHandler.UpgradeEvent.UPGRADE_SUCCESSFUL) {
             // Upgrade handler will remove itself and remove the HttpClientCodec
-            pipeline.remove(conn.channelHandlerContext().handler());
+            pipeline.remove(upgradingConnection.channelHandlerContext().handler());
           }
         }
 
@@ -164,15 +166,17 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
         }
       }
 
-      VertxHttp2ClientUpgradeCodec upgradeCodec = new VertxHttp2ClientUpgradeCodec(client.getOptions().getInitialSettings()) {
+      VertxHttp2ClientUpgradeCodec upgradeCodec = new VertxHttp2ClientUpgradeCodec(upgradedConnection.client.getOptions().getInitialSettings()) {
         @Override
         public void upgradeTo(ChannelHandlerContext ctx, FullHttpResponse upgradeResponse) throws Exception {
 
           // Now we need to upgrade this to an HTTP2
-          VertxHttp2ConnectionHandler<Http2ClientConnection> handler = Http2ClientConnection.createHttp2ConnectionHandler(client, conn.metrics, (EventLoopContext) conn.getContext(), current.metric(), conn -> {
-            conn.upgradeStream(stream.metric(), stream.getContext(), ar -> {
-              UpgradingStream.this.conn.closeHandler(null);
-              UpgradingStream.this.conn.exceptionHandler(null);
+          VertxHttp2ConnectionHandler<Http2ClientConnection> handler = Http2ClientConnection.createHttp2ConnectionHandler(upgradedConnection.client, upgradingConnection.metrics, (EventLoopContext) upgradingConnection.getContext(), upgradedConnection.current.metric(), conn -> {
+            conn.upgradeStream(upgradingStream.metric(), upgradingStream.getContext(), ar -> {
+              upgradingConnection.closeHandler(null);
+              upgradingConnection.exceptionHandler(null);
+              upgradingConnection.evictionHandler(null);
+              upgradingConnection.concurrencyChangeHandler(null);
               if (ar.succeeded()) {
                 upgradedStream = ar.result();
                 upgradedStream.headHandler(headHandler);
@@ -185,16 +189,16 @@ public void upgradeTo(ChannelHandlerContext ctx, FullHttpResponse upgradeRespons
                 upgradedStream.pushHandler(pushHandler);
                 upgradedStream.unknownFrameHandler(unknownFrameHandler);
                 upgradedStream.closeHandler(closeHandler);
-                stream.headHandler(null);
-                stream.chunkHandler(null);
-                stream.endHandler(null);
-                stream.priorityHandler(null);
-                stream.exceptionHandler(null);
-                stream.drainHandler(null);
-                stream.continueHandler(null);
-                stream.pushHandler(null);
-                stream.unknownFrameHandler(null);
-                stream.closeHandler(null);
+                upgradingStream.headHandler(null);
+                upgradingStream.chunkHandler(null);
+                upgradingStream.endHandler(null);
+                upgradingStream.priorityHandler(null);
+                upgradingStream.exceptionHandler(null);
+                upgradingStream.drainHandler(null);
+                upgradingStream.continueHandler(null);
+                upgradingStream.pushHandler(null);
+                upgradingStream.unknownFrameHandler(null);
+                upgradingStream.closeHandler(null);
                 headHandler = null;
                 chunkHandler = null;
                 endHandler = null;
@@ -204,15 +208,24 @@ public void upgradeTo(ChannelHandlerContext ctx, FullHttpResponse upgradeRespons
                 continueHandler = null;
                 pushHandler = null;
                 closeHandler = null;
-                current = conn;
-                conn.closeHandler(closeHandler);
-                conn.exceptionHandler(exceptionHandler);
-                conn.pingHandler(pingHandler);
-                conn.goAwayHandler(goAwayHandler);
-                conn.shutdownHandler(shutdownHandler);
-                conn.remoteSettingsHandler(remoteSettingsHandler);
-                conn.evictionHandler(evictionHandler);
-                conn.concurrencyChangeHandler(concurrencyChangeHandler);
+                upgradedConnection.current = conn;
+                conn.closeHandler(upgradedConnection.closeHandler);
+                conn.exceptionHandler(upgradedConnection.exceptionHandler);
+                conn.pingHandler(upgradedConnection.pingHandler);
+                conn.goAwayHandler(upgradedConnection.goAwayHandler);
+                conn.shutdownHandler(upgradedConnection.shutdownHandler);
+                conn.remoteSettingsHandler(upgradedConnection.remoteSettingsHandler);
+                conn.evictionHandler(upgradedConnection.evictionHandler);
+                conn.concurrencyChangeHandler(upgradedConnection.concurrencyChangeHandler);
+                Handler<Long> concurrencyChangeHandler = upgradedConnection.concurrencyChangeHandler;
+                upgradedConnection.closeHandler = null;
+                upgradedConnection.exceptionHandler = null;
+                upgradedConnection.pingHandler = null;
+                upgradedConnection.goAwayHandler = null;
+                upgradedConnection.shutdownHandler = null;
+                upgradedConnection.remoteSettingsHandler = null;
+                upgradedConnection.evictionHandler = null;
+                upgradedConnection.concurrencyChangeHandler = null;
                 concurrencyChangeHandler.handle(conn.concurrency());
               } else {
                 // Handle me
@@ -220,7 +233,7 @@ public void upgradeTo(ChannelHandlerContext ctx, FullHttpResponse upgradeRespons
               }
             });
           });
-          conn.channel().pipeline().addLast(handler);
+          upgradingConnection.channel().pipeline().addLast(handler);
           handler.clientUpgrade(ctx);
         }
       };
@@ -307,11 +320,11 @@ private void doWriteHead(HttpRequestHead head,
                              StreamPriority priority,
                              boolean connect,
                              Handler<AsyncResult<Void>> handler) {
-      EventExecutor exec = conn.channelHandlerContext().executor();
+      EventExecutor exec = upgradingConnection.channelHandlerContext().executor();
       if (exec.inEventLoop()) {
-        stream.writeHead(head, chunked, buf, end, priority, connect, handler);
+        upgradingStream.writeHead(head, chunked, buf, end, priority, connect, handler);
         if (end) {
-          ChannelPipeline pipeline = conn.channelHandlerContext().pipeline();
+          ChannelPipeline pipeline = upgradingConnection.channelHandlerContext().pipeline();
           pipeline.fireUserEventTriggered(SEND_BUFFERED_MESSAGES);
         }
       } else {
@@ -326,21 +339,21 @@ public int id() {
 
     @Override
     public Object metric() {
-      return stream.metric();
+      return upgradingStream.metric();
     }
 
     @Override
     public HttpVersion version() {
       HttpClientStream s = upgradedStream;
       if (s == null) {
-        s = stream;
+        s = upgradingStream;
       }
       return s.version();
     }
 
     @Override
     public ContextInternal getContext() {
-      return stream.getContext();
+      return upgradingStream.getContext();
     }
 
     @Override
@@ -348,7 +361,7 @@ public void continueHandler(Handler<Void> handler) {
       if (upgradedStream != null) {
         upgradedStream.continueHandler(handler);
       } else {
-        stream.continueHandler(handler);
+        upgradingStream.continueHandler(handler);
         continueHandler = handler;
       }
     }
@@ -358,7 +371,7 @@ public void pushHandler(Handler<HttpClientPush> handler) {
       if (pushHandler != null) {
         upgradedStream.pushHandler(handler);
       } else {
-        stream.pushHandler(handler);
+        upgradingStream.pushHandler(handler);
         pushHandler = handler;
       }
     }
@@ -368,7 +381,7 @@ public void closeHandler(Handler<Void> handler) {
       if (closeHandler != null) {
         upgradedStream.closeHandler(handler);
       } else {
-        stream.closeHandler(handler);
+        upgradingStream.closeHandler(handler);
         closeHandler = handler;
       }
     }
@@ -378,7 +391,7 @@ public void drainHandler(Handler<Void> handler) {
       if (upgradedStream != null) {
         upgradedStream.drainHandler(handler);
       } else {
-        stream.drainHandler(handler);
+        upgradingStream.drainHandler(handler);
         drainHandler = handler;
       }
     }
@@ -388,7 +401,7 @@ public void exceptionHandler(Handler<Throwable> handler) {
       if (upgradedStream != null) {
         upgradedStream.exceptionHandler(handler);
       } else {
-        stream.exceptionHandler(handler);
+        upgradingStream.exceptionHandler(handler);
         exceptionHandler = handler;
       }
     }
@@ -398,7 +411,7 @@ public void headHandler(Handler<HttpResponseHead> handler) {
       if (upgradedStream != null) {
         upgradedStream.headHandler(handler);
       } else {
-        stream.headHandler(handler);
+        upgradingStream.headHandler(handler);
         headHandler = handler;
       }
     }
@@ -408,7 +421,7 @@ public void chunkHandler(Handler<Buffer> handler) {
       if (upgradedStream != null) {
         upgradedStream.chunkHandler(handler);
       } else {
-        stream.chunkHandler(handler);
+        upgradingStream.chunkHandler(handler);
         chunkHandler = handler;
       }
     }
@@ -418,7 +431,7 @@ public void endHandler(Handler<MultiMap> handler) {
       if (upgradedStream != null) {
         upgradedStream.endHandler(handler);
       } else {
-        stream.endHandler(handler);
+        upgradingStream.endHandler(handler);
         endHandler = handler;
       }
     }
@@ -428,7 +441,7 @@ public void unknownFrameHandler(Handler<HttpFrame> handler) {
       if (upgradedStream != null) {
         upgradedStream.unknownFrameHandler(handler);
       } else {
-        stream.unknownFrameHandler(handler);
+        upgradingStream.unknownFrameHandler(handler);
         unknownFrameHandler = handler;
       }
     }
@@ -438,18 +451,18 @@ public void priorityHandler(Handler<StreamPriority> handler) {
       if (upgradedStream != null) {
         upgradedStream.priorityHandler(handler);
       } else {
-        stream.priorityHandler(handler);
+        upgradingStream.priorityHandler(handler);
         priorityHandler = handler;
       }
     }
 
     @Override
     public void writeBuffer(ByteBuf buf, boolean end, Handler<AsyncResult<Void>> handler) {
-      EventExecutor exec = conn.channelHandlerContext().executor();
+      EventExecutor exec = upgradingConnection.channelHandlerContext().executor();
       if (exec.inEventLoop()) {
-        stream.writeBuffer(buf, end, handler);
+        upgradingStream.writeBuffer(buf, end, handler);
         if (end) {
-          ChannelPipeline pipeline = conn.channelHandlerContext().pipeline();
+          ChannelPipeline pipeline = upgradingConnection.channelHandlerContext().pipeline();
           pipeline.fireUserEventTriggered(SEND_BUFFERED_MESSAGES);
         }
       } else {
@@ -459,42 +472,42 @@ public void writeBuffer(ByteBuf buf, boolean end, Handler<AsyncResult<Void>> han
 
     @Override
     public void writeFrame(int type, int flags, ByteBuf payload) {
-      stream.writeFrame(type, flags, payload);
+      upgradingStream.writeFrame(type, flags, payload);
     }
 
     @Override
     public void doSetWriteQueueMaxSize(int size) {
-      stream.doSetWriteQueueMaxSize(size);
+      upgradingStream.doSetWriteQueueMaxSize(size);
     }
 
     @Override
     public boolean isNotWritable() {
-      return stream.isNotWritable();
+      return upgradingStream.isNotWritable();
     }
 
     @Override
     public void doPause() {
-      stream.doPause();
+      upgradingStream.doPause();
     }
 
     @Override
     public void doFetch(long amount) {
-      stream.doFetch(amount);
+      upgradingStream.doFetch(amount);
     }
 
     @Override
     public void reset(Throwable cause) {
-      stream.reset(cause);
+      upgradingStream.reset(cause);
     }
 
     @Override
     public StreamPriority priority() {
-      return stream.priority();
+      return upgradingStream.priority();
     }
 
     @Override
     public void updatePriority(StreamPriority streamPriority) {
-      stream.updatePriority(streamPriority);
+      upgradingStream.updatePriority(streamPriority);
     }
   }
 
@@ -504,7 +517,7 @@ public void createStream(ContextInternal context, Handler<AsyncResult<HttpClient
       current.createStream(context, ar -> {
         if (ar.succeeded()) {
           HttpClientStream stream = ar.result();
-          UpgradingStream upgradingStream = new UpgradingStream(stream, (Http1xClientConnection) current);
+          UpgradingStream upgradingStream = new UpgradingStream(stream, this, (Http1xClientConnection) current);
           handler.handle(Future.succeededFuture(upgradingStream));
         } else {
           handler.handle(ar);
@@ -520,20 +533,6 @@ public ContextInternal getContext() {
     return current.getContext();
   }
 
-  @Override
-  public HttpConnection closeHandler(Handler<Void> handler) {
-    closeHandler = handler;
-    current.closeHandler(handler);
-    return this;
-  }
-
-  @Override
-  public HttpConnection exceptionHandler(Handler<Throwable> handler) {
-    exceptionHandler = handler;
-    current.exceptionHandler(handler);
-    return this;
-  }
-
   @Override
   public HttpConnection remoteSettingsHandler(Handler<Http2Settings> handler) {
     if (current instanceof Http1xClientConnection) {
@@ -574,13 +573,30 @@ public HttpConnection shutdownHandler(@Nullable Handler<Void> handler) {
     return this;
   }
 
+  @Override
+  public HttpConnection closeHandler(Handler<Void> handler) {
+    if (current instanceof Http1xClientConnection) {
+      closeHandler = handler;
+    }
+    current.closeHandler(handler);
+    return this;
+  }
+
+  @Override
+  public HttpConnection exceptionHandler(Handler<Throwable> handler) {
+    if (current instanceof Http1xClientConnection) {
+      exceptionHandler = handler;
+    }
+    current.exceptionHandler(handler);
+    return this;
+  }
+
   @Override
   public HttpClientConnection evictionHandler(Handler<Void> handler) {
     if (current instanceof Http1xClientConnection) {
       evictionHandler = handler;
-    } else {
-      current.evictionHandler(handler);
     }
+    current.evictionHandler(handler);
     return this;
   }
 
@@ -588,9 +604,8 @@ public HttpClientConnection evictionHandler(Handler<Void> handler) {
   public HttpClientConnection concurrencyChangeHandler(Handler<Long> handler) {
     if (current instanceof Http1xClientConnection) {
       concurrencyChangeHandler = handler;
-    } else {
-      current.concurrencyChangeHandler(handler);
     }
+    current.concurrencyChangeHandler(handler);
     return this;
   }
 


Test patch:
diff --git a/src/test/java/io/vertx/core/http/Http2Test.java b/src/test/java/io/vertx/core/http/Http2Test.java
--- a/src/test/java/io/vertx/core/http/Http2Test.java
+++ b/src/test/java/io/vertx/core/http/Http2Test.java
@@ -930,4 +930,36 @@ public void testAppendToHttpChunks() throws Exception {
     }));
     await();
   }
+
+  @Test
+  public void testNonUpgradedH2CConnectionIsEvictedFromThePool() {
+    client.close();
+    client = vertx.createHttpClient(new HttpClientOptions().setProtocolVersion(HttpVersion.HTTP_2));
+    server.close();
+    System.setProperty("vertx.disableH2c", "true");
+    server = vertx.createHttpServer();
+    try {
+      server.requestHandler(req -> req.response().end());
+      server.listen(testAddress, onSuccess(s -> {
+        Promise<Void> promise = Promise.promise();
+        client.request(requestOptions).compose(req -> {
+          req.connection().closeHandler(v -> {
+            promise.complete();
+          });
+          return req.send().compose(HttpClientResponse::body);
+        }).onSuccess(b -> {
+          server.close()
+            .compose(r -> promise.future())
+            .compose(a -> server.listen(testAddress)).onComplete(onSuccess(v -> {
+            client.request(requestOptions).compose(req -> req.send().compose(HttpClientResponse::body)).onSuccess(b2 -> {
+              testComplete();
+            });
+          }));
+        });
+      }));
+      await();
+    } finally {
+      System.clearProperty("vertx.disableH2c");
+    }
+  }
 }