Repository: eclipse-vertx/vert.x

Problem statement:
HttpClient drops original proxy on redirect
### Version

Which version(s) did you encounter this bug ?
`>= 4.x`

### Context

`RequestOptions` allows us to set a proxy per request, but upon redirect the original proxy gets lost

It also affects `WebClient`.

### Do you have a reproducer?

I have added tests for it in PR, just run `HttpTest`


Hints:

Patch:
diff --git a/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java b/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java
--- a/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java
+++ b/src/main/java/io/vertx/core/http/impl/HttpClientImpl.java
@@ -467,7 +467,10 @@ HttpClientRequest createRequest(HttpConnection connection, HttpClientStream stre
       request.redirectHandler(resp -> {
         Future<RequestOptions> fut_ = rHandler.apply(resp);
         if (fut_ != null) {
-          return fut_.compose(this::request);
+          return fut_.compose(o -> {
+            o.setProxyOptions(options.getProxyOptions());
+            return this.request(o);
+          });
         } else {
           return null;
         }


Test patch:
diff --git a/src/test/java/io/vertx/core/http/HttpTest.java b/src/test/java/io/vertx/core/http/HttpTest.java
--- a/src/test/java/io/vertx/core/http/HttpTest.java
+++ b/src/test/java/io/vertx/core/http/HttpTest.java
@@ -60,8 +60,10 @@
 import java.util.function.*;
 import java.util.stream.IntStream;
 
+import static io.vertx.core.http.HttpMethod.GET;
 import static io.vertx.core.http.HttpMethod.PUT;
 import static io.vertx.test.core.TestUtils.*;
+import static org.hamcrest.CoreMatchers.instanceOf;
 
 /**
  * @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
@@ -3726,6 +3728,55 @@ public void testFollowRedirectPutOn308() throws Exception {
     testFollowRedirect(HttpMethod.PUT, HttpMethod.PUT, 308, 308, 1, "http://" + DEFAULT_HTTP_HOST_AND_PORT + "/redirected", "http://" + DEFAULT_HTTP_HOST_AND_PORT + "/somepath");
   }
 
+
+  @Test
+  public void testFollowRedirectsWithProxy() throws Exception {
+    Assume.assumeThat("Proxy is only supported with HTTP/1", this, instanceOf(Http1xTest.class));
+    waitFor(2);
+    String location = "http://" + DEFAULT_HTTP_HOST + ":" + DEFAULT_HTTP_PORT + "/ok";
+    server.requestHandler(req -> {
+      if (!req.headers().contains("foo", "bar", true)) {
+        fail("Missing expected header");
+        return;
+      }
+      assertEquals(Collections.singletonList("bar"), req.headers().getAll("foo"));
+      if (req.path().equals("/redirect")) {
+        req.response().setStatusCode(301).putHeader("Location", location).end();
+      } else {
+        req.response().end(req.path());
+        complete();
+      }
+    });
+
+    startServer();
+    startProxy(null, ProxyType.HTTP);
+    client.request(
+        new RequestOptions(requestOptions)
+          .setServer(null)
+          .setMethod(GET)
+          .setURI("/redirect")
+          .setProxyOptions(new ProxyOptions().setPort(proxy.port()))
+      )
+      .compose(req -> req
+        .putHeader("foo", "bar")
+        .setFollowRedirects(true)
+        .send()
+        .compose(resp -> {
+          assertEquals(200, resp.statusCode());
+          assertEquals(location, proxy.getLastUri());
+          return resp.body().compose(body -> {
+            if (resp.statusCode() == 200) {
+              assertEquals(Buffer.buffer("/ok"), body);
+            } else {
+              assertEquals(Buffer.buffer(), body);
+            }
+            return Future.succeededFuture();
+          });
+        })
+      ).onSuccess(v -> testComplete());
+    await();
+  }
+
   private void testFollowRedirect(
       HttpMethod method,
       HttpMethod expectedMethod,
diff --git a/src/test/java/io/vertx/test/proxy/HttpProxy.java b/src/test/java/io/vertx/test/proxy/HttpProxy.java
--- a/src/test/java/io/vertx/test/proxy/HttpProxy.java
+++ b/src/test/java/io/vertx/test/proxy/HttpProxy.java
@@ -168,7 +168,7 @@ public HttpProxy start(Vertx vertx) throws Exception {
             }
             resp.body().onComplete(ar2 -> {
               if (ar2.succeeded()) {
-                request.response().end(ar2.result());
+                request.response().setStatusCode(resp.statusCode()).end(ar2.result());
               } else {
                 request.response().setStatusCode(500).end(ar2.cause().toString() + " on client request");
               }