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.net.URIAuthority;
67 import org.apache.hc.core5.util.Args;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71
72
73
74
75
76
77
78
79
80 @Contract(threading = ThreadingBehavior.SAFE_CONDITIONAL)
81 @Internal
82 class InternalHttpClient extends CloseableHttpClient implements Configurable {
83
84 private static final Logger LOG = LoggerFactory.getLogger(InternalHttpClient.class);
85
86 private final HttpClientConnectionManager connManager;
87 private final HttpRequestExecutor requestExecutor;
88 private final ExecChainElement execChain;
89 private final HttpRoutePlanner routePlanner;
90 private final Lookup<CookieSpecFactory> cookieSpecRegistry;
91 private final Lookup<AuthSchemeFactory> authSchemeRegistry;
92 private final CookieStore cookieStore;
93 private final CredentialsProvider credentialsProvider;
94 private final Function<HttpContext, HttpClientContext> contextAdaptor;
95 private final RequestConfig defaultConfig;
96 private final ConcurrentLinkedQueue<Closeable> closeables;
97
98 public InternalHttpClient(
99 final HttpClientConnectionManager connManager,
100 final HttpRequestExecutor requestExecutor,
101 final ExecChainElement execChain,
102 final HttpRoutePlanner routePlanner,
103 final Lookup<CookieSpecFactory> cookieSpecRegistry,
104 final Lookup<AuthSchemeFactory> authSchemeRegistry,
105 final CookieStore cookieStore,
106 final CredentialsProvider credentialsProvider,
107 final Function<HttpContext, HttpClientContext> contextAdaptor,
108 final RequestConfig defaultConfig,
109 final List<Closeable> closeables) {
110 super();
111 this.connManager = Args.notNull(connManager, "Connection manager");
112 this.requestExecutor = Args.notNull(requestExecutor, "Request executor");
113 this.execChain = Args.notNull(execChain, "Execution chain");
114 this.routePlanner = Args.notNull(routePlanner, "Route planner");
115 this.cookieSpecRegistry = cookieSpecRegistry;
116 this.authSchemeRegistry = authSchemeRegistry;
117 this.cookieStore = cookieStore;
118 this.credentialsProvider = credentialsProvider;
119 this.contextAdaptor = contextAdaptor;
120 this.defaultConfig = defaultConfig;
121 this.closeables = closeables != null ? new ConcurrentLinkedQueue<>(closeables) : null;
122 }
123
124 private HttpRoute determineRoute(final HttpHost target, final HttpRequest request, final HttpContext context) throws HttpException {
125 return this.routePlanner.determineRoute(target, request, context);
126 }
127
128 private void setupContext(final HttpClientContext context) {
129 if (context.getAuthSchemeRegistry() == null) {
130 context.setAuthSchemeRegistry(this.authSchemeRegistry);
131 }
132 if (context.getCookieSpecRegistry() == null) {
133 context.setCookieSpecRegistry(this.cookieSpecRegistry);
134 }
135 if (context.getCookieStore() == null) {
136 context.setCookieStore(this.cookieStore);
137 }
138 if (context.getCredentialsProvider() == null) {
139 context.setCredentialsProvider(this.credentialsProvider);
140 }
141 if (context.getRequestConfig() == null) {
142 context.setRequestConfig(this.defaultConfig);
143 }
144 }
145
146 @Override
147 protected CloseableHttpResponse doExecute(
148 final HttpHost target,
149 final ClassicHttpRequest request,
150 final HttpContext context) throws IOException {
151 Args.notNull(request, "HTTP request");
152 try {
153 final HttpClientContext localcontext = contextAdaptor.apply(context);
154 RequestConfig config = null;
155 if (request instanceof Configurable) {
156 config = ((Configurable) request).getConfig();
157 }
158 if (config != null) {
159 localcontext.setRequestConfig(config);
160 }
161 setupContext(localcontext);
162
163 final HttpHost resolvedTarget = target != null ? target : RoutingSupport.determineHost(request);
164 if (resolvedTarget != null) {
165 if (request.getScheme() == null) {
166 request.setScheme(resolvedTarget.getSchemeName());
167 }
168 if (request.getAuthority() == null) {
169 request.setAuthority(new URIAuthority(resolvedTarget));
170 }
171 }
172 final HttpRoute route = determineRoute(
173 resolvedTarget,
174 request,
175 localcontext);
176 final String exchangeId = ExecSupport.getNextExchangeId();
177 localcontext.setExchangeId(exchangeId);
178 if (LOG.isDebugEnabled()) {
179 LOG.debug("{} preparing request execution", exchangeId);
180 }
181
182 final ExecRuntime execRuntime = new InternalExecRuntime(LOG, connManager, requestExecutor,
183 request instanceof CancellableDependency ? (CancellableDependency) request : null);
184 final ExecChain.Scope scope = new ExecChain.Scope(exchangeId, route, request, execRuntime, localcontext);
185 final ClassicHttpResponse response = this.execChain.execute(ClassicRequestBuilder.copy(request).build(), scope);
186 return CloseableHttpResponse.adapt(response);
187 } catch (final HttpException httpException) {
188 throw new ClientProtocolException(httpException.getMessage(), httpException);
189 }
190 }
191
192 @Override
193 public RequestConfig getConfig() {
194 return this.defaultConfig;
195 }
196
197 @Override
198 public void close() {
199 close(CloseMode.GRACEFUL);
200 }
201
202 @Override
203 public void close(final CloseMode closeMode) {
204 if (this.closeables != null) {
205 Closeable closeable;
206 while ((closeable = this.closeables.poll()) != null) {
207 try {
208 if (closeable instanceof ModalCloseable) {
209 ((ModalCloseable) closeable).close(closeMode);
210 } else {
211 closeable.close();
212 }
213 } catch (final IOException ex) {
214 LOG.error(ex.getMessage(), ex);
215 }
216 }
217 }
218 }
219
220 }