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 package org.apache.http.impl.conn;
28
29 import java.io.IOException;
30 import java.io.InterruptedIOException;
31 import java.net.InetAddress;
32 import java.net.Socket;
33 import java.util.concurrent.TimeUnit;
34
35 import javax.net.ssl.SSLSession;
36 import javax.net.ssl.SSLSocket;
37
38 import org.apache.http.HttpConnectionMetrics;
39 import org.apache.http.HttpEntityEnclosingRequest;
40 import org.apache.http.HttpException;
41 import org.apache.http.HttpHost;
42 import org.apache.http.HttpRequest;
43 import org.apache.http.HttpResponse;
44 import org.apache.http.annotation.NotThreadSafe;
45 import org.apache.http.conn.ClientConnectionManager;
46 import org.apache.http.conn.ClientConnectionOperator;
47 import org.apache.http.conn.ManagedClientConnection;
48 import org.apache.http.conn.OperatedClientConnection;
49 import org.apache.http.conn.routing.HttpRoute;
50 import org.apache.http.conn.routing.RouteTracker;
51 import org.apache.http.params.HttpParams;
52 import org.apache.http.protocol.HttpContext;
53
54 @NotThreadSafe
55 class ManagedClientConnectionImpl implements ManagedClientConnection {
56
57 private final ClientConnectionManager manager;
58 private final ClientConnectionOperator operator;
59 private volatile HttpPoolEntry poolEntry;
60 private volatile boolean reusable;
61 private volatile long duration;
62
63 ManagedClientConnectionImpl(
64 final ClientConnectionManager manager,
65 final ClientConnectionOperator operator,
66 final HttpPoolEntry entry) {
67 super();
68 if (manager == null) {
69 throw new IllegalArgumentException("Connection manager may not be null");
70 }
71 if (operator == null) {
72 throw new IllegalArgumentException("Connection operator may not be null");
73 }
74 if (entry == null) {
75 throw new IllegalArgumentException("HTTP pool entry may not be null");
76 }
77 this.manager = manager;
78 this.operator = operator;
79 this.poolEntry = entry;
80 this.reusable = false;
81 this.duration = Long.MAX_VALUE;
82 }
83
84 HttpPoolEntry getPoolEntry() {
85 return this.poolEntry;
86 }
87
88 HttpPoolEntry detach() {
89 HttpPoolEntry local = this.poolEntry;
90 this.poolEntry = null;
91 return local;
92 }
93
94 public ClientConnectionManager getManager() {
95 return this.manager;
96 }
97
98 private OperatedClientConnection getConnection() {
99 HttpPoolEntry local = this.poolEntry;
100 if (local == null) {
101 return null;
102 }
103 return local.getConnection();
104 }
105
106 private OperatedClientConnection ensureConnection() {
107 HttpPoolEntry local = this.poolEntry;
108 if (local == null) {
109 throw new ConnectionShutdownException();
110 }
111 return local.getConnection();
112 }
113
114 private HttpPoolEntry ensurePoolEntry() {
115 HttpPoolEntry local = this.poolEntry;
116 if (local == null) {
117 throw new ConnectionShutdownException();
118 }
119 return local;
120 }
121
122 public void close() throws IOException {
123 HttpPoolEntry local = this.poolEntry;
124 if (local != null) {
125 OperatedClientConnection conn = local.getConnection();
126 local.getTracker().reset();
127 conn.close();
128 }
129 }
130
131 public void shutdown() throws IOException {
132 HttpPoolEntry local = this.poolEntry;
133 if (local != null) {
134 OperatedClientConnection conn = local.getConnection();
135 local.getTracker().reset();
136 conn.shutdown();
137 }
138 }
139
140 public boolean isOpen() {
141 OperatedClientConnection conn = getConnection();
142 if (conn != null) {
143 return conn.isOpen();
144 } else {
145 return false;
146 }
147 }
148
149 public boolean isStale() {
150 OperatedClientConnection conn = getConnection();
151 if (conn != null) {
152 return conn.isStale();
153 } else {
154 return true;
155 }
156 }
157
158 public void setSocketTimeout(int timeout) {
159 OperatedClientConnection conn = ensureConnection();
160 conn.setSocketTimeout(timeout);
161 }
162
163 public int getSocketTimeout() {
164 OperatedClientConnection conn = ensureConnection();
165 return conn.getSocketTimeout();
166 }
167
168 public HttpConnectionMetrics getMetrics() {
169 OperatedClientConnection conn = ensureConnection();
170 return conn.getMetrics();
171 }
172
173 public void flush() throws IOException {
174 OperatedClientConnection conn = ensureConnection();
175 conn.flush();
176 }
177
178 public boolean isResponseAvailable(int timeout) throws IOException {
179 OperatedClientConnection conn = ensureConnection();
180 return conn.isResponseAvailable(timeout);
181 }
182
183 public void receiveResponseEntity(
184 final HttpResponse response) throws HttpException, IOException {
185 OperatedClientConnection conn = ensureConnection();
186 conn.receiveResponseEntity(response);
187 }
188
189 public HttpResponse receiveResponseHeader() throws HttpException, IOException {
190 OperatedClientConnection conn = ensureConnection();
191 return conn.receiveResponseHeader();
192 }
193
194 public void sendRequestEntity(
195 final HttpEntityEnclosingRequest request) throws HttpException, IOException {
196 OperatedClientConnection conn = ensureConnection();
197 conn.sendRequestEntity(request);
198 }
199
200 public void sendRequestHeader(
201 final HttpRequest request) throws HttpException, IOException {
202 OperatedClientConnection conn = ensureConnection();
203 conn.sendRequestHeader(request);
204 }
205
206 public InetAddress getLocalAddress() {
207 OperatedClientConnection conn = ensureConnection();
208 return conn.getLocalAddress();
209 }
210
211 public int getLocalPort() {
212 OperatedClientConnection conn = ensureConnection();
213 return conn.getLocalPort();
214 }
215
216 public InetAddress getRemoteAddress() {
217 OperatedClientConnection conn = ensureConnection();
218 return conn.getRemoteAddress();
219 }
220
221 public int getRemotePort() {
222 OperatedClientConnection conn = ensureConnection();
223 return conn.getRemotePort();
224 }
225
226 public boolean isSecure() {
227 OperatedClientConnection conn = ensureConnection();
228 return conn.isSecure();
229 }
230
231 public SSLSession getSSLSession() {
232 OperatedClientConnection conn = ensureConnection();
233 SSLSession result = null;
234 Socket sock = conn.getSocket();
235 if (sock instanceof SSLSocket) {
236 result = ((SSLSocket)sock).getSession();
237 }
238 return result;
239 }
240
241 public Object getAttribute(final String id) {
242 OperatedClientConnection conn = ensureConnection();
243 if (conn instanceof HttpContext) {
244 return ((HttpContext) conn).getAttribute(id);
245 } else {
246 return null;
247 }
248 }
249
250 public Object removeAttribute(final String id) {
251 OperatedClientConnection conn = ensureConnection();
252 if (conn instanceof HttpContext) {
253 return ((HttpContext) conn).removeAttribute(id);
254 } else {
255 return null;
256 }
257 }
258
259 public void setAttribute(final String id, final Object obj) {
260 OperatedClientConnection conn = ensureConnection();
261 if (conn instanceof HttpContext) {
262 ((HttpContext) conn).setAttribute(id, obj);
263 }
264 }
265
266 public HttpRoute getRoute() {
267 HttpPoolEntry local = ensurePoolEntry();
268 return local.getEffectiveRoute();
269 }
270
271 public void open(
272 final HttpRoute route,
273 final HttpContext context,
274 final HttpParams params) throws IOException {
275 if (route == null) {
276 throw new IllegalArgumentException("Route may not be null");
277 }
278 if (params == null) {
279 throw new IllegalArgumentException("HTTP parameters may not be null");
280 }
281 OperatedClientConnection conn;
282 synchronized (this) {
283 if (this.poolEntry == null) {
284 throw new ConnectionShutdownException();
285 }
286 RouteTracker tracker = this.poolEntry.getTracker();
287 if (tracker.isConnected()) {
288 throw new IllegalStateException("Connection already open");
289 }
290 conn = this.poolEntry.getConnection();
291 }
292
293 HttpHost proxy = route.getProxyHost();
294 this.operator.openConnection(
295 conn,
296 (proxy != null) ? proxy : route.getTargetHost(),
297 route.getLocalAddress(),
298 context, params);
299
300 synchronized (this) {
301 if (this.poolEntry == null) {
302 throw new InterruptedIOException();
303 }
304 RouteTracker tracker = this.poolEntry.getTracker();
305 if (proxy == null) {
306 tracker.connectTarget(conn.isSecure());
307 } else {
308 tracker.connectProxy(proxy, conn.isSecure());
309 }
310 }
311 }
312
313 public void tunnelTarget(
314 boolean secure, final HttpParams params) throws IOException {
315 if (params == null) {
316 throw new IllegalArgumentException("HTTP parameters may not be null");
317 }
318 HttpHost target;
319 OperatedClientConnection conn;
320 synchronized (this) {
321 if (this.poolEntry == null) {
322 throw new ConnectionShutdownException();
323 }
324 RouteTracker tracker = this.poolEntry.getTracker();
325 if (!tracker.isConnected()) {
326 throw new IllegalStateException("Connection not open");
327 }
328 if (tracker.isTunnelled()) {
329 throw new IllegalStateException("Connection is already tunnelled");
330 }
331 target = tracker.getTargetHost();
332 conn = this.poolEntry.getConnection();
333 }
334
335 conn.update(null, target, secure, params);
336
337 synchronized (this) {
338 if (this.poolEntry == null) {
339 throw new InterruptedIOException();
340 }
341 RouteTracker tracker = this.poolEntry.getTracker();
342 tracker.tunnelTarget(secure);
343 }
344 }
345
346 public void tunnelProxy(
347 final HttpHost next, boolean secure, final HttpParams params) throws IOException {
348 if (next == null) {
349 throw new IllegalArgumentException("Next proxy amy not be null");
350 }
351 if (params == null) {
352 throw new IllegalArgumentException("HTTP parameters may not be null");
353 }
354 OperatedClientConnection conn;
355 synchronized (this) {
356 if (this.poolEntry == null) {
357 throw new ConnectionShutdownException();
358 }
359 RouteTracker tracker = this.poolEntry.getTracker();
360 if (!tracker.isConnected()) {
361 throw new IllegalStateException("Connection not open");
362 }
363 conn = this.poolEntry.getConnection();
364 }
365
366 conn.update(null, next, secure, params);
367
368 synchronized (this) {
369 if (this.poolEntry == null) {
370 throw new InterruptedIOException();
371 }
372 RouteTracker tracker = this.poolEntry.getTracker();
373 tracker.tunnelProxy(next, secure);
374 }
375 }
376
377 public void layerProtocol(
378 final HttpContext context, final HttpParams params) throws IOException {
379 if (params == null) {
380 throw new IllegalArgumentException("HTTP parameters may not be null");
381 }
382 HttpHost target;
383 OperatedClientConnection conn;
384 synchronized (this) {
385 if (this.poolEntry == null) {
386 throw new ConnectionShutdownException();
387 }
388 RouteTracker tracker = this.poolEntry.getTracker();
389 if (!tracker.isConnected()) {
390 throw new IllegalStateException("Connection not open");
391 }
392 if (!tracker.isTunnelled()) {
393 throw new IllegalStateException("Protocol layering without a tunnel not supported");
394 }
395 if (tracker.isLayered()) {
396 throw new IllegalStateException("Multiple protocol layering not supported");
397 }
398 target = tracker.getTargetHost();
399 conn = this.poolEntry.getConnection();
400 }
401 this.operator.updateSecureConnection(conn, target, context, params);
402
403 synchronized (this) {
404 if (this.poolEntry == null) {
405 throw new InterruptedIOException();
406 }
407 RouteTracker tracker = this.poolEntry.getTracker();
408 tracker.layerProtocol(conn.isSecure());
409 }
410 }
411
412 public Object getState() {
413 HttpPoolEntry local = ensurePoolEntry();
414 return local.getState();
415 }
416
417 public void setState(final Object state) {
418 HttpPoolEntry local = ensurePoolEntry();
419 local.setState(state);
420 }
421
422 public void markReusable() {
423 this.reusable = true;
424 }
425
426 public void unmarkReusable() {
427 this.reusable = false;
428 }
429
430 public boolean isMarkedReusable() {
431 return this.reusable;
432 }
433
434 public void setIdleDuration(long duration, TimeUnit unit) {
435 if(duration > 0) {
436 this.duration = unit.toMillis(duration);
437 } else {
438 this.duration = -1;
439 }
440 }
441
442 public void releaseConnection() {
443 synchronized (this) {
444 if (this.poolEntry == null) {
445 return;
446 }
447 this.manager.releaseConnection(this, this.duration, TimeUnit.MILLISECONDS);
448 this.poolEntry = null;
449 }
450 }
451
452 public void abortConnection() {
453 synchronized (this) {
454 if (this.poolEntry == null) {
455 return;
456 }
457 this.reusable = false;
458 OperatedClientConnection conn = this.poolEntry.getConnection();
459 try {
460 conn.shutdown();
461 } catch (IOException ignore) {
462 }
463 this.manager.releaseConnection(this, this.duration, TimeUnit.MILLISECONDS);
464 this.poolEntry = null;
465 }
466 }
467
468 }