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.http.nio.protocol;
29
30 import java.io.IOException;
31
32 import org.apache.http.ConnectionReuseStrategy;
33 import org.apache.http.HttpEntity;
34 import org.apache.http.HttpEntityEnclosingRequest;
35 import org.apache.http.HttpException;
36 import org.apache.http.HttpRequest;
37 import org.apache.http.HttpResponse;
38 import org.apache.http.HttpStatus;
39 import org.apache.http.annotation.Immutable;
40 import org.apache.http.nio.ContentDecoder;
41 import org.apache.http.nio.ContentEncoder;
42 import org.apache.http.nio.NHttpClientConnection;
43 import org.apache.http.nio.NHttpClientHandler;
44 import org.apache.http.nio.entity.ConsumingNHttpEntity;
45 import org.apache.http.nio.entity.NHttpEntityWrapper;
46 import org.apache.http.nio.entity.ProducingNHttpEntity;
47 import org.apache.http.nio.util.ByteBufferAllocator;
48 import org.apache.http.nio.util.HeapByteBufferAllocator;
49 import org.apache.http.params.CoreProtocolPNames;
50 import org.apache.http.params.DefaultedHttpParams;
51 import org.apache.http.params.HttpParams;
52 import org.apache.http.protocol.ExecutionContext;
53 import org.apache.http.protocol.HttpContext;
54 import org.apache.http.protocol.HttpProcessor;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 @Deprecated
93 @Immutable
94 public class AsyncNHttpClientHandler extends NHttpHandlerBase
95 implements NHttpClientHandler {
96
97 protected NHttpRequestExecutionHandler execHandler;
98
99 public AsyncNHttpClientHandler(
100 final HttpProcessor httpProcessor,
101 final NHttpRequestExecutionHandler execHandler,
102 final ConnectionReuseStrategy connStrategy,
103 final ByteBufferAllocator allocator,
104 final HttpParams params) {
105 super(httpProcessor, connStrategy, allocator, params);
106 if (execHandler == null) {
107 throw new IllegalArgumentException("HTTP request execution handler may not be null.");
108 }
109 this.execHandler = execHandler;
110 }
111
112 public AsyncNHttpClientHandler(
113 final HttpProcessor httpProcessor,
114 final NHttpRequestExecutionHandler execHandler,
115 final ConnectionReuseStrategy connStrategy,
116 final HttpParams params) {
117 this(httpProcessor, execHandler, connStrategy,
118 new HeapByteBufferAllocator(), params);
119 }
120
121 public void connected(final NHttpClientConnection conn, final Object attachment) {
122 HttpContext context = conn.getContext();
123
124 initialize(conn, attachment);
125
126 ClientConnState connState = new ClientConnState();
127 context.setAttribute(CONN_STATE, connState);
128
129 if (this.eventListener != null) {
130 this.eventListener.connectionOpen(conn);
131 }
132
133 requestReady(conn);
134 }
135
136 public void closed(final NHttpClientConnection conn) {
137 HttpContext context = conn.getContext();
138
139 ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
140 try {
141 connState.reset();
142 } catch (IOException ex) {
143 if (this.eventListener != null) {
144 this.eventListener.fatalIOException(ex, conn);
145 }
146 }
147
148 this.execHandler.finalizeContext(context);
149
150 if (this.eventListener != null) {
151 this.eventListener.connectionClosed(conn);
152 }
153 }
154
155 public void exception(final NHttpClientConnection conn, final HttpException ex) {
156 closeConnection(conn, ex);
157 if (this.eventListener != null) {
158 this.eventListener.fatalProtocolException(ex, conn);
159 }
160 }
161
162 public void exception(final NHttpClientConnection conn, final IOException ex) {
163 shutdownConnection(conn, ex);
164 if (this.eventListener != null) {
165 this.eventListener.fatalIOException(ex, conn);
166 }
167 }
168
169 public void requestReady(final NHttpClientConnection conn) {
170 HttpContext context = conn.getContext();
171
172 ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
173 if (connState.getOutputState() != ClientConnState.READY) {
174 return;
175 }
176
177 try {
178
179 HttpRequest request = this.execHandler.submitRequest(context);
180 if (request == null) {
181 return;
182 }
183
184 request.setParams(
185 new DefaultedHttpParams(request.getParams(), this.params));
186
187 context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
188 this.httpProcessor.process(request, context);
189
190 HttpEntityEnclosingRequest entityReq = null;
191 HttpEntity entity = null;
192
193 if (request instanceof HttpEntityEnclosingRequest) {
194 entityReq = (HttpEntityEnclosingRequest) request;
195 entity = entityReq.getEntity();
196 }
197
198 if (entity instanceof ProducingNHttpEntity) {
199 connState.setProducingEntity((ProducingNHttpEntity) entity);
200 } else if (entity != null) {
201 connState.setProducingEntity(new NHttpEntityWrapper(entity));
202 }
203
204 connState.setRequest(request);
205 conn.submitRequest(request);
206 connState.setOutputState(ClientConnState.REQUEST_SENT);
207
208 if (entityReq != null && entityReq.expectContinue()) {
209 int timeout = conn.getSocketTimeout();
210 connState.setTimeout(timeout);
211 timeout = this.params.getIntParameter(
212 CoreProtocolPNames.WAIT_FOR_CONTINUE, 3000);
213 conn.setSocketTimeout(timeout);
214 connState.setOutputState(ClientConnState.EXPECT_CONTINUE);
215 } else if (connState.getProducingEntity() != null) {
216 connState.setOutputState(ClientConnState.REQUEST_BODY_STREAM);
217 }
218
219 } catch (IOException ex) {
220 shutdownConnection(conn, ex);
221 if (this.eventListener != null) {
222 this.eventListener.fatalIOException(ex, conn);
223 }
224 } catch (HttpException ex) {
225 closeConnection(conn, ex);
226 if (this.eventListener != null) {
227 this.eventListener.fatalProtocolException(ex, conn);
228 }
229 }
230 }
231
232 public void inputReady(final NHttpClientConnection conn, final ContentDecoder decoder) {
233 HttpContext context = conn.getContext();
234
235 ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
236
237 ConsumingNHttpEntity consumingEntity = connState.getConsumingEntity();
238
239 try {
240 consumingEntity.consumeContent(decoder, conn);
241 if (decoder.isCompleted()) {
242 processResponse(conn, connState);
243 }
244
245 } catch (IOException ex) {
246 shutdownConnection(conn, ex);
247 if (this.eventListener != null) {
248 this.eventListener.fatalIOException(ex, conn);
249 }
250 } catch (HttpException ex) {
251 closeConnection(conn, ex);
252 if (this.eventListener != null) {
253 this.eventListener.fatalProtocolException(ex, conn);
254 }
255 }
256 }
257
258 public void outputReady(final NHttpClientConnection conn, final ContentEncoder encoder) {
259 HttpContext context = conn.getContext();
260 ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
261
262 try {
263 if (connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
264 conn.suspendOutput();
265 return;
266 }
267
268 ProducingNHttpEntity entity = connState.getProducingEntity();
269
270 entity.produceContent(encoder, conn);
271 if (encoder.isCompleted()) {
272 connState.setOutputState(ClientConnState.REQUEST_BODY_DONE);
273 }
274 } catch (IOException ex) {
275 shutdownConnection(conn, ex);
276 if (this.eventListener != null) {
277 this.eventListener.fatalIOException(ex, conn);
278 }
279 }
280 }
281
282 public void responseReceived(final NHttpClientConnection conn) {
283 HttpContext context = conn.getContext();
284 ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
285
286 HttpResponse response = conn.getHttpResponse();
287 response.setParams(
288 new DefaultedHttpParams(response.getParams(), this.params));
289
290 HttpRequest request = connState.getRequest();
291 try {
292
293 int statusCode = response.getStatusLine().getStatusCode();
294 if (statusCode < HttpStatus.SC_OK) {
295
296 if (statusCode == HttpStatus.SC_CONTINUE
297 && connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
298 continueRequest(conn, connState);
299 }
300 return;
301 } else {
302 connState.setResponse(response);
303 if (connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
304 cancelRequest(conn, connState);
305 } else if (connState.getOutputState() == ClientConnState.REQUEST_BODY_STREAM) {
306
307 cancelRequest(conn, connState);
308 connState.invalidate();
309 conn.suspendOutput();
310 }
311 }
312
313 context.setAttribute(ExecutionContext.HTTP_RESPONSE, response);
314
315 if (!canResponseHaveBody(request, response)) {
316 conn.resetInput();
317 response.setEntity(null);
318 this.httpProcessor.process(response, context);
319 processResponse(conn, connState);
320 } else {
321 HttpEntity entity = response.getEntity();
322 if (entity != null) {
323 ConsumingNHttpEntity consumingEntity = this.execHandler.responseEntity(
324 response, context);
325 if (consumingEntity == null) {
326 consumingEntity = new NullNHttpEntity(entity);
327 }
328 response.setEntity(consumingEntity);
329 connState.setConsumingEntity(consumingEntity);
330 this.httpProcessor.process(response, context);
331 }
332 }
333
334
335 } catch (IOException ex) {
336 shutdownConnection(conn, ex);
337 if (this.eventListener != null) {
338 this.eventListener.fatalIOException(ex, conn);
339 }
340 } catch (HttpException ex) {
341 closeConnection(conn, ex);
342 if (this.eventListener != null) {
343 this.eventListener.fatalProtocolException(ex, conn);
344 }
345 }
346 }
347
348 public void timeout(final NHttpClientConnection conn) {
349 HttpContext context = conn.getContext();
350 ClientConnState connState = (ClientConnState) context.getAttribute(CONN_STATE);
351
352 try {
353
354 if (connState.getOutputState() == ClientConnState.EXPECT_CONTINUE) {
355 continueRequest(conn, connState);
356 return;
357 }
358
359 } catch (IOException ex) {
360 shutdownConnection(conn, ex);
361 if (this.eventListener != null) {
362 this.eventListener.fatalIOException(ex, conn);
363 }
364 }
365
366 handleTimeout(conn);
367 }
368
369 private void initialize(
370 final NHttpClientConnection conn,
371 final Object attachment) {
372 HttpContext context = conn.getContext();
373
374 context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
375 this.execHandler.initalizeContext(context, attachment);
376 }
377
378
379
380
381 private void continueRequest(
382 final NHttpClientConnection conn,
383 final ClientConnState connState) throws IOException {
384
385 int timeout = connState.getTimeout();
386 conn.setSocketTimeout(timeout);
387
388 conn.requestOutput();
389 connState.setOutputState(ClientConnState.REQUEST_BODY_STREAM);
390 }
391
392 private void cancelRequest(
393 final NHttpClientConnection conn,
394 final ClientConnState connState) throws IOException {
395
396 int timeout = connState.getTimeout();
397 conn.setSocketTimeout(timeout);
398
399 conn.resetOutput();
400 connState.resetOutput();
401 }
402
403
404
405
406 private void processResponse(
407 final NHttpClientConnection conn,
408 final ClientConnState connState) throws IOException, HttpException {
409
410 if (!connState.isValid()) {
411 conn.close();
412 }
413
414 HttpContext context = conn.getContext();
415 HttpResponse response = connState.getResponse();
416 this.execHandler.handleResponse(response, context);
417 if (!this.connStrategy.keepAlive(response, context)) {
418 conn.close();
419 }
420
421 if (conn.isOpen()) {
422
423 connState.resetInput();
424 connState.resetOutput();
425 conn.requestOutput();
426 }
427 }
428
429 protected static class ClientConnState {
430
431 public static final int READY = 0;
432 public static final int REQUEST_SENT = 1;
433 public static final int EXPECT_CONTINUE = 2;
434 public static final int REQUEST_BODY_STREAM = 4;
435 public static final int REQUEST_BODY_DONE = 8;
436 public static final int RESPONSE_RECEIVED = 16;
437 public static final int RESPONSE_BODY_STREAM = 32;
438 public static final int RESPONSE_BODY_DONE = 64;
439
440 private int outputState;
441
442 private HttpRequest request;
443 private HttpResponse response;
444 private ConsumingNHttpEntity consumingEntity;
445 private ProducingNHttpEntity producingEntity;
446 private boolean valid;
447 private int timeout;
448
449 public ClientConnState() {
450 super();
451 this.valid = true;
452 }
453
454 public void setConsumingEntity(final ConsumingNHttpEntity consumingEntity) {
455 this.consumingEntity = consumingEntity;
456 }
457
458 public void setProducingEntity(final ProducingNHttpEntity producingEntity) {
459 this.producingEntity = producingEntity;
460 }
461
462 public ProducingNHttpEntity getProducingEntity() {
463 return producingEntity;
464 }
465
466 public ConsumingNHttpEntity getConsumingEntity() {
467 return consumingEntity;
468 }
469
470 public int getOutputState() {
471 return this.outputState;
472 }
473
474 public void setOutputState(int outputState) {
475 this.outputState = outputState;
476 }
477
478 public HttpRequest getRequest() {
479 return this.request;
480 }
481
482 public void setRequest(final HttpRequest request) {
483 this.request = request;
484 }
485
486 public HttpResponse getResponse() {
487 return this.response;
488 }
489
490 public void setResponse(final HttpResponse response) {
491 this.response = response;
492 }
493
494 public int getTimeout() {
495 return this.timeout;
496 }
497
498 public void setTimeout(int timeout) {
499 this.timeout = timeout;
500 }
501
502 public void resetInput() throws IOException {
503 this.response = null;
504 if (this.consumingEntity != null) {
505 this.consumingEntity.finish();
506 this.consumingEntity = null;
507 }
508 }
509
510 public void resetOutput() throws IOException {
511 this.request = null;
512 if (this.producingEntity != null) {
513 this.producingEntity.finish();
514 this.producingEntity = null;
515 }
516 this.outputState = READY;
517 }
518
519 public void reset() throws IOException {
520 resetInput();
521 resetOutput();
522 }
523
524 public boolean isValid() {
525 return this.valid;
526 }
527
528 public void invalidate() {
529 this.valid = false;
530 }
531
532 }
533
534 }