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.HttpRequest;
59 import org.apache.hc.core5.http.config.Lookup;
60 import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
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.net.URIAuthority;
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 RequestConfig defaultConfig;
94 private final ConcurrentLinkedQueue<Closeable> closeables;
95
96 public InternalHttpClient(
97 final HttpClientConnectionManager connManager,
98 final HttpRequestExecutor requestExecutor,
99 final ExecChainElement execChain,
100 final HttpRoutePlanner routePlanner,
101 final Lookup<CookieSpecFactory> cookieSpecRegistry,
102 final Lookup<AuthSchemeFactory> authSchemeRegistry,
103 final CookieStore cookieStore,
104 final CredentialsProvider credentialsProvider,
105 final RequestConfig defaultConfig,
106 final List<Closeable> closeables) {
107 super();
108 this.connManager = Args.notNull(connManager, "Connection manager");
109 this.requestExecutor = Args.notNull(requestExecutor, "Request executor");
110 this.execChain = Args.notNull(execChain, "Execution chain");
111 this.routePlanner = Args.notNull(routePlanner, "Route planner");
112 this.cookieSpecRegistry = cookieSpecRegistry;
113 this.authSchemeRegistry = authSchemeRegistry;
114 this.cookieStore = cookieStore;
115 this.credentialsProvider = credentialsProvider;
116 this.defaultConfig = defaultConfig;
117 this.closeables = closeables != null ? new ConcurrentLinkedQueue<>(closeables) : null;
118 }
119
120 private HttpRoute determineRoute(
121 final HttpHost host,
122 final HttpRequest request,
123 final HttpContext context) throws HttpException {
124 final HttpHost target = host != null ? host : RoutingSupport.determineHost(request);
125 return this.routePlanner.determineRoute(target, context);
126 }
127
128 private void setupContext(final HttpClientContext context) {
129 if (context.getAttribute(HttpClientContext.AUTHSCHEME_REGISTRY) == null) {
130 context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
131 }
132 if (context.getAttribute(HttpClientContext.COOKIESPEC_REGISTRY) == null) {
133 context.setAttribute(HttpClientContext.COOKIESPEC_REGISTRY, this.cookieSpecRegistry);
134 }
135 if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
136 context.setAttribute(HttpClientContext.COOKIE_STORE, this.cookieStore);
137 }
138 if (context.getAttribute(HttpClientContext.CREDS_PROVIDER) == null) {
139 context.setAttribute(HttpClientContext.CREDS_PROVIDER, this.credentialsProvider);
140 }
141 if (context.getAttribute(HttpClientContext.REQUEST_CONFIG) == null) {
142 context.setAttribute(HttpClientContext.REQUEST_CONFIG, 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 if (request.getScheme() == null && target != null) {
154 request.setScheme(target.getSchemeName());
155 }
156 if (request.getAuthority() == null && target != null) {
157 request.setAuthority(new URIAuthority(target));
158 }
159 final HttpClientContext localcontext = HttpClientContext.adapt(
160 context != null ? context : new BasicHttpContext());
161 RequestConfig config = null;
162 if (request instanceof Configurable) {
163 config = ((Configurable) request).getConfig();
164 }
165 if (config != null) {
166 localcontext.setRequestConfig(config);
167 }
168 setupContext(localcontext);
169 final HttpRoute route = determineRoute(target, request, localcontext);
170 final String exchangeId = ExecSupport.getNextExchangeId();
171 if (LOG.isDebugEnabled()) {
172 LOG.debug("{}: preparing request execution", exchangeId);
173 }
174
175 final ExecRuntime execRuntime = new InternalExecRuntime(LOG, connManager, requestExecutor,
176 request instanceof CancellableDependency ? (CancellableDependency) request : null);
177 final ExecChain.Scope scope = new ExecChain.Scope(exchangeId, route, request, execRuntime, localcontext);
178 final ClassicHttpResponse response = this.execChain.execute(ClassicRequestCopier.INSTANCE.copy(request), scope);
179 return CloseableHttpResponse.adapt(response);
180 } catch (final HttpException httpException) {
181 throw new ClientProtocolException(httpException.getMessage(), httpException);
182 }
183 }
184
185 @Override
186 public RequestConfig getConfig() {
187 return this.defaultConfig;
188 }
189
190 @Override
191 public void close() {
192 close(CloseMode.GRACEFUL);
193 }
194
195 @Override
196 public void close(final CloseMode closeMode) {
197 if (this.closeables != null) {
198 Closeable closeable;
199 while ((closeable = this.closeables.poll()) != null) {
200 try {
201 if (closeable instanceof ModalCloseable) {
202 ((ModalCloseable) closeable).close(closeMode);
203 } else {
204 closeable.close();
205 }
206 } catch (final IOException ex) {
207 LOG.error(ex.getMessage(), ex);
208 }
209 }
210 }
211 }
212
213 }