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