1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.jetty.client;
16
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.InterruptedIOException;
20
21 import org.mortbay.io.Buffer;
22 import org.mortbay.io.Buffers;
23 import org.mortbay.io.ByteArrayBuffer;
24 import org.mortbay.io.Connection;
25 import org.mortbay.io.EndPoint;
26 import org.mortbay.io.nio.SelectChannelEndPoint;
27 import org.mortbay.jetty.HttpGenerator;
28 import org.mortbay.jetty.HttpHeaderValues;
29 import org.mortbay.jetty.HttpHeaders;
30 import org.mortbay.jetty.HttpParser;
31 import org.mortbay.jetty.HttpSchemes;
32 import org.mortbay.jetty.HttpVersions;
33 import org.mortbay.jetty.client.security.Authorization;
34 import org.mortbay.jetty.security.SslHttpChannelEndPoint;
35 import org.mortbay.log.Log;
36 import org.mortbay.thread.Timeout;
37
38
39
40
41
42
43 public class HttpConnection implements Connection
44 {
45 HttpDestination _destination;
46 EndPoint _endp;
47 HttpGenerator _generator;
48 HttpParser _parser;
49 boolean _http11 = true;
50 Buffer _connectionHeader;
51 Buffer _requestContentChunk;
52 long _last;
53 boolean _requestComplete;
54 public String _message;
55 public boolean _reserved;
56
57
58 volatile HttpExchange _exchange;
59 HttpExchange _pipeline;
60
61 public void dump() throws IOException
62 {
63 System.err.println("endp=" + _endp + " " + _endp.isBufferingInput() + " " + _endp.isBufferingOutput());
64 System.err.println("generator=" + _generator);
65 System.err.println("parser=" + _parser.getState() + " " + _parser.isMoreInBuffer());
66 System.err.println("exchange=" + _exchange);
67 if (_endp instanceof SslHttpChannelEndPoint)
68 ((SslHttpChannelEndPoint)_endp).dump();
69 }
70
71 Timeout.Task _timeout = new Timeout.Task()
72 {
73 public void expired()
74 {
75 HttpExchange ex=null;
76 try
77 {
78 synchronized (HttpConnection.this)
79 {
80 ex = _exchange;
81 _exchange = null;
82 if (ex != null)
83 _destination.returnConnection(HttpConnection.this,true);
84 }
85 }
86 catch (Exception e)
87 {
88 Log.debug(e);
89 }
90 finally
91 {
92 try
93 {
94 _endp.close();
95 }
96 catch (IOException e)
97 {
98 Log.ignore(e);
99 }
100
101 if (ex!=null && ex.getStatus() < HttpExchange.STATUS_COMPLETED)
102 {
103 ex.setStatus(HttpExchange.STATUS_EXPIRED);
104 }
105 }
106 }
107 };
108
109
110 HttpConnection(Buffers buffers, EndPoint endp, int hbs, int cbs)
111 {
112 _endp = endp;
113 _generator = new HttpGenerator(buffers,endp,hbs,cbs);
114 _parser = new HttpParser(buffers,endp,new Handler(),hbs,cbs);
115 }
116
117 public void setReserved (boolean reserved)
118 {
119 _reserved = reserved;
120 }
121
122 public boolean isReserved()
123 {
124 return _reserved;
125 }
126
127
128 public HttpDestination getDestination()
129 {
130 return _destination;
131 }
132
133
134 public void setDestination(HttpDestination destination)
135 {
136 _destination = destination;
137 }
138
139
140 public boolean send(HttpExchange ex) throws IOException
141 {
142
143
144
145 synchronized (this)
146 {
147 if (_exchange != null)
148 {
149 if (_pipeline != null)
150 throw new IllegalStateException(this + " PIPELINED!!! _exchange=" + _exchange);
151 _pipeline = ex;
152 return true;
153 }
154
155 if (!_endp.isOpen())
156 return false;
157
158 ex.setStatus(HttpExchange.STATUS_WAITING_FOR_COMMIT);
159 _exchange = ex;
160
161 if (_endp.isBlocking())
162 this.notify();
163 else
164 {
165 SelectChannelEndPoint scep = (SelectChannelEndPoint)_endp;
166 scep.scheduleWrite();
167 }
168
169 if (!_endp.isBlocking())
170 _destination.getHttpClient().schedule(_timeout);
171
172 return true;
173 }
174 }
175
176
177 public void handle() throws IOException
178 {
179 int no_progress = 0;
180 long flushed = 0;
181
182 boolean failed = false;
183 while (_endp.isBufferingInput() || _endp.isOpen())
184 {
185 synchronized (this)
186 {
187 while (_exchange == null)
188 {
189 if (_endp.isBlocking())
190 {
191 try
192 {
193 this.wait();
194 }
195 catch (InterruptedException e)
196 {
197 throw new InterruptedIOException();
198 }
199 }
200 else
201 {
202
203 _parser.fill();
204 _parser.skipCRLF();
205 if (_parser.isMoreInBuffer())
206 {
207 Log.warn("unexpected data");
208 _endp.close();
209 }
210
211 return;
212 }
213 }
214 }
215 if (_exchange.getStatus() == HttpExchange.STATUS_WAITING_FOR_COMMIT)
216 {
217 no_progress = 0;
218 commitRequest();
219 }
220
221 try
222 {
223 long io = 0;
224 _endp.flush();
225
226 if (_generator.isComplete())
227 {
228 if (!_requestComplete)
229 {
230 _requestComplete = true;
231 _exchange.getEventListener().onRequestComplete();
232 }
233 }
234 else
235 {
236
237 synchronized (this)
238 {
239 if (_exchange == null)
240 continue;
241 flushed = _generator.flush();
242 io += flushed;
243 }
244
245 if (!_generator.isComplete())
246 {
247 InputStream in = _exchange.getRequestContentSource();
248 if (in != null)
249 {
250 if (_requestContentChunk == null || _requestContentChunk.length() == 0)
251 {
252 _requestContentChunk = _exchange.getRequestContentChunk();
253 if (_requestContentChunk != null)
254 _generator.addContent(_requestContentChunk,false);
255 else
256 _generator.complete();
257 io += _generator.flush();
258 }
259 }
260 else
261 _generator.complete();
262 }
263 }
264
265
266
267 if (!_parser.isComplete() && _generator.isCommitted())
268 {
269 long filled = _parser.parseAvailable();
270 io += filled;
271 }
272
273 if (io > 0)
274 no_progress = 0;
275 else if (no_progress++ >= 2 && !_endp.isBlocking())
276 {
277
278 if (_endp instanceof SslHttpChannelEndPoint && !_generator.isComplete() && !_generator.isEmpty())
279 {
280 if (_generator.flush()>0)
281 continue;
282 }
283 return;
284 }
285 }
286 catch (IOException e)
287 {
288 synchronized (this)
289 {
290 if (_exchange != null)
291 {
292 _exchange.getEventListener().onException(e);
293 _exchange.setStatus(HttpExchange.STATUS_EXCEPTED);
294 }
295 }
296 failed = true;
297 throw e;
298 }
299 finally
300 {
301 boolean complete = false;
302 boolean close = failed;
303 if (!failed)
304 {
305
306 if (_generator.isComplete())
307 {
308 if (!_requestComplete)
309 {
310 _requestComplete = true;
311 _exchange.getEventListener().onRequestComplete();
312 }
313
314
315
316 if (_parser.isComplete())
317 {
318 _destination.getHttpClient().cancel(_timeout);
319 complete = true;
320 }
321 }
322 }
323
324 if (complete || failed)
325 {
326 synchronized (this)
327 {
328 if (!close)
329 close = shouldClose();
330
331 reset(true);
332 no_progress = 0;
333 flushed = -1;
334 if (_exchange != null)
335 {
336 _exchange = null;
337
338 if (_pipeline == null)
339 {
340 if (!isReserved())
341 _destination.returnConnection(this,close);
342 if (close)
343 return;
344 }
345 else
346 {
347 if (close)
348 {
349 if (!isReserved())
350 _destination.returnConnection(this,close);
351 _destination.send(_pipeline);
352 _pipeline = null;
353 return;
354 }
355
356 HttpExchange ex = _pipeline;
357 _pipeline = null;
358
359 send(ex);
360 }
361 }
362 }
363 }
364 }
365 }
366 }
367
368
369 public boolean isIdle()
370 {
371 synchronized (this)
372 {
373 return _exchange == null;
374 }
375 }
376
377
378 public EndPoint getEndPoint()
379 {
380 return _endp;
381 }
382
383
384 private void commitRequest() throws IOException
385 {
386 synchronized (this)
387 {
388 if (_exchange.getStatus() != HttpExchange.STATUS_WAITING_FOR_COMMIT)
389 throw new IllegalStateException();
390
391 _exchange.setStatus(HttpExchange.STATUS_SENDING_REQUEST);
392 _generator.setVersion(_exchange._version);
393
394 String uri = _exchange._uri;
395 if (_destination.isProxied() && uri.startsWith("/"))
396 {
397
398 uri = (_destination.isSecure()?HttpSchemes.HTTPS:HttpSchemes.HTTP) + "://" + _destination.getAddress().getHost() + ":"
399 + _destination.getAddress().getPort() + uri;
400 Authorization auth = _destination.getProxyAuthentication();
401 if (auth != null)
402 auth.setCredentials(_exchange);
403 }
404
405 _generator.setRequest(_exchange._method,uri);
406
407 if (_exchange._version >= HttpVersions.HTTP_1_1_ORDINAL)
408 {
409 if (!_exchange._requestFields.containsKey(HttpHeaders.HOST_BUFFER))
410 _exchange._requestFields.add(HttpHeaders.HOST_BUFFER,_destination.getHostHeader());
411 }
412
413 if (_exchange._requestContent != null)
414 {
415 _exchange._requestFields.putLongField(HttpHeaders.CONTENT_LENGTH,_exchange._requestContent.length());
416 _generator.completeHeader(_exchange._requestFields,false);
417 _generator.addContent(_exchange._requestContent,true);
418 }
419 else if (_exchange._requestContentSource != null)
420 {
421 _generator.completeHeader(_exchange._requestFields,false);
422 int available = _exchange._requestContentSource.available();
423 if (available > 0)
424 {
425
426
427
428 byte[] buf = new byte[available];
429 int length = _exchange._requestContentSource.read(buf);
430 _generator.addContent(new ByteArrayBuffer(buf,0,length),false);
431 }
432 }
433 else
434 {
435 _exchange._requestFields.remove(HttpHeaders.CONTENT_LENGTH);
436
437
438
439
440
441 _generator.completeHeader(_exchange._requestFields,true);
442 }
443
444 _exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
445 }
446 }
447
448
449 protected void reset(boolean returnBuffers) throws IOException
450 {
451 _requestComplete = false;
452 _connectionHeader = null;
453 _parser.reset(returnBuffers);
454 _generator.reset(returnBuffers);
455 _http11 = true;
456 }
457
458
459 private boolean shouldClose()
460 {
461 if (_connectionHeader!=null)
462 {
463 if (HttpHeaderValues.CLOSE_BUFFER.equals(_connectionHeader))
464 return true;
465 if (HttpHeaderValues.KEEP_ALIVE_BUFFER.equals(_connectionHeader))
466 return false;
467 }
468 return !_http11;
469 }
470
471
472 private class Handler extends HttpParser.EventHandler
473 {
474 @Override
475 public void startRequest(Buffer method, Buffer url, Buffer version) throws IOException
476 {
477
478
479
480
481
482 }
483
484 @Override
485 public void startResponse(Buffer version, int status, Buffer reason) throws IOException
486 {
487 HttpExchange exchange = _exchange;
488 if (exchange!=null)
489 {
490 _http11 = HttpVersions.HTTP_1_1_BUFFER.equals(version);
491 exchange.getEventListener().onResponseStatus(version,status,reason);
492 exchange.setStatus(HttpExchange.STATUS_PARSING_HEADERS);
493 }
494 }
495
496 @Override
497 public void parsedHeader(Buffer name, Buffer value) throws IOException
498 {
499 HttpExchange exchange = _exchange;
500 if (exchange!=null)
501 {
502 if (HttpHeaders.CACHE.getOrdinal(name) == HttpHeaders.CONNECTION_ORDINAL)
503 {
504 _connectionHeader = HttpHeaderValues.CACHE.lookup(value);
505 }
506 exchange.getEventListener().onResponseHeader(name,value);
507 }
508 }
509
510 @Override
511 public void headerComplete() throws IOException
512 {
513 HttpExchange exchange = _exchange;
514 if (exchange!=null)
515 exchange.setStatus(HttpExchange.STATUS_PARSING_CONTENT);
516 }
517
518 @Override
519 public void content(Buffer ref) throws IOException
520 {
521 HttpExchange exchange = _exchange;
522 if (exchange!=null)
523 exchange.getEventListener().onResponseContent(ref);
524 }
525
526 @Override
527 public void messageComplete(long contextLength) throws IOException
528 {
529 HttpExchange exchange = _exchange;
530 if (exchange!=null)
531 exchange.setStatus(HttpExchange.STATUS_COMPLETED);
532 }
533 }
534
535
536 public String toString()
537 {
538 return "HttpConnection@" + hashCode() + "//" + _destination.getAddress().getHost() + ":" + _destination.getAddress().getPort();
539 }
540
541
542 public String toDetailString()
543 {
544 return toString() + " ex=" + _exchange + " " + _timeout.getAge();
545 }
546
547
548
549
550
551 public long getLast()
552 {
553 return _last;
554 }
555
556
557
558
559
560
561 public void setLast(long last)
562 {
563 _last = last;
564 }
565
566
567 public void close() throws IOException
568 {
569 _endp.close();
570 }
571
572 }