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