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