1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.impl.classic;
29
30 import java.io.Closeable;
31 import java.io.IOException;
32 import java.util.List;
33 import java.util.concurrent.ConcurrentLinkedQueue;
34 import java.util.function.Function;
35
36 import org.apache.hc.client5.http.ClientProtocolException;
37 import org.apache.hc.client5.http.HttpRoute;
38 import org.apache.hc.client5.http.auth.AuthSchemeFactory;
39 import org.apache.hc.client5.http.auth.CredentialsProvider;
40 import org.apache.hc.client5.http.classic.ExecChain;
41 import org.apache.hc.client5.http.classic.ExecRuntime;
42 import org.apache.hc.client5.http.config.Configurable;
43 import org.apache.hc.client5.http.config.RequestConfig;
44 import org.apache.hc.client5.http.cookie.CookieSpecFactory;
45 import org.apache.hc.client5.http.cookie.CookieStore;
46 import org.apache.hc.client5.http.impl.ExecSupport;
47 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
48 import org.apache.hc.client5.http.protocol.HttpClientContext;
49 import org.apache.hc.client5.http.routing.HttpRoutePlanner;
50 import org.apache.hc.client5.http.routing.RoutingSupport;
51 import org.apache.hc.core5.annotation.Contract;
52 import org.apache.hc.core5.annotation.Internal;
53 import org.apache.hc.core5.annotation.ThreadingBehavior;
54 import org.apache.hc.core5.concurrent.CancellableDependency;
55 import org.apache.hc.core5.http.ClassicHttpRequest;
56 import org.apache.hc.core5.http.ClassicHttpResponse;
57 import org.apache.hc.core5.http.HttpException;
58 import org.apache.hc.core5.http.HttpHost;
59 import org.apache.hc.core5.http.HttpRequest;
60 import org.apache.hc.core5.http.config.Lookup;
61 import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
62 import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
63 import org.apache.hc.core5.http.protocol.HttpContext;
64 import org.apache.hc.core5.io.CloseMode;
65 import org.apache.hc.core5.io.ModalCloseable;
66 import org.apache.hc.core5.util.Args;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70
71
72
73
74
75
76
77
78
79 @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
80 @Internal
81 class InternalHttpClient extends CloseableHttpClient implements Configurable {
82
83 private static final Logger LOG = LoggerFactory.getLogger(InternalHttpClient.class);
84
85 private final HttpClientConnectionManager connManager;
86 private final HttpRequestExecutor requestExecutor;
87 private final ExecChainElement execChain;
88 private final HttpRoutePlanner routePlanner;
89 private final Lookup<CookieSpecFactory> cookieSpecRegistry;
90 private final Lookup<AuthSchemeFactory> authSchemeRegistry;
91 private final CookieStore cookieStore;
92 private final CredentialsProvider credentialsProvider;
93 private final Function<HttpContext, HttpClientContext> contextAdaptor;
94 private final RequestConfig defaultConfig;
95 private final ConcurrentLinkedQueue<Closeable> closeables;
96
97 public InternalHttpClient(
98 final HttpClientConnectionManager connManager,
99 final HttpRequestExecutor requestExecutor,
100 final ExecChainElement execChain,
101 final HttpRoutePlanner routePlanner,
102 final Lookup<CookieSpecFactory> cookieSpecRegistry,
103 final Lookup<AuthSchemeFactory> authSchemeRegistry,
104 final CookieStore cookieStore,
105 final CredentialsProvider credentialsProvider,
106 final Function<HttpContext, HttpClientContext> contextAdaptor,
107 final RequestConfig defaultConfig,
108 final List<Closeable> closeables) {
109 super();
110 this.connManager = Args.notNull(connManager, "Connection manager");
111 this.requestExecutor = Args.notNull(requestExecutor, "Request executor");
112 this.execChain = Args.notNull(execChain, "Execution chain");
113 this.routePlanner = Args.notNull(routePlanner, "Route planner");
114 this.cookieSpecRegistry = cookieSpecRegistry;
115 this.authSchemeRegistry = authSchemeRegistry;
116 this.cookieStore = cookieStore;
117 this.credentialsProvider = credentialsProvider;
118 this.contextAdaptor = contextAdaptor;
119 this.defaultConfig = defaultConfig;
120 this.closeables = closeables != null ? new ConcurrentLinkedQueue<>(closeables) : null;
121 }
122
123 private HttpRoute determineRoute(final HttpHost target, final HttpRequest request, final HttpContext context) throws HttpException {
124 return this.routePlanner.determineRoute(target, request, context);
125 }
126
127 private void setupContext(final HttpClientContext context) {
128 if (context.getAuthSchemeRegistry() == null) {
129 context.setAuthSchemeRegistry(this.authSchemeRegistry);
130 }
131 if (context.getCookieSpecRegistry() == null) {
132 context.setCookieSpecRegistry(this.cookieSpecRegistry);
133 }
134 if (context.getCookieStore() == null) {
135 context.setCookieStore(this.cookieStore);
136 }
137 if (context.getCredentialsProvider() == null) {
138 context.setCredentialsProvider(this.credentialsProvider);
139 }
140 if (context.getRequestConfig() == null) {
141 context.setRequestConfig(this.defaultConfig);
142 }
143 }
144
145 @Override
146 protected CloseableHttpResponse doExecute(
147 final HttpHost target,
148 final ClassicHttpRequest request,
149 final HttpContext context) throws IOException {
150 Args.notNull(request, "HTTP request");
151 try {
152 final HttpClientContext localcontext = contextAdaptor.apply(context);
153 RequestConfig config = null;
154 if (request instanceof Configurable) {
155 config = ((Configurable) request).getConfig();
156 }
157 if (config != null) {
158 localcontext.setRequestConfig(config);
159 }
160 setupContext(localcontext);
161 final HttpRoute route = determineRoute(
162 target != null ? target : RoutingSupport.determineHost(request),
163 request,
164 localcontext);
165 final String exchangeId = ExecSupport.getNextExchangeId();
166 localcontext.setExchangeId(exchangeId);
167 if (LOG.isDebugEnabled()) {
168 LOG.debug("{} preparing request execution", exchangeId);
169 }
170
171 final ExecRuntime execRuntime = new InternalExecRuntime(LOG, connManager, requestExecutor,
172 request instanceof CancellableDependency ? (CancellableDependency) request : null);
173 final ExecChain.Scope scope = new ExecChain.Scope(exchangeId, route, request, execRuntime, localcontext);
174 final ClassicHttpResponse response = this.execChain.execute(ClassicRequestBuilder.copy(request).build(), scope);
175 return CloseableHttpResponse.adapt(response);
176 } catch (final HttpException httpException) {
177 throw new ClientProtocolException(httpException.getMessage(), httpException);
178 }
179 }
180
181 @Override
182 public RequestConfig getConfig() {
183 return this.defaultConfig;
184 }
185
186 @Override
187 public void close() {
188 close(CloseMode.GRACEFUL);
189 }
190
191 @Override
192 public void close(final CloseMode closeMode) {
193 if (this.closeables != null) {
194 Closeable closeable;
195 while ((closeable = this.closeables.poll()) != null) {
196 try {
197 if (closeable instanceof ModalCloseable) {
198 ((ModalCloseable) closeable).close(closeMode);
199 } else {
200 closeable.close();
201 }
202 } catch (final IOException ex) {
203 LOG.error(ex.getMessage(), ex);
204 }
205 }
206 }
207 }
208
209 }