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.IOException;
31 import java.io.InterruptedIOException;
32
33 import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
34 import org.apache.hc.client5.http.HttpRoute;
35 import org.apache.hc.client5.http.UserTokenHandler;
36 import org.apache.hc.client5.http.classic.ExecChain;
37 import org.apache.hc.client5.http.classic.ExecChainHandler;
38 import org.apache.hc.client5.http.classic.ExecRuntime;
39 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
40 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
41 import org.apache.hc.client5.http.protocol.HttpClientContext;
42 import org.apache.hc.core5.annotation.Contract;
43 import org.apache.hc.core5.annotation.Internal;
44 import org.apache.hc.core5.annotation.ThreadingBehavior;
45 import org.apache.hc.core5.http.ClassicHttpRequest;
46 import org.apache.hc.core5.http.ClassicHttpResponse;
47 import org.apache.hc.core5.http.ConnectionReuseStrategy;
48 import org.apache.hc.core5.http.HttpEntity;
49 import org.apache.hc.core5.http.HttpException;
50 import org.apache.hc.core5.http.message.RequestLine;
51 import org.apache.hc.core5.io.CloseMode;
52 import org.apache.hc.core5.util.Args;
53 import org.apache.hc.core5.util.TimeValue;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57
58
59
60
61
62
63
64 @Contract(threading = ThreadingBehavior.STATELESS)
65 @Internal
66 public final class MainClientExec implements ExecChainHandler {
67
68 private static final Logger LOG = LoggerFactory.getLogger(MainClientExec.class);
69
70 private final HttpClientConnectionManager connectionManager;
71 private final ConnectionReuseStrategy reuseStrategy;
72 private final ConnectionKeepAliveStrategy keepAliveStrategy;
73 private final UserTokenHandler userTokenHandler;
74
75
76
77
78 public MainClientExec(
79 final HttpClientConnectionManager connectionManager,
80 final ConnectionReuseStrategy reuseStrategy,
81 final ConnectionKeepAliveStrategy keepAliveStrategy,
82 final UserTokenHandler userTokenHandler) {
83 this.connectionManager = Args.notNull(connectionManager, "Connection manager");
84 this.reuseStrategy = Args.notNull(reuseStrategy, "Connection reuse strategy");
85 this.keepAliveStrategy = Args.notNull(keepAliveStrategy, "Connection keep alive strategy");
86 this.userTokenHandler = Args.notNull(userTokenHandler, "User token handler");
87 }
88
89 @Override
90 public ClassicHttpResponse execute(
91 final ClassicHttpRequest request,
92 final ExecChain.Scope scope,
93 final ExecChain chain) throws IOException, HttpException {
94 Args.notNull(request, "HTTP request");
95 Args.notNull(scope, "Scope");
96 final String exchangeId = scope.exchangeId;
97 final HttpRoute route = scope.route;
98 final HttpClientContext context = scope.clientContext;
99 final ExecRuntime execRuntime = scope.execRuntime;
100
101 if (LOG.isDebugEnabled()) {
102 LOG.debug("{} executing {}", exchangeId, new RequestLine(request));
103 }
104 try {
105 final ClassicHttpResponse response = execRuntime.execute(exchangeId, request, context);
106
107 Object userToken = context.getUserToken();
108 if (userToken == null) {
109 userToken = userTokenHandler.getUserToken(route, context);
110 context.setAttribute(HttpClientContext.USER_TOKEN, userToken);
111 }
112
113
114 if (reuseStrategy.keepAlive(request, response, context)) {
115
116 final TimeValue duration = keepAliveStrategy.getKeepAliveDuration(response, context);
117 if (LOG.isDebugEnabled()) {
118 final String s;
119 if (duration != null) {
120 s = "for " + duration;
121 } else {
122 s = "indefinitely";
123 }
124 LOG.debug("{} connection can be kept alive {}", exchangeId, s);
125 }
126 execRuntime.markConnectionReusable(userToken, duration);
127 } else {
128 execRuntime.markConnectionNonReusable();
129 }
130
131 final HttpEntity entity = response.getEntity();
132 if (entity == null || !entity.isStreaming()) {
133
134 execRuntime.releaseEndpoint();
135 return new CloseableHttpResponse(response, null);
136 }
137 return new CloseableHttpResponse(response, execRuntime);
138 } catch (final ConnectionShutdownException ex) {
139 final InterruptedIOException ioex = new InterruptedIOException(
140 "Connection has been shut down");
141 ioex.initCause(ex);
142 execRuntime.discardEndpoint();
143 throw ioex;
144 } catch (final HttpException | RuntimeException | IOException ex) {
145 execRuntime.discardEndpoint();
146 throw ex;
147 } catch (final Error error) {
148 connectionManager.close(CloseMode.IMMEDIATE);
149 throw error;
150 }
151
152 }
153
154 }