Improved protocol handling in the async request execution chain; implemented cookie processing and authentication handling

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1793567 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2017-05-02 18:22:59 +00:00
parent d43ee7177b
commit d5039137ca
9 changed files with 1112 additions and 25 deletions

View File

@ -33,6 +33,9 @@ import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.URIScheme;
import org.apache.hc.core5.http.config.H1Config;
import org.apache.hc.core5.http.impl.HttpProcessors;
import org.apache.hc.core5.http.protocol.HttpProcessor;
import org.apache.hc.core5.io.ShutdownType;
import org.apache.hc.core5.reactor.ListenerEndpoint;
import org.junit.Rule;
@ -69,8 +72,8 @@ public abstract class IntegrationTestBase extends LocalAsyncServerTestBase {
};
public HttpHost start() throws Exception {
server.start();
public HttpHost start(final HttpProcessor httpProcessor, final H1Config h1Config) throws Exception {
server.start(httpProcessor, h1Config);
final ListenerEndpoint listener = server.listen(new InetSocketAddress(0));
httpclient = clientBuilder.build();
httpclient.start();
@ -79,4 +82,8 @@ public abstract class IntegrationTestBase extends LocalAsyncServerTestBase {
return new HttpHost("localhost", address.getPort(), scheme.name());
}
public HttpHost start() throws Exception {
return start(HttpProcessors.server(), H1Config.DEFAULT);
}
}

View File

@ -70,7 +70,6 @@ import org.apache.hc.core5.reactor.ListenerEndpoint;
import org.apache.hc.core5.testing.nio.Http2TestServer;
import org.apache.hc.core5.util.TimeValue;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@ -641,7 +640,7 @@ public class TestAsyncRedirects extends IntegrationTestBase {
}
}
@Test @Ignore
@Test
public void testRedirectWithCookie() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {

View File

@ -0,0 +1,627 @@
/*
* ====================================================================
* 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.testing.async;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong;
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.SimpleRequestProducer;
import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
import org.apache.hc.client5.http.auth.AuthChallenge;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.auth.AuthSchemeProvider;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.ChallengeType;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.CredentialsStore;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.auth.BasicScheme;
import org.apache.hc.client5.http.impl.protocol.DefaultAuthenticationStrategy;
import org.apache.hc.client5.http.impl.sync.BasicCredentialsProvider;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.sync.methods.HttpGet;
import org.apache.hc.client5.testing.auth.RequestBasicAuth;
import org.apache.hc.client5.testing.auth.ResponseBasicUnauthorized;
import org.apache.hc.core5.function.Supplier;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.HeaderElements;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.HttpResponseInterceptor;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.URIScheme;
import org.apache.hc.core5.http.config.H1Config;
import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.impl.HttpProcessors;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.http.message.BasicHttpResponse;
import org.apache.hc.core5.http.nio.AsyncResponseProducer;
import org.apache.hc.core5.http.nio.AsyncServerExchangeHandler;
import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
import org.apache.hc.core5.http.nio.support.BasicAsyncResponseProducer;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.protocol.HttpCoreContext;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class TestClientAuthentication extends IntegrationTestBase {
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> protocols() {
return Arrays.asList(new Object[][]{
{URIScheme.HTTP},
{URIScheme.HTTPS},
});
}
public TestClientAuthentication(final URIScheme scheme) {
super(scheme);
}
@Override
public HttpHost start() throws Exception {
return super.start(HttpProcessors.customServer(null)
.add(new RequestBasicAuth())
.add(new ResponseBasicUnauthorized())
.build(),
H1Config.DEFAULT);
}
static class AuthHandler extends AbstractSimpleServerExchangeHandler {
private final boolean keepAlive;
AuthHandler(final boolean keepAlive) {
super();
this.keepAlive = keepAlive;
}
AuthHandler() {
this(true);
}
@Override
protected SimpleHttpResponse handle(
final SimpleHttpRequest request,
final HttpCoreContext context) throws HttpException {
final String creds = (String) context.getAttribute("creds");
final SimpleHttpResponse response;
if (creds == null || !creds.equals("test:test")) {
response = new SimpleHttpResponse(HttpStatus.SC_UNAUTHORIZED);
} else {
response = new SimpleHttpResponse(HttpStatus.SC_OK, "success", ContentType.TEXT_PLAIN);
}
response.setHeader(HttpHeaders.CONNECTION, this.keepAlive ? HeaderElements.KEEP_ALIVE : HeaderElements.CLOSE);
return response;
}
}
static class TestCredentialsProvider implements CredentialsStore {
private final Credentials creds;
private AuthScope authscope;
TestCredentialsProvider(final Credentials creds) {
super();
this.creds = creds;
}
@Override
public void clear() {
}
@Override
public Credentials getCredentials(final AuthScope authscope, final HttpContext context) {
this.authscope = authscope;
return this.creds;
}
@Override
public void setCredentials(final AuthScope authscope, final Credentials credentials) {
}
public AuthScope getAuthScope() {
return this.authscope;
}
}
@Test
public void testBasicAuthenticationNoCreds() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler();
}
});
final HttpHost target = start();
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(null);
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
final Future<SimpleHttpResponse> future = httpclient.execute(SimpleHttpRequest.get(target, "/"), context, null);
final HttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
final AuthScope authscope = credsProvider.getAuthScope();
Assert.assertNotNull(authscope);
Assert.assertEquals("test realm", authscope.getRealm());
}
@Test
public void testBasicAuthenticationFailure() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler();
}
});
final HttpHost target = start();
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
new UsernamePasswordCredentials("test", "all-wrong".toCharArray()));
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
final Future<SimpleHttpResponse> future = httpclient.execute(SimpleHttpRequest.get(target, "/"), context, null);
final HttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
final AuthScope authscope = credsProvider.getAuthScope();
Assert.assertNotNull(authscope);
Assert.assertEquals("test realm", authscope.getRealm());
}
@Test
public void testBasicAuthenticationSuccess() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler();
}
});
final HttpHost target = start();
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
new UsernamePasswordCredentials("test", "test".toCharArray()));
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
final Future<SimpleHttpResponse> future = httpclient.execute(SimpleHttpRequest.get(target, "/"), context, null);
final HttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
final AuthScope authscope = credsProvider.getAuthScope();
Assert.assertNotNull(authscope);
Assert.assertEquals("test realm", authscope.getRealm());
}
@Test
public void testBasicAuthenticationSuccessNonPersistentConnection() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler(false);
}
});
final HttpHost target = start();
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
new UsernamePasswordCredentials("test", "test".toCharArray()));
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
final Future<SimpleHttpResponse> future = httpclient.execute(SimpleHttpRequest.get(target, "/"), context, null);
final HttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
final AuthScope authscope = credsProvider.getAuthScope();
Assert.assertNotNull(authscope);
Assert.assertEquals("test realm", authscope.getRealm());
}
@Test
public void testBasicAuthenticationExpectationFailure() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler() {
@Override
protected AsyncResponseProducer verify(
final HttpRequest request,
final HttpContext context) throws IOException, HttpException {
final String creds = (String) context.getAttribute("creds");
if (creds == null || !creds.equals("test:test")) {
return new BasicAsyncResponseProducer(new BasicHttpResponse(HttpStatus.SC_UNAUTHORIZED),
new StringAsyncEntityProducer("Unauthorized"));
} else {
return null;
}
}
};
}
});
final HttpHost target = start();
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
new UsernamePasswordCredentials("test", "all-wrong".toCharArray()));
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
final Future<SimpleHttpResponse> future = httpclient.execute(
SimpleHttpRequest.put(target, "/", "Some important stuff", ContentType.TEXT_PLAIN), context, null);
final HttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
}
@Test
public void testBasicAuthenticationExpectationSuccess() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler() {
@Override
protected AsyncResponseProducer verify(
final HttpRequest request,
final HttpContext context) throws IOException, HttpException {
final String creds = (String) context.getAttribute("creds");
if (creds == null || !creds.equals("test:test")) {
return new BasicAsyncResponseProducer(new BasicHttpResponse(HttpStatus.SC_UNAUTHORIZED),
new StringAsyncEntityProducer("Unauthorized"));
} else {
return null;
}
}
};
}
});
final HttpHost target = start();
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
new UsernamePasswordCredentials("test", "test".toCharArray()));
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
final Future<SimpleHttpResponse> future = httpclient.execute(
SimpleHttpRequest.put(target, "/", "Some important stuff", ContentType.TEXT_PLAIN), context, null);
final HttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
final AuthScope authscope = credsProvider.getAuthScope();
Assert.assertNotNull(authscope);
Assert.assertEquals("test realm", authscope.getRealm());
}
@Test
public void testBasicAuthenticationCredentialsCaching() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler();
}
});
final AtomicLong count = new AtomicLong(0);
this.clientBuilder.setTargetAuthenticationStrategy(new DefaultAuthenticationStrategy() {
@Override
public List<AuthScheme> select(
final ChallengeType challengeType,
final Map<String, AuthChallenge> challenges,
final HttpContext context) {
count.incrementAndGet();
return super.select(challengeType, challenges, context);
}
});
final HttpHost target = start();
final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials("test", "test".toCharArray()));
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
final Future<SimpleHttpResponse> future1 = httpclient.execute(SimpleHttpRequest.get(target, "/"), context, null);
final HttpResponse response1 = future1.get();
Assert.assertNotNull(response1);
Assert.assertEquals(HttpStatus.SC_OK, response1.getCode());
final Future<SimpleHttpResponse> future2 = httpclient.execute(SimpleHttpRequest.get(target, "/"), context, null);
final HttpResponse response2 = future2.get();
Assert.assertNotNull(response2);
Assert.assertEquals(HttpStatus.SC_OK, response2.getCode());
Assert.assertEquals(1, count.get());
}
@Test
public void testAuthenticationUserinfoInRequestSuccess() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler();
}
});
final HttpHost target = start();
final HttpClientContext context = HttpClientContext.create();
final Future<SimpleHttpResponse> future = httpclient.execute(
SimpleHttpRequest.get(target.getSchemeName() + "://test:test@" + target.toHostString() + "/"), context, null);
final SimpleHttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
Assert.assertEquals("success", response.getBody());
}
@Test
public void testAuthenticationUserinfoInRequestFailure() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler();
}
});
final HttpHost target = start();
final HttpClientContext context = HttpClientContext.create();
final Future<SimpleHttpResponse> future = httpclient.execute(
SimpleHttpRequest.get(target.getSchemeName() + "://test:all-worng@" + target.toHostString() + "/"), context, null);
final SimpleHttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getCode());
}
@Test
public void testAuthenticationUserinfoInRedirectSuccess() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler();
}
});
final HttpHost target = start();
server.register("/thatway", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AbstractSimpleServerExchangeHandler() {
@Override
protected SimpleHttpResponse handle(
final SimpleHttpRequest request, final HttpCoreContext context) throws HttpException {
final SimpleHttpResponse response = new SimpleHttpResponse(HttpStatus.SC_MOVED_PERMANENTLY);
response.addHeader(new BasicHeader("Location", target.getSchemeName() + "://test:test@" + target.toHostString() + "/"));
return response;
}
};
}
});
final HttpClientContext context = HttpClientContext.create();
final Future<SimpleHttpResponse> future = httpclient.execute(
SimpleHttpRequest.get(target.getSchemeName() + "://test:test@" + target.toHostString() + "/thatway"), context, null);
final SimpleHttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
Assert.assertEquals("success", response.getBody());
}
@Test
public void testReauthentication() throws Exception {
final AtomicLong count = new AtomicLong(0);
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AbstractSimpleServerExchangeHandler() {
@Override
protected SimpleHttpResponse handle(
final SimpleHttpRequest request,
final HttpCoreContext context) throws HttpException {
final String creds = (String) context.getAttribute("creds");
if (creds == null || !creds.equals("test:test")) {
return new SimpleHttpResponse(HttpStatus.SC_UNAUTHORIZED);
} else {
// Make client re-authenticate on each fourth request
if (count.incrementAndGet() % 4 == 0) {
return new SimpleHttpResponse(HttpStatus.SC_UNAUTHORIZED);
} else {
return new SimpleHttpResponse(HttpStatus.SC_OK, "success", ContentType.TEXT_PLAIN);
}
}
}
};
}
});
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
new UsernamePasswordCredentials("test", "test".toCharArray()));
final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
.register("MyBasic", new AuthSchemeProvider() {
@Override
public AuthScheme create(final HttpContext context) {
return new BasicScheme() {
@Override
public String getName() {
return "MyBasic";
}
};
}
})
.build();
this.clientBuilder.setDefaultAuthSchemeRegistry(authSchemeRegistry);
final HttpHost target = start(HttpProcessors.customServer(null)
.add(new RequestBasicAuth())
.add(new HttpResponseInterceptor() {
@Override
public void process(
final HttpResponse response,
final EntityDetails entityDetails,
final HttpContext context) throws HttpException, IOException {
if (response.getCode() == HttpStatus.SC_UNAUTHORIZED) {
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "MyBasic realm=\"test realm\"");
}
}
})
.build(),
H1Config.DEFAULT);
final RequestConfig config = RequestConfig.custom()
.setTargetPreferredAuthSchemes(Arrays.asList("MyBasic"))
.build();
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
for (int i = 0; i < 10; i++) {
final HttpGet httpget = new HttpGet("/");
httpget.setConfig(config);
final Future<SimpleHttpResponse> future = httpclient.execute(
new SimpleRequestProducer(SimpleHttpRequest.get(target, "/"), config),
new SimpleResponseConsumer(),
context, null);
final SimpleHttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
}
}
@Test
public void testAuthenticationFallback() throws Exception {
server.register("*", new Supplier<AsyncServerExchangeHandler>() {
@Override
public AsyncServerExchangeHandler get() {
return new AuthHandler();
}
});
final HttpHost target = start(HttpProcessors.customServer(null)
.add(new RequestBasicAuth())
.add(new HttpResponseInterceptor() {
@Override
public void process(
final HttpResponse response,
final EntityDetails entityDetails,
final HttpContext context) throws HttpException, IOException {
if (response.getCode() == HttpStatus.SC_UNAUTHORIZED) {
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Digest realm=\"test realm\" invalid");
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"test realm\"");
}
}
})
.build(),
H1Config.DEFAULT);
final TestCredentialsProvider credsProvider = new TestCredentialsProvider(
new UsernamePasswordCredentials("test", "test".toCharArray()));
final HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
final Future<SimpleHttpResponse> future = httpclient.execute(SimpleHttpRequest.get(target, "/"), context, null);
final SimpleHttpResponse response = future.get();
Assert.assertNotNull(response);
Assert.assertEquals(HttpStatus.SC_OK, response.getCode());
Assert.assertEquals("success", response.getBody());
final AuthScope authscope = credsProvider.getAuthScope();
Assert.assertNotNull(authscope);
Assert.assertEquals("test realm", authscope.getRealm());
}
}

View File

@ -0,0 +1,88 @@
/*
* ====================================================================
* 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.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.sync.BasicCredentialsProvider;
import org.apache.hc.core5.concurrent.FutureCallback;
import org.apache.hc.core5.io.ShutdownType;
/**
* A simple example that uses HttpClient to execute an HTTP request against
* a target site that requires user authentication.
*/
public class AsyncClientAuthentication {
public static void main(String[] args) throws Exception {
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope("httpbin.org", 80),
new UsernamePasswordCredentials("user", "passwd".toCharArray()));
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.build();
httpclient.start();
final String requestUri = "http://httpbin.org/basic-auth/user/passwd";
SimpleHttpRequest httpget = SimpleHttpRequest.get(requestUri);
System.out.println("Executing request " + requestUri);
final Future<SimpleHttpResponse> future = httpclient.execute(
httpget,
new FutureCallback<SimpleHttpResponse>() {
@Override
public void completed(final SimpleHttpResponse response) {
System.out.println(requestUri + "->" + response.getCode());
System.out.println(response.getBody());
}
@Override
public void failed(final Exception ex) {
System.out.println(requestUri + "->" + ex);
}
@Override
public void cancelled() {
System.out.println(requestUri + " cancelled");
}
});
future.get();
System.out.println("Shutting down");
httpclient.shutdown(ShutdownType.GRACEFUL);
}
}

