Skip to content

Commit d13f648

Browse files
author
oleksiys
committed
[1.8.x] fix issue AsyncHttpClient#791
AsyncHttpClient#791 "The request body is sent with HTTP CONNECT"
1 parent 0452153 commit d13f648

File tree

1 file changed

+118
-72
lines changed

1 file changed

+118
-72
lines changed

src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java

Lines changed: 118 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,6 @@
5959
import com.ning.http.util.AsyncHttpProviderUtils;
6060
import com.ning.http.util.AuthenticatorUtils;
6161
import static com.ning.http.util.MiscUtil.isNonEmpty;
62-
import static com.ning.http.util.MiscUtil.isNonEmpty;
63-
import static com.ning.http.util.MiscUtil.isNonEmpty;
6462

6563
import com.ning.http.util.ProxyUtils;
6664
import com.ning.http.util.SslUtils;
@@ -561,18 +559,26 @@ static int getPort(final URI uri, final int p) {
561559

562560

563561
@SuppressWarnings({"unchecked"})
564-
boolean sendRequest(final FilterChainContext ctx,
565-
final Request request,
562+
boolean sendRequest(final HttpTransactionContext httpCtx,
563+
final FilterChainContext ctx,
566564
final HttpRequestPacket requestPacket,
567565
final BodyHandler bodyHandler)
568566
throws IOException {
567+
568+
final Request request = httpCtx.request;
569+
final AsyncHandler h = httpCtx.handler;
570+
if (h instanceof TransferCompletionHandler) {
571+
final FluentCaseInsensitiveStringsMap map =
572+
new FluentCaseInsensitiveStringsMap(request.getHeaders());
573+
TransferCompletionHandler.class.cast(h).transferAdapter(new GrizzlyTransferAdapter(map));
574+
}
569575

576+
requestPacket.setConnection(ctx.getConnection());
577+
570578
boolean isWriteComplete = true;
571579

572580
if (bodyHandler != null) { // Check if the HTTP request has body
573-
final HttpTransactionContext context = HttpTransactionContext.get(ctx.getConnection());
574-
575-
context.bodyHandler = bodyHandler;
581+
httpCtx.bodyHandler = bodyHandler;
576582
if (LOGGER.isDebugEnabled()) {
577583
LOGGER.debug("REQUEST: " + requestPacket.toString());
578584
}
@@ -867,42 +873,36 @@ private boolean sendAsGrizzlyRequest(final Request request,
867873
convertToUpgradeRequest(httpCtx);
868874
}
869875
final Request req = httpCtx.request;
870-
final URI uri = req.isUseRawUrl() ? req.getRawURI() : req.getURI();
871876
final Method method = Method.valueOf(request.getMethod());
872-
final HttpRequestPacket.Builder builder = HttpRequestPacket.builder();
877+
final URI uri = req.isUseRawUrl() ? req.getRawURI() : req.getURI();
878+
873879
boolean secure = "https".equals(uri.getScheme());
874-
builder.method(method);
875-
builder.protocol(Protocol.HTTP_1_1);
876880

877-
if (!request.getHeaders().containsKey(Header.Host.toString())) {
878-
String host = request.getVirtualHost();
879-
if (host != null) {
880-
builder.header(Header.Host, host);
881-
} else {
882-
if (uri.getPort() == -1) {
883-
builder.header(Header.Host, uri.getHost());
884-
} else {
885-
builder.header(Header.Host, uri.getHost() + ':' + uri.getPort());
886-
}
887-
}
888-
}
889881
final ProxyServer proxy = ProxyUtils.getProxyServer(config, request);
890882
final boolean useProxy = proxy != null;
883+
884+
final boolean isEstablishingConnectTunnel =
885+
useProxy && (secure || httpCtx.isWSRequest) &&
886+
!httpCtx.isTunnelEstablished(connection);
891887

888+
if (isEstablishingConnectTunnel) {
889+
// once the tunnel is established, sendAsGrizzlyRequest will
890+
// be called again and we'll finally send the request over the tunnel
891+
return establishConnectTunnel(proxy, httpCtx, uri, ctx);
892+
}
893+
894+
final HttpRequestPacket.Builder builder =
895+
HttpRequestPacket.builder()
896+
.protocol(Protocol.HTTP_1_1)
897+
.method(method);
898+
892899
if (useProxy) {
893-
if (secure || httpCtx.isWSRequest) { // TUNNELING?
894-
if (!httpCtx.isTunnelEstablished(connection)) {
895-
secure = false;
896-
httpCtx.establishingTunnel = true;
897-
builder.method(Method.CONNECT);
898-
builder.uri(AsyncHttpProviderUtils.getAuthority(uri));
900+
if (secure || httpCtx.isWSRequest) { // Sending message over established CONNECT tunnel
901+
if (config.isUseRelativeURIsWithConnectProxies()) {
902+
builder.uri(uri.getRawPath());
903+
builder.query(uri.getRawQuery());
899904
} else {
900-
if (config.isUseRelativeURIsWithConnectProxies()) {
901-
builder.uri(uri.getRawPath());
902-
builder.query(uri.getRawQuery());
903-
} else {
904-
builder.uri(uri.toString());
905-
}
905+
builder.uri(uri.toString());
906906
}
907907
} else {
908908
builder.uri(uri.toString());
@@ -912,10 +912,11 @@ private boolean sendAsGrizzlyRequest(final Request request,
912912
builder.query(uri.getRawQuery());
913913
}
914914

915-
final BodyHandler bodyHandler = isPayloadAllowed(method) ?
916-
bodyHandlerFactory.getBodyHandler(request) :
917-
null;
918-
915+
HttpRequestPacket requestPacket;
916+
final BodyHandler bodyHandler = isPayloadAllowed(method)
917+
? bodyHandlerFactory.getBodyHandler(request)
918+
: null;
919+
919920
if (bodyHandler != null) {
920921
final long contentLength = request.getContentLength();
921922
if (contentLength >= 0) {
@@ -925,53 +926,68 @@ private boolean sendAsGrizzlyRequest(final Request request,
925926
builder.chunked(true);
926927
}
927928
}
928-
929-
HttpRequestPacket requestPacket;
930-
if (httpCtx.isWSRequest && !httpCtx.establishingTunnel) {
929+
930+
if (httpCtx.isWSRequest) {
931931
try {
932932
final URI wsURI = new URI(httpCtx.wsRequestURI);
933933
secure = "wss".equalsIgnoreCase(wsURI.getScheme());
934934
httpCtx.protocolHandler = Version.RFC6455.createHandler(true);
935935
httpCtx.handshake = httpCtx.protocolHandler.createHandShake(wsURI);
936-
requestPacket = (HttpRequestPacket)
937-
httpCtx.handshake.composeHeaders().getHttpHeader();
936+
requestPacket = (HttpRequestPacket) httpCtx.handshake.composeHeaders().getHttpHeader();
938937
} catch (URISyntaxException e) {
939938
throw new IllegalArgumentException("Invalid WS URI: " + httpCtx.wsRequestURI);
940939
}
941940
} else {
942941
requestPacket = builder.build();
943942
}
944-
requestPacket.setSecure(secure);
945943

944+
requestPacket.setSecure(secure);
946945
ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(secure, connection));
947946

948-
addHeaders(request, requestPacket);
947+
copyHeaders(request, requestPacket);
949948
addCookies(request, requestPacket);
950-
addAuthorizationHeader(request, requestPacket);
951949

952-
if (useProxy) {
953-
if (!requestPacket.getHeaders().contains(Header.ProxyConnection)) {
954-
requestPacket.setHeader(Header.ProxyConnection, "keep-alive");
955-
}
950+
addServiceHeaders(requestPacket);
951+
addHostHeaderIfNeeded(request, uri, requestPacket);
952+
addAuthorizationHeader(getRealm(request), requestPacket);
956953

957-
if (proxy.getPrincipal() != null) {
958-
requestPacket.setHeader(Header.ProxyAuthorization,
959-
AuthenticatorUtils.computeBasicAuthentication(proxy));
960-
}
961-
}
962-
final AsyncHandler h = httpCtx.handler;
963-
if (h instanceof TransferCompletionHandler) {
964-
final FluentCaseInsensitiveStringsMap map =
965-
new FluentCaseInsensitiveStringsMap(request.getHeaders());
966-
TransferCompletionHandler.class.cast(h).transferAdapter(new GrizzlyTransferAdapter(map));
954+
if (useProxy) {
955+
addProxyHeaders(proxy, requestPacket);
967956
}
968957

969-
requestPacket.setConnection(connection);
970-
return sendRequest(ctx, request, requestPacket,
958+
return sendRequest(httpCtx, ctx, requestPacket,
971959
wrapWithExpectHandlerIfNeeded(bodyHandler, requestPacket));
972960

973961
}
974962

963+
private boolean establishConnectTunnel(
964+
final ProxyServer proxy,
965+
final HttpTransactionContext httpCtx,
966+
final URI uri,
967+
final FilterChainContext ctx) throws IOException {
968+
final Connection connection = ctx.getConnection();
969+
970+
final HttpRequestPacket requestPacket =
971+
HttpRequestPacket.builder()
972+
.protocol(Protocol.HTTP_1_0)
973+
.method(Method.CONNECT)
974+
.uri(AsyncHttpProviderUtils.getAuthority(uri))
975+
.build();
976+
977+
httpCtx.establishingTunnel = true;
978+
979+
// turn off SSL, because CONNECT will be sent in plain mode
980+
ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(false, connection));
981+
982+
final Request request = httpCtx.request;
983+
addServiceHeaders(requestPacket);
984+
addHostHeaderIfNeeded(request, uri, requestPacket);
985+
addAuthorizationHeader(getRealm(request), requestPacket);
986+
addProxyHeaders(proxy, requestPacket);
987+
988+
return sendRequest(httpCtx, ctx, requestPacket, null);
989+
}
990+
975991
/**
976992
* check if we need to wrap the BodyHandler with ExpectHandler
977993
*/
@@ -997,11 +1013,7 @@ private boolean isPayloadAllowed(final Method method) {
9971013
return method.getPayloadExpectation() != Method.PayloadExpectation.NOT_ALLOWED;
9981014
}
9991015

1000-
private void addAuthorizationHeader(final Request request, final HttpRequestPacket requestPacket) {
1001-
Realm realm = request.getRealm();
1002-
if (realm == null) {
1003-
realm = config.getRealm();
1004-
}
1016+
private void addAuthorizationHeader(final Realm realm, final HttpRequestPacket requestPacket) {
10051017
if (realm != null && realm.getUsePreemptiveAuth()) {
10061018
final String authHeaderValue = generateAuthHeader(realm);
10071019
if (authHeaderValue != null) {
@@ -1010,6 +1022,40 @@ private void addAuthorizationHeader(final Request request, final HttpRequestPack
10101022
}
10111023
}
10121024

1025+
private void addProxyHeaders(final ProxyServer proxy,
1026+
final HttpRequestPacket requestPacket)
1027+
throws UnsupportedEncodingException {
1028+
1029+
if (!requestPacket.getHeaders().contains(Header.ProxyConnection)) {
1030+
requestPacket.setHeader(Header.ProxyConnection, "keep-alive");
1031+
}
1032+
1033+
if (proxy.getPrincipal() != null) {
1034+
requestPacket.setHeader(Header.ProxyAuthorization,
1035+
AuthenticatorUtils.computeBasicAuthentication(proxy));
1036+
}
1037+
}
1038+
1039+
private void addHostHeaderIfNeeded(final Request request,
1040+
final URI uri, final HttpRequestPacket requestPacket) {
1041+
if (!requestPacket.containsHeader(Header.Host)) {
1042+
String host = request.getVirtualHost();
1043+
if (host != null) {
1044+
requestPacket.addHeader(Header.Host, host);
1045+
} else {
1046+
if (uri.getPort() == -1) {
1047+
requestPacket.addHeader(Header.Host, uri.getHost());
1048+
} else {
1049+
requestPacket.addHeader(Header.Host, uri.getHost() + ':' + uri.getPort());
1050+
}
1051+
}
1052+
}
1053+
}
1054+
1055+
private Realm getRealm(final Request request) {
1056+
return request.getRealm() != null ? request.getRealm() : config.getRealm();
1057+
}
1058+
10131059
private String generateAuthHeader(final Realm realm) {
10141060
try {
10151061
switch (realm.getAuthScheme()) {
@@ -1051,7 +1097,7 @@ private void convertToUpgradeRequest(final HttpTransactionContext ctx) {
10511097
ctx.requestUrl = sb.toString();
10521098
}
10531099

1054-
private void addHeaders(final Request request,
1100+
private void copyHeaders(final Request request,
10551101
final HttpRequestPacket requestPacket) {
10561102

10571103
final FluentCaseInsensitiveStringsMap map = request.getHeaders();
@@ -1066,7 +1112,9 @@ private void addHeaders(final Request request,
10661112
}
10671113
}
10681114
}
1069-
1115+
}
1116+
1117+
private void addServiceHeaders(final HttpRequestPacket requestPacket) {
10701118
final MimeHeaders headers = requestPacket.getHeaders();
10711119
if (!headers.contains(Header.Connection)) {
10721120
requestPacket.addHeader(Header.Connection, "keep-alive");
@@ -1079,8 +1127,6 @@ private void addHeaders(final Request request,
10791127
if (!headers.contains(Header.UserAgent)) {
10801128
requestPacket.addHeader(Header.UserAgent, config.getUserAgent());
10811129
}
1082-
1083-
10841130
}
10851131

10861132

0 commit comments

Comments
 (0)