Skip to content

Commit d24ee6a

Browse files
authored
Propagate original request user-agent in proxy CONNECT requests (AsyncHttpClient#1742)
* Makes sure custom user-agent is propagated down to CONNECT requests when a proxy is in the way, ensuring all outgoing requests bear the correct user agent. * Add a test for custom user agent with proxy
1 parent 7770c8b commit d24ee6a

File tree

2 files changed

+20
-5
lines changed

2 files changed

+20
-5
lines changed

client/src/main/java/org/asynchttpclient/netty/request/NettyRequestFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ public NettyRequest newNettyRequest(Request request, boolean performConnectReque
140140
if (connect) {
141141
// assign proxy-auth as configured on request
142142
headers.set(PROXY_AUTHORIZATION, request.getHeaders().getAll(PROXY_AUTHORIZATION));
143+
headers.set(USER_AGENT, request.getHeaders().getAll(USER_AGENT));
143144

144145
} else {
145146
// assign headers as configured on request

client/src/test/java/org/asynchttpclient/BasicHttpProxyToHttpsTest.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,20 @@
3131
import java.util.concurrent.ExecutionException;
3232
import java.util.concurrent.Future;
3333

34-
import static io.netty.handler.codec.http.HttpHeaderNames.PROXY_AUTHENTICATE;
35-
import static io.netty.handler.codec.http.HttpHeaderNames.PROXY_AUTHORIZATION;
34+
import static io.netty.handler.codec.http.HttpHeaderNames.*;
3635
import static org.asynchttpclient.Dsl.*;
3736
import static org.asynchttpclient.test.TestUtils.addHttpConnector;
3837
import static org.asynchttpclient.test.TestUtils.addHttpsConnector;
38+
import static org.asynchttpclient.config.AsyncHttpClientConfigDefaults.*;
3939

4040
/**
41-
* Test that validates that when having an HTTP proxy and trying to access an HTTPS through the proxy the proxy credentials should be passed during the CONNECT request.
41+
* Test that validates that when having an HTTP proxy and trying to access an HTTPS
42+
* through the proxy the proxy credentials and a custom user-agent (if set) should be passed during the CONNECT request.
4243
*/
4344
public class BasicHttpProxyToHttpsTest {
4445

4546
private static final Logger LOGGER = LoggerFactory.getLogger(BasicHttpProxyToHttpsTest.class);
47+
private static final String CUSTOM_USER_AGENT = "custom-user-agent";
4648

4749
private int httpPort;
4850
private int proxyPort;
@@ -66,13 +68,24 @@ public void setUpGlobal() throws Exception {
6668
ConnectHandler connectHandler = new ConnectHandler() {
6769

6870
@Override
71+
// This proxy receives a CONNECT request from the client before making the real request for the target host.
6972
protected boolean handleAuthentication(HttpServletRequest request, HttpServletResponse response, String address) {
73+
74+
// If the userAgent of the CONNECT request is the same as the default userAgent,
75+
// then the custom userAgent was not properly propagated and the test should fail.
76+
String userAgent = request.getHeader(USER_AGENT.toString());
77+
if(userAgent.equals(defaultUserAgent())) {
78+
return false;
79+
}
80+
81+
// If the authentication failed, the test should also fail.
7082
String authorization = request.getHeader(PROXY_AUTHORIZATION.toString());
7183
if (authorization == null) {
7284
response.setStatus(HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED);
7385
response.setHeader(PROXY_AUTHENTICATE.toString(), "Basic realm=\"Fake Realm\"");
7486
return false;
75-
} else if (authorization.equals("Basic am9obmRvZTpwYXNz")) {
87+
}
88+
else if (authorization.equals("Basic am9obmRvZTpwYXNz")) {
7689
return true;
7790
}
7891
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
@@ -98,6 +111,7 @@ public void nonPreemptiveProxyAuthWithHttpsTarget() throws IOException, Interrup
98111
String targetUrl = "https://localhost:" + httpPort + "/foo/bar";
99112
Request request = get(targetUrl)
100113
.setProxyServer(proxyServer("127.0.0.1", proxyPort).setRealm(realm(AuthScheme.BASIC, "johndoe", "pass")))
114+
.setHeader("user-agent", CUSTOM_USER_AGENT)
101115
// .setRealm(realm(AuthScheme.BASIC, "user", "passwd"))
102116
.build();
103117
Future<Response> responseFuture = client.executeRequest(request);
@@ -107,4 +121,4 @@ public void nonPreemptiveProxyAuthWithHttpsTarget() throws IOException, Interrup
107121
Assert.assertEquals("/foo/bar", response.getHeader("X-pathInfo"));
108122
}
109123
}
110-
}
124+
}

0 commit comments

Comments
 (0)