View File

@ -25,19 +25,22 @@
*
*/
package org.apache.hc.client5.http.auth.util;
package org.apache.hc.client5.http.impl;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.CredentialsStore;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.config.AuthSchemes;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.net.URIAuthority;
import org.apache.hc.core5.util.Args;
/**
* @since 5.0
*/
public class CredentialSupport {
public class AuthSupport {
public static void extractFromAuthority(
final URIAuthority authority,
@ -65,4 +68,20 @@ public class CredentialSupport {
new UsernamePasswordCredentials(userName, password));
}
public static HttpHost resolveAuthTarget(final HttpRequest request, final HttpRoute route) {
Args.notNull(request, "Request");
Args.notNull(route, "Route");
final URIAuthority authority = request.getAuthority();
final String scheme = request.getScheme();
final HttpHost target = authority != null ? new HttpHost(authority, scheme) : route.getTargetHost();;
if (target.getPort() < 0) {
return new HttpHost(
target.getHostName(),
route.getTargetHost().getPort(),
target.getSchemeName());
} else {
return target;
}
}
}

View File

@ -27,31 +27,74 @@
package org.apache.hc.client5.http.impl.async;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.StandardMethods;
import org.apache.hc.client5.http.async.AsyncExecCallback;
import org.apache.hc.client5.http.async.AsyncExecChain;
import org.apache.hc.client5.http.async.AsyncExecChainHandler;
import org.apache.hc.client5.http.async.AsyncExecRuntime;
import org.apache.hc.client5.http.auth.AuthExchange;
import org.apache.hc.client5.http.auth.ChallengeType;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.CredentialsStore;
import org.apache.hc.client5.http.auth.util.CredentialSupport;
import org.apache.hc.client5.http.impl.AuthSupport;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
import org.apache.hc.client5.http.protocol.AuthenticationStrategy;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.utils.URIUtils;
import org.apache.hc.core5.annotation.Contract;
import org.apache.hc.core5.annotation.ThreadingBehavior;
import org.apache.hc.core5.http.EntityDetails;
import org.apache.hc.core5.http.Header;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHeaders;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.ProtocolException;
import org.apache.hc.core5.http.nio.AsyncDataConsumer;
import org.apache.hc.core5.http.nio.AsyncEntityProducer;
import org.apache.hc.core5.http.protocol.HttpCoreContext;
import org.apache.hc.core5.http.protocol.HttpProcessor;
import org.apache.hc.core5.net.URIAuthority;
import org.apache.hc.core5.util.Args;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Request executor in the request execution chain that is responsible
* for implementation of HTTP specification requirements.
* <p>
* Further responsibilities such as communication with the opposite
* endpoint is delegated to the next executor in the request execution
* chain.
*
* @since 5.0
*/
@Contract(threading = ThreadingBehavior.IMMUTABLE)
class AsyncProtocolExec implements AsyncExecChainHandler {
private final HttpProcessor httpProcessor;
private final Logger log = LogManager.getLogger(getClass());
AsyncProtocolExec(final HttpProcessor httpProcessor) {
this.httpProcessor = httpProcessor;
private final HttpProcessor httpProcessor;
private final AuthenticationStrategy targetAuthStrategy;
private final AuthenticationStrategy proxyAuthStrategy;
private final HttpAuthenticator authenticator;
AsyncProtocolExec(
final HttpProcessor httpProcessor,
final AuthenticationStrategy targetAuthStrategy,
final AuthenticationStrategy proxyAuthStrategy) {
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.authenticator = new HttpAuthenticator();
}
@Override
@ -63,32 +106,121 @@ class AsyncProtocolExec implements AsyncExecChainHandler {
final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
final HttpRoute route = scope.route;
final HttpClientContext clientContext = scope.clientContext;
if (route.getProxyHost() != null && !route.isTunnelled()) {
try {
URI uri = request.getUri();
if (!uri.isAbsolute()) {
uri = URIUtils.rewriteURI(uri, route.getTargetHost(), true);
} else {
uri = URIUtils.rewriteURI(uri);
}
request.setPath(uri.toASCIIString());
} catch (final URISyntaxException ex) {
throw new ProtocolException("Invalid request URI: " + request.getRequestUri(), ex);
}
}
final URIAuthority authority = request.getAuthority();
if (authority != null) {
final CredentialsProvider credsProvider = clientContext.getCredentialsProvider();
if (credsProvider instanceof CredentialsStore) {
CredentialSupport.extractFromAuthority(authority, (CredentialsStore) credsProvider);
AuthSupport.extractFromAuthority(authority, (CredentialsStore) credsProvider);
}
}
final AtomicBoolean challenged = new AtomicBoolean(false);
internalExecute(challenged, request, entityProducer, scope, chain, asyncExecCallback);
}
private void internalExecute(
final AtomicBoolean challenged,
final HttpRequest request,
final AsyncEntityProducer entityProducer,
final AsyncExecChain.Scope scope,
final AsyncExecChain chain,
final AsyncExecCallback asyncExecCallback) throws HttpException, IOException {
final HttpRoute route = scope.route;
final HttpClientContext clientContext = scope.clientContext;
final AsyncExecRuntime execRuntime = scope.execRuntime;
final HttpHost target = route.getTargetHost();
final HttpHost proxy = route.getProxyHost();
final AuthExchange targetAuthExchange = clientContext.getAuthExchange(target);
final AuthExchange proxyAuthExchange = proxy != null ? clientContext.getAuthExchange(proxy) : new AuthExchange();
clientContext.setAttribute(HttpClientContext.HTTP_ROUTE, route);
clientContext.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
httpProcessor.process(request, entityProducer, clientContext);
if (!request.containsHeader(HttpHeaders.AUTHORIZATION)) {
if (log.isDebugEnabled()) {
log.debug("Target auth state: " + targetAuthExchange.getState());
}
authenticator.addAuthResponse(target, ChallengeType.TARGET, request, targetAuthExchange, clientContext);
}
if (!request.containsHeader(HttpHeaders.PROXY_AUTHORIZATION) && !route.isTunnelled()) {
if (log.isDebugEnabled()) {
log.debug("Proxy auth state: " + proxyAuthExchange.getState());
}
authenticator.addAuthResponse(proxy, ChallengeType.PROXY, request, proxyAuthExchange, clientContext);
}
chain.proceed(request, entityProducer, scope, new AsyncExecCallback() {
@Override
public AsyncDataConsumer handleResponse(
final HttpResponse response, final EntityDetails entityDetails) throws HttpException, IOException {
clientContext.setAttribute(HttpCoreContext.HTTP_RESPONSE, response);
httpProcessor.process(response, entityDetails, clientContext);
return asyncExecCallback.handleResponse(response, entityDetails);
if (request.getMethod().equalsIgnoreCase(StandardMethods.TRACE.name())) {
// Do not perform authentication for TRACE request
return asyncExecCallback.handleResponse(response, entityDetails);
}
if (needAuthentication(targetAuthExchange, proxyAuthExchange, route, request, response, clientContext)) {
challenged.set(true);
return null;
} else {
challenged.set(false);
return asyncExecCallback.handleResponse(response, entityDetails);
}
}
@Override
public void completed() {
asyncExecCallback.completed();
if (execRuntime.isConnected()) {
if (proxyAuthExchange.getState() == AuthExchange.State.SUCCESS
&& proxyAuthExchange.getAuthScheme() != null
&& proxyAuthExchange.getAuthScheme().isConnectionBased()) {
log.debug("Resetting proxy auth state");
proxyAuthExchange.reset();
}
if (targetAuthExchange.getState() == AuthExchange.State.SUCCESS
&& targetAuthExchange.getAuthScheme() != null
&& targetAuthExchange.getAuthScheme().isConnectionBased()) {
log.debug("Resetting target auth state");
targetAuthExchange.reset();
}
}
if (challenged.get()) {
// Reset request headers
final HttpRequest original = scope.originalRequest;
request.setHeaders();
for (final Iterator<Header> it = original.headerIterator(); it.hasNext(); ) {
request.addHeader(it.next());
}
try {
internalExecute(challenged, request, entityProducer, scope, chain, asyncExecCallback);
} catch (final HttpException | IOException ex) {
asyncExecCallback.failed(ex);
}
} else {
asyncExecCallback.completed();
}
}
@Override
@ -99,4 +231,37 @@ class AsyncProtocolExec implements AsyncExecChainHandler {
});
}
private boolean needAuthentication(
final AuthExchange targetAuthExchange,
final AuthExchange proxyAuthExchange,
final HttpRoute route,
final HttpRequest request,
final HttpResponse response,
final HttpClientContext context) {
final RequestConfig config = context.getRequestConfig();
if (config.isAuthenticationEnabled()) {
final HttpHost target = AuthSupport.resolveAuthTarget(request, route);
final boolean targetAuthRequested = authenticator.isChallenged(
target, ChallengeType.TARGET, response, targetAuthExchange, context);
HttpHost proxy = route.getProxyHost();
// if proxy is not set use target host instead
if (proxy == null) {
proxy = route.getTargetHost();
}
final boolean proxyAuthRequested = authenticator.isChallenged(
proxy, ChallengeType.PROXY, response, proxyAuthExchange, context);
if (targetAuthRequested) {
return authenticator.prepareAuthResponse(target, ChallengeType.TARGET, response,
targetAuthStrategy, targetAuthExchange, context);
}
if (proxyAuthRequested) {
return authenticator.prepareAuthResponse(proxy, ChallengeType.PROXY, response,
proxyAuthStrategy, proxyAuthExchange, context);
}
}
return false;
}
}

View File

@ -37,25 +37,46 @@ import java.util.List;
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.SystemDefaultDnsResolver;
import org.apache.hc.client5.http.async.AsyncExecChainHandler;
import org.apache.hc.client5.http.auth.AuthSchemeProvider;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.config.AuthSchemes;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.cookie.BasicCookieStore;
import org.apache.hc.client5.http.cookie.CookieSpecProvider;
import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy;
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
import org.apache.hc.client5.http.impl.DefaultUserTokenHandler;
import org.apache.hc.client5.http.impl.IdleConnectionEvictor;
import org.apache.hc.client5.http.impl.NamedElementChain;
import org.apache.hc.client5.http.impl.NoopUserTokenHandler;
import org.apache.hc.client5.http.impl.auth.BasicSchemeFactory;
import org.apache.hc.client5.http.impl.auth.CredSspSchemeFactory;
import org.apache.hc.client5.http.impl.auth.DigestSchemeFactory;
import org.apache.hc.client5.http.impl.auth.KerberosSchemeFactory;
import org.apache.hc.client5.http.impl.auth.NTLMSchemeFactory;
import org.apache.hc.client5.http.impl.auth.SPNegoSchemeFactory;
import org.apache.hc.client5.http.impl.auth.SystemDefaultCredentialsProvider;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import org.apache.hc.client5.http.impl.protocol.DefaultAuthenticationStrategy;
import org.apache.hc.client5.http.impl.protocol.DefaultRedirectStrategy;
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner;
import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
import org.apache.hc.client5.http.impl.sync.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.sync.ChainElements;
import org.apache.hc.client5.http.impl.sync.CookieSpecRegistries;
import org.apache.hc.client5.http.impl.sync.DefaultHttpRequestRetryHandler;
import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
import org.apache.hc.client5.http.protocol.AuthenticationStrategy;
import org.apache.hc.client5.http.protocol.RedirectStrategy;
import org.apache.hc.client5.http.protocol.RequestAddCookies;
import org.apache.hc.client5.http.protocol.RequestAuthCache;
import org.apache.hc.client5.http.protocol.RequestDefaultHeaders;
import org.apache.hc.client5.http.protocol.RequestExpectContinue;
import org.apache.hc.client5.http.protocol.ResponseProcessCookies;
import org.apache.hc.client5.http.protocol.UserTokenHandler;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.client5.http.sync.HttpRequestRetryHandler;
@ -72,11 +93,14 @@ import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.HttpResponseInterceptor;
import org.apache.hc.core5.http.config.CharCodingConfig;
import org.apache.hc.core5.http.config.H1Config;
import org.apache.hc.core5.http.config.Lookup;
import org.apache.hc.core5.http.config.RegistryBuilder;
import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
import org.apache.hc.core5.http.nio.AsyncPushConsumer;
import org.apache.hc.core5.http.nio.HandlerFactory;
import org.apache.hc.core5.http.nio.command.ShutdownCommand;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.http.protocol.HttpProcessor;
import org.apache.hc.core5.http.protocol.HttpProcessorBuilder;
import org.apache.hc.core5.http.protocol.RequestUserAgent;
import org.apache.hc.core5.http2.HttpVersionPolicy;
@ -179,6 +203,8 @@ public class HttpAsyncClientBuilder {
private SchemePortResolver schemePortResolver;
private ConnectionKeepAliveStrategy keepAliveStrategy;
private UserTokenHandler userTokenHandler;
private AuthenticationStrategy targetAuthStrategy;
private AuthenticationStrategy proxyAuthStrategy;
private LinkedList<RequestInterceptorEntry> requestInterceptors;
private LinkedList<ResponseInterceptorEntry> responseInterceptors;
@ -190,6 +216,11 @@ public class HttpAsyncClientBuilder {
private ConnectionReuseStrategy reuseStrategy;
private Lookup<AuthSchemeProvider> authSchemeRegistry;
private Lookup<CookieSpecProvider> cookieSpecRegistry;
private CookieStore cookieStore;
private CredentialsProvider credentialsProvider;
private String userAgent;
private HttpHost proxy;
private Collection<? extends Header> defaultHeaders;
@ -201,6 +232,8 @@ public class HttpAsyncClientBuilder {
private boolean systemProperties;
private boolean automaticRetriesDisabled;
private boolean redirectHandlingDisabled;
private boolean cookieManagementDisabled;
private boolean authCachingDisabled;
private boolean connectionStateDisabled;
private List<Closeable> closeables;
@ -307,6 +340,26 @@ public class HttpAsyncClientBuilder {
return this;
}
/**
* Assigns {@link AuthenticationStrategy} instance for target
* host authentication.
*/
public final HttpAsyncClientBuilder setTargetAuthenticationStrategy(
final AuthenticationStrategy targetAuthStrategy) {
this.targetAuthStrategy = targetAuthStrategy;
return this;
}
/**
* Assigns {@link AuthenticationStrategy} instance for proxy
* authentication.
*/
public final HttpAsyncClientBuilder setProxyAuthenticationStrategy(
final AuthenticationStrategy proxyAuthStrategy) {
this.proxyAuthStrategy = proxyAuthStrategy;
return this;
}
/**
* Adds this protocol interceptor to the head of the protocol processing list.
*/
@ -462,6 +515,45 @@ public class HttpAsyncClientBuilder {
return this;
}
/**
* Assigns default {@link CredentialsProvider} instance which will be used
* for request execution if not explicitly set in the client execution
* context.
*/
public final HttpAsyncClientBuilder setDefaultCredentialsProvider(final CredentialsProvider credentialsProvider) {
this.credentialsProvider = credentialsProvider;
return this;
}
/**
* Assigns default {@link org.apache.hc.client5.http.auth.AuthScheme} registry which will
* be used for request execution if not explicitly set in the client execution
* context.
*/
public final HttpAsyncClientBuilder setDefaultAuthSchemeRegistry(final Lookup<AuthSchemeProvider> authSchemeRegistry) {
this.authSchemeRegistry = authSchemeRegistry;
return this;
}
/**
* Assigns default {@link org.apache.hc.client5.http.cookie.CookieSpec} registry
* which will be used for request execution if not explicitly set in the client
* execution context.
*/
public final HttpAsyncClientBuilder setDefaultCookieSpecRegistry(final Lookup<CookieSpecProvider> cookieSpecRegistry) {
this.cookieSpecRegistry = cookieSpecRegistry;
return this;
}
/**
* Assigns default {@link CookieStore} instance which will be used for
* request execution if not explicitly set in the client execution context.
*/
public final HttpAsyncClientBuilder setDefaultCookieStore(final CookieStore cookieStore) {
this.cookieStore = cookieStore;
return this;
}
/**
* Assigns default {@link RequestConfig} instance which will be used
* for request execution if not explicitly set in the client execution
@ -505,6 +597,22 @@ public class HttpAsyncClientBuilder {
return this;
}
/**
* Disables state (cookie) management.
*/
public final HttpAsyncClientBuilder disableCookieManagement() {
this.cookieManagementDisabled = true;
return this;
}
/**
* Disables authentication scheme caching.
*/
public final HttpAsyncClientBuilder disableAuthCaching() {
this.authCachingDisabled = true;
return this;
}
/**
* Makes this instance of HttpClient proactively evict expired connections from the
* connection pool using a background thread.
@ -596,6 +704,15 @@ public class HttpAsyncClientBuilder {
new AsyncMainClientExec(keepAliveStrategyCopy, userTokenHandlerCopy),
ChainElements.MAIN_TRANSPORT.name());
AuthenticationStrategy targetAuthStrategyCopy = this.targetAuthStrategy;
if (targetAuthStrategyCopy == null) {
targetAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
}
AuthenticationStrategy proxyAuthStrategyCopy = this.proxyAuthStrategy;
if (proxyAuthStrategyCopy == null) {
proxyAuthStrategyCopy = DefaultAuthenticationStrategy.INSTANCE;
}
String userAgentCopy = this.userAgent;
if (userAgentCopy == null) {
if (systemProperties) {
@ -629,6 +746,15 @@ public class HttpAsyncClientBuilder {
new H2RequestConnControl(),
new RequestUserAgent(userAgentCopy),
new RequestExpectContinue());
if (!cookieManagementDisabled) {
b.add(new RequestAddCookies());
}
if (!authCachingDisabled) {
b.add(new RequestAuthCache());
}
if (!cookieManagementDisabled) {
b.add(new ResponseProcessCookies());
}
if (requestInterceptors != null) {
for (final RequestInterceptorEntry entry: requestInterceptors) {
if (entry.postion == RequestInterceptorEntry.Postion.LAST) {
@ -644,8 +770,9 @@ public class HttpAsyncClientBuilder {
}
}
final HttpProcessor httpProcessor = b.build();
execChainDefinition.addFirst(
new AsyncProtocolExec(b.build()),
new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
ChainElements.PROTOCOL.name());
// Add request retry executor, if not disabled
@ -783,6 +910,36 @@ public class HttpAsyncClientBuilder {
current = current.getPrevious();
}
Lookup<AuthSchemeProvider> authSchemeRegistryCopy = this.authSchemeRegistry;
if (authSchemeRegistryCopy == null) {
authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeProvider>create()
.register(AuthSchemes.BASIC, new BasicSchemeFactory())
.register(AuthSchemes.DIGEST, new DigestSchemeFactory())
.register(AuthSchemes.CREDSSP, new CredSspSchemeFactory())
.register(AuthSchemes.NTLM, new NTLMSchemeFactory())
.register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(SystemDefaultDnsResolver.INSTANCE, true, true))
.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory(SystemDefaultDnsResolver.INSTANCE, true, true))
.build();
}
Lookup<CookieSpecProvider> cookieSpecRegistryCopy = this.cookieSpecRegistry;
if (cookieSpecRegistryCopy == null) {
cookieSpecRegistryCopy = CookieSpecRegistries.createDefault();
}
CookieStore cookieStoreCopy = this.cookieStore;
if (cookieStoreCopy == null) {
cookieStoreCopy = new BasicCookieStore();
}
CredentialsProvider credentialsProviderCopy = this.credentialsProvider;
if (credentialsProviderCopy == null) {
if (systemProperties) {
credentialsProviderCopy = new SystemDefaultCredentialsProvider();
} else {
credentialsProviderCopy = new BasicCredentialsProvider();
}
}
return new InternalHttpAsyncClient(
ioReactor,
execChain,
@ -791,6 +948,10 @@ public class HttpAsyncClientBuilder {
connManagerCopy,
routePlannerCopy,
versionPolicy != null ? versionPolicy : HttpVersionPolicy.NEGOTIATE,
cookieSpecRegistryCopy,
authSchemeRegistryCopy,
cookieStoreCopy,
credentialsProviderCopy,
defaultRequestConfig,
closeablesCopy);
}

View File

@ -36,8 +36,12 @@ import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.async.AsyncExecCallback;
import org.apache.hc.client5.http.async.AsyncExecChain;
import org.apache.hc.client5.http.async.AsyncExecRuntime;
import org.apache.hc.client5.http.auth.AuthSchemeProvider;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.config.Configurable;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.cookie.CookieSpecProvider;
import org.apache.hc.client5.http.cookie.CookieStore;
import org.apache.hc.client5.http.impl.ExecSupport;
import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
import org.apache.hc.client5.http.protocol.HttpClientContext;
@ -49,6 +53,7 @@ import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpRequest;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.config.Lookup;
import org.apache.hc.core5.http.nio.AsyncClientExchangeHandler;
import org.apache.hc.core5.http.nio.AsyncDataConsumer;
import org.apache.hc.core5.http.nio.AsyncRequestProducer;
@ -65,6 +70,10 @@ class InternalHttpAsyncClient extends AbstractHttpAsyncClientBase {
private final AsyncExecChainElement execChain;
private final HttpRoutePlanner routePlanner;
private final HttpVersionPolicy versionPolicy;
private final Lookup<CookieSpecProvider> cookieSpecRegistry;
private final Lookup<AuthSchemeProvider> authSchemeRegistry;
private final CookieStore cookieStore;
private final CredentialsProvider credentialsProvider;
private final RequestConfig defaultConfig;
private final List<Closeable> closeables;
@ -76,6 +85,10 @@ class InternalHttpAsyncClient extends AbstractHttpAsyncClientBase {
final AsyncClientConnectionManager connmgr,
final HttpRoutePlanner routePlanner,
final HttpVersionPolicy versionPolicy,
final Lookup<CookieSpecProvider> cookieSpecRegistry,
final Lookup<AuthSchemeProvider> authSchemeRegistry,
final CookieStore cookieStore,
final CredentialsProvider credentialsProvider,
final RequestConfig defaultConfig,
final List<Closeable> closeables) {
super(ioReactor, pushConsumerRegistry, threadFactory);
@ -83,6 +96,10 @@ class InternalHttpAsyncClient extends AbstractHttpAsyncClientBase {
this.execChain = execChain;
this.routePlanner = routePlanner;
this.versionPolicy = versionPolicy;
this.cookieSpecRegistry = cookieSpecRegistry;
this.authSchemeRegistry = authSchemeRegistry;
this.cookieStore = cookieStore;
this.credentialsProvider = credentialsProvider;
this.defaultConfig = defaultConfig;
this.closeables = closeables;
}
@ -102,6 +119,18 @@ class InternalHttpAsyncClient extends AbstractHttpAsyncClientBase {
}
private void setupContext(final HttpClientContext context) {
if (context.getAttribute(HttpClientContext.AUTHSCHEME_REGISTRY) == null) {
context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, authSchemeRegistry);
}
if (context.getAttribute(HttpClientContext.COOKIESPEC_REGISTRY) == null) {
context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, cookieSpecRegistry);
}
if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
context.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore);
}
if (context.getAttribute(HttpClientContext.CREDS_PROVIDER) == null) {
context.setAttribute(HttpClientContext.CREDS_PROVIDER, credentialsProvider);
}
if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
context.setAttribute(HttpClientContext.REQUEST_CONFIG, defaultConfig);
}

View File

@ -38,7 +38,7 @@ import org.apache.hc.client5.http.auth.AuthExchange;
import org.apache.hc.client5.http.auth.ChallengeType;
import org.apache.hc.client5.http.auth.CredentialsProvider;
import org.apache.hc.client5.http.auth.CredentialsStore;
import org.apache.hc.client5.http.auth.util.CredentialSupport;
import org.apache.hc.client5.http.impl.AuthSupport;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
import org.apache.hc.client5.http.protocol.AuthenticationStrategy;
@ -131,7 +131,7 @@ final class ProtocolExec implements ExecChainHandler {
if (authority != null) {
final CredentialsProvider credsProvider = context.getCredentialsProvider();
if (credsProvider instanceof CredentialsStore) {
CredentialSupport.extractFromAuthority(authority, (CredentialsStore) credsProvider);
AuthSupport.extractFromAuthority(authority, (CredentialsStore) credsProvider);
}
}
@ -222,15 +222,7 @@ final class ProtocolExec implements ExecChainHandler {
final HttpClientContext context) {
final RequestConfig config = context.getRequestConfig();
if (config.isAuthenticationEnabled()) {
final URIAuthority authority = request.getAuthority();
final String scheme = request.getScheme();
HttpHost target = authority != null ? new HttpHost(authority, scheme) : route.getTargetHost();;
if (target.getPort() < 0) {
target = new HttpHost(
target.getHostName(),
route.getTargetHost().getPort(),
target.getSchemeName());
}
final HttpHost target = AuthSupport.resolveAuthTarget(request, route);
final boolean targetAuthRequested = authenticator.isChallenged(
target, ChallengeType.TARGET, response, targetAuthExchange, context);