1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mortbay.jetty;
17
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.PrintWriter;
21
22 import javax.servlet.ServletInputStream;
23 import javax.servlet.ServletOutputStream;
24 import javax.servlet.http.HttpServletResponse;
25
26 import org.mortbay.io.Buffer;
27 import org.mortbay.io.Connection;
28 import org.mortbay.io.EndPoint;
29 import org.mortbay.io.BufferCache.CachedBuffer;
30 import org.mortbay.io.nio.SelectChannelEndPoint;
31 import org.mortbay.log.Log;
32 import org.mortbay.resource.Resource;
33 import org.mortbay.util.URIUtil;
34 import org.mortbay.util.ajax.Continuation;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class HttpConnection implements Connection
54 {
55 private static int UNKNOWN = -2;
56 private static ThreadLocal __currentConnection = new ThreadLocal();
57
58 private long _timeStamp=System.currentTimeMillis();
59 private int _requests;
60 private boolean _handling;
61 private boolean _destroy;
62
63 protected Connector _connector;
64 protected EndPoint _endp;
65 protected Server _server;
66
67 protected HttpURI _uri=new HttpURI();
68
69 protected Parser _parser;
70 protected HttpFields _requestFields;
71 protected Request _request;
72 protected ServletInputStream _in;
73
74 protected Generator _generator;
75 protected HttpFields _responseFields;
76 protected Response _response;
77 protected Output _out;
78 protected OutputWriter _writer;
79 protected PrintWriter _printWriter;
80
81 int _include;
82
83 private Object _associatedObject;
84
85 private transient int _expect = UNKNOWN;
86 private transient int _version = UNKNOWN;
87 private transient boolean _head = false;
88 private transient boolean _host = false;
89 private transient boolean _delayedHandling=false;
90
91
92 public static HttpConnection getCurrentConnection()
93 {
94 return (HttpConnection) __currentConnection.get();
95 }
96
97
98 protected static void setCurrentConnection(HttpConnection connection)
99 {
100 __currentConnection.set(connection);
101 }
102
103
104
105
106
107 public HttpConnection(Connector connector, EndPoint endpoint, Server server)
108 {
109 _connector = connector;
110 _endp = endpoint;
111 _parser = new HttpParser(_connector, endpoint, new RequestHandler(), _connector.getHeaderBufferSize(), _connector.getRequestBufferSize());
112 _requestFields = new HttpFields();
113 _responseFields = new HttpFields();
114 _request = new Request(this);
115 _response = new Response(this);
116 _generator = new HttpGenerator(_connector, _endp, _connector.getHeaderBufferSize(), _connector.getResponseBufferSize());
117 _generator.setSendServerVersion(server.getSendServerVersion());
118 _server = server;
119 }
120
121
122 public void destroy()
123 {
124 synchronized(this)
125 {
126 _destroy=true;
127 if (!_handling)
128 {
129 if (_parser!=null)
130 _parser.reset(true);
131
132 if (_generator!=null)
133 _generator.reset(true);
134
135 if (_requestFields!=null)
136 _requestFields.destroy();
137
138 if (_responseFields!=null)
139 _responseFields.destroy();
140
141 _server=null;
142 }
143 }
144 }
145
146
147
148
149
150 public Parser getParser()
151 {
152 return _parser;
153 }
154
155
156
157
158
159 public int getRequests()
160 {
161 return _requests;
162 }
163
164
165
166
167
168 public long getTimeStamp()
169 {
170 return _timeStamp;
171 }
172
173
174
175
176
177 public Object getAssociatedObject()
178 {
179 return _associatedObject;
180 }
181
182
183
184
185
186 public void setAssociatedObject(Object associatedObject)
187 {
188 _associatedObject = associatedObject;
189 }
190
191
192
193
194
195 public Connector getConnector()
196 {
197 return _connector;
198 }
199
200
201
202
203
204 public HttpFields getRequestFields()
205 {
206 return _requestFields;
207 }
208
209
210
211
212
213 public HttpFields getResponseFields()
214 {
215 return _responseFields;
216 }
217
218
219
220
221
222
223 public boolean isConfidential(Request request)
224 {
225 if (_connector!=null)
226 return _connector.isConfidential(request);
227 return false;
228 }
229
230
231
232
233
234
235
236
237 public boolean isIntegral(Request request)
238 {
239 if (_connector!=null)
240 return _connector.isIntegral(request);
241 return false;
242 }
243
244
245
246
247
248 public EndPoint getEndPoint()
249 {
250 return _endp;
251 }
252
253
254
255
256
257 public boolean getResolveNames()
258 {
259 return _connector.getResolveNames();
260 }
261
262
263
264
265
266 public Request getRequest()
267 {
268 return _request;
269 }
270
271
272
273
274
275 public Response getResponse()
276 {
277 return _response;
278 }
279
280
281
282
283
284 public ServletInputStream getInputStream()
285 {
286 if (_in == null)
287 _in = new HttpParser.Input(((HttpParser)_parser),_connector.getMaxIdleTime());
288 return _in;
289 }
290
291
292
293
294
295 public ServletOutputStream getOutputStream()
296 {
297 if (_out == null)
298 _out = new Output();
299 return _out;
300 }
301
302
303
304
305
306
307 public PrintWriter getPrintWriter(String encoding)
308 {
309 getOutputStream();
310 if (_writer==null)
311 {
312 _writer=new OutputWriter();
313 _printWriter=new PrintWriter(_writer)
314 {
315
316
317
318
319 public void close()
320 {
321 try
322 {
323 out.close();
324 }
325 catch(IOException e)
326 {
327 Log.debug(e);
328 setError();
329 }
330 }
331
332 };
333 }
334 _writer.setCharacterEncoding(encoding);
335 return _printWriter;
336 }
337
338
339 public boolean isResponseCommitted()
340 {
341 return _generator.isCommitted();
342 }
343
344
345 public void handle() throws IOException
346 {
347
348 boolean more_in_buffer =true;
349 int no_progress=0;
350
351 while (more_in_buffer)
352 {
353 try
354 {
355 synchronized(this)
356 {
357 if (_handling)
358 throw new IllegalStateException();
359 _handling=true;
360 }
361
362 setCurrentConnection(this);
363 long io=0;
364
365 Continuation continuation = _request.getContinuation();
366 if (continuation != null && continuation.isPending())
367 {
368 Log.debug("resume continuation {}",continuation);
369 if (_request.getMethod()==null)
370 throw new IllegalStateException();
371 handleRequest();
372 }
373 else
374 {
375
376 if (!_parser.isComplete())
377 io=_parser.parseAvailable();
378
379
380
381
382
383 while (_generator.isCommitted() && !_generator.isComplete())
384 {
385 long written=_generator.flush();
386 io+=written;
387 if (written<=0)
388 break;
389 else if (_endp.isBufferingOutput())
390 _endp.flush();
391 }
392
393
394 if (_endp.isBufferingOutput())
395 {
396 _endp.flush();
397 if (!_endp.isBufferingOutput())
398 no_progress=0;
399 }
400
401 if (io>0)
402 no_progress=0;
403 else if (no_progress++>=2)
404 return;
405 }
406 }
407 catch (HttpException e)
408 {
409 if (Log.isDebugEnabled())
410 {
411 Log.debug("uri="+_uri);
412 Log.debug("fields="+_requestFields);
413 Log.debug(e);
414 }
415 _generator.sendError(e.getStatus(), e.getReason(), null, true);
416
417 _parser.reset(true);
418 _endp.close();
419 throw e;
420 }
421 finally
422 {
423 setCurrentConnection(null);
424
425 more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
426
427 synchronized(this)
428 {
429 _handling=false;
430
431 if (_destroy)
432 {
433 destroy();
434 return;
435 }
436 }
437
438 if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput())
439 {
440 if (!_generator.isPersistent())
441 {
442 _parser.reset(true);
443 more_in_buffer=false;
444 }
445
446 reset(!more_in_buffer);
447 no_progress=0;
448 }
449
450 Continuation continuation = _request.getContinuation();
451 if (continuation != null && continuation.isPending())
452 {
453 break;
454 }
455 else if (_generator.isCommitted() && !_generator.isComplete() && _endp instanceof SelectChannelEndPoint)
456 ((SelectChannelEndPoint)_endp).setWritable(false);
457 }
458 }
459 }
460
461
462 public void reset(boolean returnBuffers)
463 {
464 _parser.reset(returnBuffers);
465 _requestFields.clear();
466 _request.recycle();
467
468 _generator.reset(returnBuffers);
469 _responseFields.clear();
470 _response.recycle();
471
472 _uri.clear();
473 }
474
475
476 protected void handleRequest() throws IOException
477 {
478 if (_server != null)
479 {
480 boolean retrying = false;
481 boolean error = false;
482 String threadName=null;
483 try
484 {
485
486 String info=URIUtil.canonicalPath(_uri.getDecodedPath());
487 if (info==null)
488 throw new HttpException(400);
489 _request.setPathInfo(info);
490
491 if (_out!=null)
492 _out.reopen();
493
494 if (Log.isDebugEnabled())
495 {
496 threadName=Thread.currentThread().getName();
497 Thread.currentThread().setName(threadName+" - "+_uri);
498 }
499
500 _connector.customize(_endp, _request);
501
502 _server.handle(this);
503 }
504 catch (RetryRequest r)
505 {
506 if (Log.isDebugEnabled())
507 Log.ignore(r);
508 retrying = true;
509 }
510 catch (EofException e)
511 {
512 Log.ignore(e);
513 error=true;
514 }
515 catch (HttpException e)
516 {
517 Log.debug(e);
518 _request.setHandled(true);
519 _response.sendError(e.getStatus(), e.getReason());
520 error=true;
521 }
522 catch (Exception e)
523 {
524 Log.warn(e);
525 _request.setHandled(true);
526 _generator.sendError(500, null, null, true);
527 error=true;
528 }
529 catch (Error e)
530 {
531 Log.warn(e);
532 _request.setHandled(true);
533 _generator.sendError(500, null, null, true);
534 error=true;
535 }
536 finally
537 {
538 if (threadName!=null)
539 Thread.currentThread().setName(threadName);
540
541 if (!retrying)
542 {
543 if (_request.getContinuation()!=null)
544 {
545 Log.debug("continuation still pending {}");
546 _request.getContinuation().reset();
547 }
548
549 if(_endp.isOpen())
550 {
551 if (_generator.isPersistent())
552 _connector.persist(_endp);
553
554 if (error)
555 _endp.close();
556 else
557 {
558 if (!_response.isCommitted() && !_request.isHandled())
559 _response.sendError(HttpServletResponse.SC_NOT_FOUND);
560 _response.complete();
561 }
562 }
563 else
564 {
565 _response.complete();
566 }
567 }
568 }
569 }
570 }
571
572
573 public void commitResponse(boolean last) throws IOException
574 {
575 if (!_generator.isCommitted())
576 {
577 _generator.setResponse(_response.getStatus(), _response.getReason());
578 _generator.completeHeader(_responseFields, last);
579 }
580 if (last)
581 _generator.complete();
582 }
583
584
585 public void completeResponse() throws IOException
586 {
587 if (!_generator.isCommitted())
588 {
589 _generator.setResponse(_response.getStatus(), _response.getReason());
590 _generator.completeHeader(_responseFields, HttpGenerator.LAST);
591 }
592
593 _generator.complete();
594 }
595
596
597 public void flushResponse() throws IOException
598 {
599 try
600 {
601 commitResponse(HttpGenerator.MORE);
602 _generator.flush();
603 }
604 catch(IOException e)
605 {
606 throw (e instanceof EofException) ? e:new EofException(e);
607 }
608 }
609
610
611 public Generator getGenerator()
612 {
613 return _generator;
614 }
615
616
617
618 public boolean isIncluding()
619 {
620 return _include>0;
621 }
622
623
624 public void include()
625 {
626 _include++;
627 }
628
629
630 public void included()
631 {
632 _include--;
633 if (_out!=null)
634 _out.reopen();
635 }
636
637
638 public boolean isIdle()
639 {
640 return _generator.isIdle() && (_parser.isIdle() || _delayedHandling);
641 }
642
643
644
645
646 private class RequestHandler extends HttpParser.EventHandler
647 {
648 private String _charset;
649
650
651
652
653
654
655 public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
656 {
657 _host = false;
658 _expect = UNKNOWN;
659 _delayedHandling=false;
660 _charset=null;
661
662 if(_request.getTimeStamp()==0)
663 _request.setTimeStamp(System.currentTimeMillis());
664 _request.setMethod(method.toString());
665
666 try
667 {
668 _uri.parse(uri.array(), uri.getIndex(), uri.length());
669 _request.setUri(_uri);
670
671 if (version==null)
672 {
673 _request.setProtocol(HttpVersions.HTTP_0_9);
674 _version=HttpVersions.HTTP_0_9_ORDINAL;
675 }
676 else
677 {
678 version= HttpVersions.CACHE.get(version);
679 _version = HttpVersions.CACHE.getOrdinal(version);
680 if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL;
681 _request.setProtocol(version.toString());
682 }
683
684 _head = method == HttpMethods.HEAD_BUFFER;
685 }
686 catch (Exception e)
687 {
688 throw new HttpException(HttpStatus.ORDINAL_400_Bad_Request,null,e);
689 }
690 }
691
692
693
694
695 public void parsedHeader(Buffer name, Buffer value)
696 {
697 int ho = HttpHeaders.CACHE.getOrdinal(name);
698 switch (ho)
699 {
700 case HttpHeaders.HOST_ORDINAL:
701
702 _host = true;
703 break;
704
705 case HttpHeaders.EXPECT_ORDINAL:
706 value = HttpHeaderValues.CACHE.lookup(value);
707 _expect = HttpHeaderValues.CACHE.getOrdinal(value);
708 break;
709
710 case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
711 case HttpHeaders.USER_AGENT_ORDINAL:
712 value = HttpHeaderValues.CACHE.lookup(value);
713 break;
714
715 case HttpHeaders.CONTENT_TYPE_ORDINAL:
716 value = MimeTypes.CACHE.lookup(value);
717 _charset=MimeTypes.getCharsetFromContentType(value);
718 break;
719
720 case HttpHeaders.CONNECTION_ORDINAL:
721
722 int ordinal = HttpHeaderValues.CACHE.getOrdinal(value);
723 switch(ordinal)
724 {
725 case -1:
726 {
727 String[] values = value.toString().split(",");
728 for (int i=0;values!=null && i<values.length;i++)
729 {
730 CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim());
731
732 if (cb!=null)
733 {
734 switch(cb.getOrdinal())
735 {
736 case HttpHeaderValues.CLOSE_ORDINAL:
737 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
738 _generator.setPersistent(false);
739 break;
740
741 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
742 if (_version==HttpVersions.HTTP_1_0_ORDINAL)
743 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
744 break;
745 }
746 }
747 }
748 break;
749 }
750 case HttpHeaderValues.CLOSE_ORDINAL:
751 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
752 _generator.setPersistent(false);
753 break;
754
755 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
756 if (_version==HttpVersions.HTTP_1_0_ORDINAL)
757 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
758 break;
759 }
760 }
761
762 _requestFields.add(name, value);
763 }
764
765
766
767
768 public void headerComplete() throws IOException
769 {
770 _requests++;
771 _generator.setVersion(_version);
772 switch (_version)
773 {
774 case HttpVersions.HTTP_0_9_ORDINAL:
775 break;
776 case HttpVersions.HTTP_1_0_ORDINAL:
777 _generator.setHead(_head);
778 break;
779 case HttpVersions.HTTP_1_1_ORDINAL:
780 _generator.setHead(_head);
781
782 if (_server.getSendDateHeader())
783 _responseFields.put(HttpHeaders.DATE_BUFFER, _request.getTimeStampBuffer(),_request.getTimeStamp());
784
785 if (!_host)
786 {
787 _generator.setResponse(HttpStatus.ORDINAL_400_Bad_Request, null);
788 _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
789 _generator.completeHeader(_responseFields, true);
790 _generator.complete();
791 return;
792 }
793
794 if (_expect != UNKNOWN)
795 {
796 if (_expect == HttpHeaderValues.CONTINUE_ORDINAL)
797 {
798
799 if (((HttpParser)_parser).getHeaderBuffer()==null || ((HttpParser)_parser).getHeaderBuffer().length()<2)
800 {
801 _generator.setResponse(HttpStatus.ORDINAL_100_Continue, null);
802 _generator.completeHeader(null, true);
803 _generator.complete();
804 _generator.reset(false);
805 }
806 }
807 else if (_expect == HttpHeaderValues.PROCESSING_ORDINAL)
808 {
809 }
810 else
811 {
812 _generator.sendError(HttpStatus.ORDINAL_417_Expectation_Failed, null, null, true);
813 return;
814 }
815 }
816
817 break;
818 default:
819 }
820
821 if(_charset!=null)
822 _request.setCharacterEncodingUnchecked(_charset);
823
824
825 if (((HttpParser)_parser).getContentLength()<=0 && !((HttpParser)_parser).isChunking())
826 handleRequest();
827 else
828 _delayedHandling=true;
829 }
830
831
832
833
834
835 public void content(Buffer ref) throws IOException
836 {
837 if (_delayedHandling)
838 {
839 _delayedHandling=false;
840 handleRequest();
841 }
842 }
843
844
845
846
847
848
849 public void messageComplete(long contextLength) throws IOException
850 {
851 if (_delayedHandling)
852 {
853 _delayedHandling=false;
854 handleRequest();
855 }
856 }
857
858
859
860
861
862
863
864 public void startResponse(Buffer version, int status, Buffer reason)
865 {
866 Log.debug("Bad request!: "+version+" "+status+" "+reason);
867 }
868
869 }
870
871
872
873
874
875 public class Output extends AbstractGenerator.Output
876 {
877 Output()
878 {
879 super((AbstractGenerator)HttpConnection.this._generator,_connector.getMaxIdleTime());
880 }
881
882
883
884
885
886 public void close() throws IOException
887 {
888 if (_closed)
889 return;
890
891 if (!isIncluding() && !_generator.isCommitted())
892 commitResponse(HttpGenerator.LAST);
893 else
894 flushResponse();
895
896 super.close();
897 }
898
899
900
901
902
903
904 public void flush() throws IOException
905 {
906 if (!_generator.isCommitted())
907 commitResponse(HttpGenerator.MORE);
908 super.flush();
909 }
910
911
912
913
914
915 public void print(String s) throws IOException
916 {
917 if (_closed)
918 throw new IOException("Closed");
919 PrintWriter writer=getPrintWriter(null);
920 writer.print(s);
921 }
922
923
924 public void sendResponse(Buffer response) throws IOException
925 {
926 ((HttpGenerator)_generator).sendResponse(response);
927 }
928
929
930 public void sendContent(Object content) throws IOException
931 {
932 Resource resource=null;
933
934 if (_closed)
935 throw new IOException("Closed");
936
937 if (_generator.getContentWritten() > 0) throw new IllegalStateException("!empty");
938
939 if (content instanceof HttpContent)
940 {
941 HttpContent c = (HttpContent) content;
942 if (c.getContentType() != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
943 _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, c.getContentType());
944 if (c.getContentLength() > 0)
945 _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER, c.getContentLength());
946 Buffer lm = c.getLastModified();
947 long lml=c.getResource().lastModified();
948 if (lm != null)
949 _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm,lml);
950 else if (c.getResource()!=null)
951 {
952 if (lml!=-1)
953 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml);
954 }
955
956 content = c.getBuffer();
957 if (content==null)
958 content=c.getInputStream();
959 }
960 else if (content instanceof Resource)
961 {
962 resource=(Resource)content;
963 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, resource.lastModified());
964 content=resource.getInputStream();
965 }
966
967
968 if (content instanceof Buffer)
969 {
970 _generator.addContent((Buffer) content, HttpGenerator.LAST);
971 commitResponse(HttpGenerator.LAST);
972 }
973 else if (content instanceof InputStream)
974 {
975 InputStream in = (InputStream)content;
976
977 try
978 {
979 int max = _generator.prepareUncheckedAddContent();
980 Buffer buffer = _generator.getUncheckedBuffer();
981
982 int len=buffer.readFrom(in,max);
983
984 while (len>=0)
985 {
986 _generator.completeUncheckedAddContent();
987 _out.flush();
988
989 max = _generator.prepareUncheckedAddContent();
990 buffer = _generator.getUncheckedBuffer();
991 len=buffer.readFrom(in,max);
992 }
993 _generator.completeUncheckedAddContent();
994 _out.flush();
995 }
996 finally
997 {
998 if (resource!=null)
999 resource.release();
1000 else
1001 in.close();
1002
1003 }
1004 }
1005 else
1006 throw new IllegalArgumentException("unknown content type?");
1007
1008
1009 }
1010 }
1011
1012
1013
1014
1015 public class OutputWriter extends AbstractGenerator.OutputWriter
1016 {
1017 OutputWriter()
1018 {
1019 super(HttpConnection.this._out);
1020 }
1021 }
1022
1023 }