You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2022/02/13 19:03:50 UTC
[httpcomponents-client] branch 5.1.x updated: HTTPCLIENT-2203: Corrected target host normalization by the request execution interceptors
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch 5.1.x
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git
The following commit(s) were added to refs/heads/5.1.x by this push:
new 224622f HTTPCLIENT-2203: Corrected target host normalization by the request execution interceptors
224622f is described below
commit 224622f7291c221fb6b2806e695a7b1d1e3f93e9
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Sun Feb 13 19:57:15 2022 +0100
HTTPCLIENT-2203: Corrected target host normalization by the request execution interceptors
---
.../client5/http/impl/async/AsyncProtocolExec.java | 19 +++-
.../http/impl/async/H2AsyncClientBuilder.java | 2 +-
.../http/impl/async/HttpAsyncClientBuilder.java | 2 +-
.../http/impl/classic/HttpClientBuilder.java | 2 +-
.../hc/client5/http/impl/classic/ProtocolExec.java | 19 +++-
.../AsyncPreemptiveBasicClientAuthentication.java | 108 +++++++++++++++++++++
6 files changed, 145 insertions(+), 7 deletions(-)
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java
index 880d9e5..5cfdbe9 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java
@@ -32,6 +32,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.hc.client5.http.AuthenticationStrategy;
import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.async.AsyncExecCallback;
import org.apache.hc.client5.http.async.AsyncExecChain;
import org.apache.hc.client5.http.async.AsyncExecChainHandler;
@@ -42,8 +43,10 @@ import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.CredentialsStore;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.AuthSupport;
+import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.Internal;
import org.apache.hc.core5.annotation.ThreadingBehavior;
@@ -87,17 +90,27 @@ public final class AsyncProtocolExec implements AsyncExecChainHandler {
private final AuthenticationStrategy targetAuthStrategy;
private final AuthenticationStrategy proxyAuthStrategy;
private final HttpAuthenticator authenticator;
+ private final SchemePortResolver schemePortResolver;
AsyncProtocolExec(
final HttpProcessor httpProcessor,
final AuthenticationStrategy targetAuthStrategy,
- final AuthenticationStrategy proxyAuthStrategy) {
+ final AuthenticationStrategy proxyAuthStrategy,
+ final SchemePortResolver schemePortResolver) {
this.httpProcessor = Args.notNull(httpProcessor, "HTTP protocol processor");
this.targetAuthStrategy = Args.notNull(targetAuthStrategy, "Target authentication strategy");
this.proxyAuthStrategy = Args.notNull(proxyAuthStrategy, "Proxy authentication strategy");
+ this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
this.authenticator = new HttpAuthenticator(LOG);
}
+ AsyncProtocolExec(
+ final HttpProcessor httpProcessor,
+ final AuthenticationStrategy targetAuthStrategy,
+ final AuthenticationStrategy proxyAuthStrategy) {
+ this(httpProcessor, targetAuthStrategy, proxyAuthStrategy, null);
+ }
+
@Override
public void execute(
final HttpRequest userRequest,
@@ -158,7 +171,9 @@ public final class AsyncProtocolExec implements AsyncExecChainHandler {
final AsyncExecRuntime execRuntime = scope.execRuntime;
final HttpHost proxy = route.getProxyHost();
- final HttpHost target = new HttpHost(request.getScheme(), request.getAuthority());
+ final HttpHost target = RoutingSupport.normalize(
+ new HttpHost(request.getScheme(), request.getAuthority()),
+ schemePortResolver);
final AuthExchange targetAuthExchange = clientContext.getAuthExchange(target);
final AuthExchange proxyAuthExchange = proxy != null ? clientContext.getAuthExchange(proxy) : new AuthExchange();
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
index 693af2f..8a0f82a 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
@@ -673,7 +673,7 @@ public class H2AsyncClientBuilder {
final HttpProcessor httpProcessor = b.build();
execChainDefinition.addFirst(
- new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
+ new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy, schemePortResolver),
ChainElement.PROTOCOL.name());
// Add request retry executor, if not disabled
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
index ff02782..6a83849 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
@@ -834,7 +834,7 @@ public class HttpAsyncClientBuilder {
final HttpProcessor httpProcessor = b.build();
execChainDefinition.addFirst(
- new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
+ new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy, schemePortResolver),
ChainElement.PROTOCOL.name());
// Add request retry executor, if not disabled
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
index 29701c6..a9f3ee9 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
@@ -851,7 +851,7 @@ public class HttpClientBuilder {
}
final HttpProcessor httpProcessor = b.build();
execChainDefinition.addFirst(
- new ProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
+ new ProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy, schemePortResolver),
ChainElement.PROTOCOL.name());
// Add request retry executor, if not disabled
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java
index a799787..7567c86 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java
@@ -32,6 +32,7 @@ import java.util.Iterator;
import org.apache.hc.client5.http.AuthenticationStrategy;
import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.auth.AuthExchange;
import org.apache.hc.client5.http.auth.ChallengeType;
import org.apache.hc.client5.http.auth.CredentialsProvider;
@@ -41,8 +42,10 @@ import org.apache.hc.client5.http.classic.ExecChainHandler;
import org.apache.hc.client5.http.classic.ExecRuntime;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.AuthSupport;
+import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.routing.RoutingSupport;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.Internal;
import org.apache.hc.core5.annotation.ThreadingBehavior;
@@ -86,17 +89,27 @@ public final class ProtocolExec implements ExecChainHandler {
private final AuthenticationStrategy targetAuthStrategy;
private final AuthenticationStrategy proxyAuthStrategy;
private final HttpAuthenticator authenticator;
+ private final SchemePortResolver schemePortResolver;
public ProtocolExec(
final HttpProcessor httpProcessor,
final AuthenticationStrategy targetAuthStrategy,
- final AuthenticationStrategy proxyAuthStrategy) {
+ final AuthenticationStrategy proxyAuthStrategy,
+ final SchemePortResolver schemePortResolver) {
this.httpProcessor = Args.notNull(httpProcessor, "HTTP protocol processor");
this.targetAuthStrategy = Args.notNull(targetAuthStrategy, "Target authentication strategy");
this.proxyAuthStrategy = Args.notNull(proxyAuthStrategy, "Proxy authentication strategy");
+ this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
this.authenticator = new HttpAuthenticator();
}
+ public ProtocolExec(
+ final HttpProcessor httpProcessor,
+ final AuthenticationStrategy targetAuthStrategy,
+ final AuthenticationStrategy proxyAuthStrategy) {
+ this(httpProcessor, targetAuthStrategy, proxyAuthStrategy, null);
+ }
+
@Override
public ClassicHttpResponse execute(
final ClassicHttpRequest userRequest,
@@ -144,7 +157,9 @@ public final class ProtocolExec implements ExecChainHandler {
AuthSupport.extractFromAuthority(request.getScheme(), authority, (CredentialsStore) credsProvider);
}
- final HttpHost target = new HttpHost(request.getScheme(), request.getAuthority());
+ final HttpHost target = RoutingSupport.normalize(
+ new HttpHost(request.getScheme(), request.getAuthority()),
+ schemePortResolver);
final AuthExchange targetAuthExchange = context.getAuthExchange(target);
final AuthExchange proxyAuthExchange = proxy != null ? context.getAuthExchange(proxy) : new AuthExchange();
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncPreemptiveBasicClientAuthentication.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncPreemptiveBasicClientAuthentication.java
new file mode 100644
index 0000000..531daaf
--- /dev/null
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncPreemptiveBasicClientAuthentication.java
@@ -0,0 +1,108 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.hc.client5.http.examples;
+
+import java.util.concurrent.Future;
+
+import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
+import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
+import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
+import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
+import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
+import org.apache.hc.client5.http.auth.AuthScope;
+import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
+import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
+import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
+import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.BasicScheme;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.message.StatusLine;
+import org.apache.hc.core5.io.CloseMode;
+
+/**
+ * A simple example that uses HttpClient to execute an HTTP request against
+ * a target site that requires user authentication.
+ */
+public class AsyncPreemptiveBasicClientAuthentication {
+
+ public static void main(final String[] args) throws Exception {
+ final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
+ credsProvider.setCredentials(
+ new AuthScope("httpbin.org", 80),
+ new UsernamePasswordCredentials("user", "passwd".toCharArray()));
+ final CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
+ .setDefaultCredentialsProvider(credsProvider)
+ .build();
+ httpclient.start();
+
+ // Generate Basic scheme object and add it to the local auth cache
+ final BasicScheme basicAuth = new BasicScheme();
+ basicAuth.initPreemptive(new UsernamePasswordCredentials("user", "passwd".toCharArray()));
+
+ final HttpHost target = new HttpHost("http", "httpbin.org", 80);
+
+ // Add AuthCache to the execution context
+ final HttpClientContext localContext = HttpClientContext.create();
+ localContext.resetAuthExchange(target, basicAuth);
+
+ final SimpleHttpRequest request = SimpleRequestBuilder.get("http://httpbin.org:80/basic-auth/user/passwd")
+ .build();
+
+ System.out.println("Executing request " + request);
+ for (int i = 0; i < 3; i++) {
+ final Future<SimpleHttpResponse> future = httpclient.execute(
+ SimpleRequestProducer.create(request),
+ SimpleResponseConsumer.create(),
+ localContext,
+ new FutureCallback<SimpleHttpResponse>() {
+
+ @Override
+ public void completed(final SimpleHttpResponse response) {
+ System.out.println(request + "->" + new StatusLine(response));
+ System.out.println(response.getBody());
+ }
+
+ @Override
+ public void failed(final Exception ex) {
+ System.out.println(request + "->" + ex);
+ }
+
+ @Override
+ public void cancelled() {
+ System.out.println(request + " cancelled");
+ }
+
+ });
+ future.get();
+ }
+
+ System.out.println("Shutting down");
+ httpclient.close(CloseMode.GRACEFUL);
+ }
+}