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.URIUtil;
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<HttpConnection> __currentConnection = new ThreadLocal<HttpConnection>();
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() throws IOException
285 {
286
287 if (_expect == HttpHeaderValues.CONTINUE_ORDINAL)
288 {
289 if (((HttpParser)_parser).getHeaderBuffer()==null || ((HttpParser)_parser).getHeaderBuffer().length()<2)
290 {
291 _generator.setResponse(HttpStatus.ORDINAL_100_Continue, null);
292 _generator.completeHeader(null, true);
293 _generator.complete();
294 _generator.reset(false);
295 }
296 _expect = UNKNOWN;
297 }
298
299 if (_in == null)
300 _in = new HttpParser.Input(((HttpParser)_parser),_connector.getMaxIdleTime());
301 return _in;
302 }
303
304
305
306
307
308 public ServletOutputStream getOutputStream()
309 {
310 if (_out == null)
311 _out = new Output();
312 return _out;
313 }
314
315
316
317
318
319
320 public PrintWriter getPrintWriter(String encoding)
321 {
322 getOutputStream();
323 if (_writer==null)
324 {
325 _writer=new OutputWriter();
326 _printWriter=new PrintWriter(_writer)
327 {
328
329
330
331
332 public void close()
333 {
334 try
335 {
336 out.close();
337 }
338 catch(IOException e)
339 {
340 Log.debug(e);
341 setError();
342 }
343 }
344
345 };
346 }
347 _writer.setCharacterEncoding(encoding);
348 return _printWriter;
349 }
350
351
352 public boolean isResponseCommitted()
353 {
354 return _generator.isCommitted();
355 }
356
357
358 public void handle() throws IOException
359 {
360
361 boolean more_in_buffer =true;
362 int no_progress=0;
363
364 while (more_in_buffer)
365 {
366 try
367 {
368 synchronized(this)
369 {
370 if (_handling)
371 throw new IllegalStateException();
372 _handling=true;
373 }
374
375 setCurrentConnection(this);
376 long io=0;
377
378 if (!_request.isInitial())
379 {
380 if (_request.isSuspended())
381 {
382 Log.warn("suspended dispatch");
383 }
384 Log.debug("resume request",_request);
385 handleRequest();
386 }
387 else
388 {
389
390 if (!_parser.isComplete())
391 io=_parser.parseAvailable();
392
393
394
395
396
397 while (_generator.isCommitted() && !_generator.isComplete())
398 {
399 long written=_generator.flush();
400 io+=written;
401 if (written<=0)
402 break;
403 else if (_endp.isBufferingOutput())
404 _endp.flush();
405 }
406
407
408 if (_endp.isBufferingOutput())
409 {
410 _endp.flush();
411 if (!_endp.isBufferingOutput())
412 no_progress=0;
413 }
414
415 if (io>0)
416 no_progress=0;
417 else if (no_progress++>=2)
418 return;
419 }
420 }
421 catch (HttpException e)
422 {
423 if (Log.isDebugEnabled())
424 {
425 Log.debug("uri="+_uri);
426 Log.debug("fields="+_requestFields);
427 Log.debug(e);
428 }
429 _generator.sendError(e.getStatus(), e.getReason(), null, true);
430
431 _parser.reset(true);
432 _endp.close();
433 throw e;
434 }
435 finally
436 {
437 setCurrentConnection(null);
438
439 more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
440
441 synchronized(this)
442 {
443 _handling=false;
444
445 if (_destroy)
446 {
447 destroy();
448 return;
449 }
450 }
451
452 if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput())
453 {
454 if (!_generator.isPersistent())
455 {
456 _parser.reset(true);
457 more_in_buffer=false;
458 }
459
460 reset(!more_in_buffer);
461 no_progress=0;
462 }
463
464 if (_request.isSuspended())
465 {
466 Log.debug("return with suspended request");
467 return;
468 }
469 else if (_generator.isCommitted() && !_generator.isComplete() && _endp instanceof SelectChannelEndPoint)
470 ((SelectChannelEndPoint)_endp).setWritable(false);
471 }
472 }
473 }
474
475
476 public void scheduleTimeout(Timeout.Task task, long timeoutMs)
477 {
478 throw new UnsupportedOperationException();
479 }
480
481
482 public void cancelTimeout(Timeout.Task task)
483 {
484 throw new UnsupportedOperationException();
485 }
486
487
488 public void reset(boolean returnBuffers)
489 {
490 _parser.reset(returnBuffers);
491 _requestFields.clear();
492 _request.recycle();
493
494 _generator.reset(returnBuffers);
495 _responseFields.clear();
496 _response.recycle();
497
498 _uri.clear();
499 }
500
501
502 protected void handleRequest() throws IOException
503 {
504 _request.handling();
505 boolean handling=true;
506
507 while (handling)
508 {
509 _request.setHandled(false);
510 _response.enable();
511 boolean error = false;
512 String threadName=null;
513 try
514 {
515 String info=URIUtil.canonicalPath(_uri.getDecodedPath());
516 if (info==null)
517 throw new HttpException(400);
518 _request.setPathInfo(info);
519
520 if (_out!=null)
521 _out.reopen();
522
523 if (_request.isInitial())
524 _connector.customize(_endp, _request);
525
526 if (Log.isDebugEnabled())
527 {
528 threadName=Thread.currentThread().getName();
529 Thread.currentThread().setName(threadName+" - "+_uri);
530 }
531
532 if (_request.shouldHandleRequest())
533 _server.handle(this);
534 else
535 _request.setHandled(true);
536 }
537 catch (RetryRequest r)
538 {
539 Log.ignore(r);
540 }
541 catch (EofException e)
542 {
543 Log.ignore(e);
544 error=true;
545 }
546 catch (HttpException e)
547 {
548 Log.debug(e);
549 _request.setHandled(true);
550 _response.sendError(e.getStatus(), e.getReason());
551 error=true;
552 }
553 catch (Exception e)
554 {
555 Log.warn(e);
556 _request.setHandled(true);
557 _generator.sendError(500, null, null, true);
558 error=true;
559 }
560 catch (Error e)
561 {
562 Log.warn(e);
563 _request.setHandled(true);
564 _generator.sendError(500, null, null, true);
565 error=true;
566 }
567 finally
568 {
569 handling = !_request.unhandling() && _server != null;
570
571 if (handling)
572 continue;
573
574 if (threadName!=null)
575 Thread.currentThread().setName(threadName);
576
577
578 if (_request.shouldComplete() )
579 {
580 if (_expect == HttpHeaderValues.CONTINUE_ORDINAL)
581 {
582
583 _expect = UNKNOWN;
584 if (_parser instanceof HttpParser)
585 ((HttpParser)_parser).setState(HttpParser.STATE_END);
586 }
587
588 if(_endp.isOpen())
589 {
590 if (_generator.isPersistent())
591 _connector.persist(_endp);
592
593 if (error)
594 _endp.close();
595 else
596 {
597 if (!_response.isCommitted() && !_request.isHandled())
598 _response.sendError(HttpServletResponse.SC_NOT_FOUND);
599 _response.complete();
600 }
601 }
602 else
603 {
604 _response.complete();
605 }
606 }
607 }
608 }
609 }
610
611
612 public void commitResponse(boolean last) throws IOException
613 {
614 if (!_generator.isCommitted())
615 {
616 _generator.setResponse(_response.getStatus(), _response.getReason());
617 _generator.completeHeader(_responseFields, last);
618 }
619 if (last)
620 _generator.complete();
621 }
622
623
624 public void completeResponse() throws IOException
625 {
626 if (!_generator.isCommitted())
627 {
628 _generator.setResponse(_response.getStatus(), _response.getReason());
629 _generator.completeHeader(_responseFields, HttpGenerator.LAST);
630 }
631
632 _generator.complete();
633 }
634
635
636 public void flushResponse() throws IOException
637 {
638 try
639 {
640 commitResponse(HttpGenerator.MORE);
641 _generator.flush();
642 }
643 catch(IOException e)
644 {
645 throw (e instanceof EofException) ? e:new EofException(e);
646 }
647 }
648
649
650 public Generator getGenerator()
651 {
652 return _generator;
653 }
654
655
656
657 public boolean isIncluding()
658 {
659 return _include>0;
660 }
661
662
663 public void include()
664 {
665 _include++;
666 }
667
668
669 public void included()
670 {
671 _include--;
672 if (_out!=null)
673 _out.reopen();
674 }
675
676
677 public boolean isIdle()
678 {
679 return _generator.isIdle() && (_parser.isIdle() || _delayedHandling);
680 }
681
682
683
684
685 private class RequestHandler extends HttpParser.EventHandler
686 {
687 private String _charset;
688
689
690
691
692
693
694 public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
695 {
696 _host = false;
697 _expect = UNKNOWN;
698 _delayedHandling=false;
699 _charset=null;
700
701 if(_request.getTimeStamp()==0)
702 _request.setTimeStamp(System.currentTimeMillis());
703 _request.setMethod(method.toString());
704
705 try
706 {
707 _uri.parse(uri.array(), uri.getIndex(), uri.length());
708 _request.setUri(_uri);
709
710 if (version==null)
711 {
712 _request.setProtocol(HttpVersions.HTTP_0_9);
713 _version=HttpVersions.HTTP_0_9_ORDINAL;
714 }
715 else
716 {
717 version= HttpVersions.CACHE.get(version);
718 _version = HttpVersions.CACHE.getOrdinal(version);
719 if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL;
720 _request.setProtocol(version.toString());
721 }
722
723 _head = method == HttpMethods.HEAD_BUFFER;
724 }
725 catch (Exception e)
726 {
727 throw new HttpException(HttpStatus.ORDINAL_400_Bad_Request,null,e);
728 }
729 }
730
731
732
733
734 public void parsedHeader(Buffer name, Buffer value)
735 {
736 int ho = HttpHeaders.CACHE.getOrdinal(name);
737 switch (ho)
738 {
739 case HttpHeaders.HOST_ORDINAL:
740
741 _host = true;
742 break;
743
744 case HttpHeaders.EXPECT_ORDINAL:
745 value = HttpHeaderValues.CACHE.lookup(value);
746 _expect = HttpHeaderValues.CACHE.getOrdinal(value);
747 break;
748
749 case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
750 case HttpHeaders.USER_AGENT_ORDINAL:
751 value = HttpHeaderValues.CACHE.lookup(value);
752 break;
753
754 case HttpHeaders.CONTENT_TYPE_ORDINAL:
755 value = MimeTypes.CACHE.lookup(value);
756 _charset=MimeTypes.getCharsetFromContentType(value);
757 break;
758
759 case HttpHeaders.CONNECTION_ORDINAL:
760
761 int ordinal = HttpHeaderValues.CACHE.getOrdinal(value);
762 switch(ordinal)
763 {
764 case -1:
765 {
766 String[] values = value.toString().split(",");
767 for (int i=0;values!=null && i<values.length;i++)
768 {
769 CachedBuffer cb = HttpHeaderValues.CACHE.get(values[i].trim());
770
771 if (cb!=null)
772 {
773 switch(cb.getOrdinal())
774 {
775 case HttpHeaderValues.CLOSE_ORDINAL:
776 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
777 _generator.setPersistent(false);
778 break;
779
780 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
781 if (_version==HttpVersions.HTTP_1_0_ORDINAL)
782 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
783 break;
784 }
785 }
786 }
787 break;
788 }
789 case HttpHeaderValues.CLOSE_ORDINAL:
790 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
791 _generator.setPersistent(false);
792 break;
793
794 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
795 if (_version==HttpVersions.HTTP_1_0_ORDINAL)
796 _responseFields.put(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.KEEP_ALIVE_BUFFER);
797 break;
798 }
799 }
800
801 _requestFields.add(name, value);
802 }
803
804
805
806
807 public void headerComplete() throws IOException
808 {
809 _requests++;
810 _generator.setVersion(_version);
811 switch (_version)
812 {
813 case HttpVersions.HTTP_0_9_ORDINAL:
814 break;
815 case HttpVersions.HTTP_1_0_ORDINAL:
816 _generator.setHead(_head);
817 break;
818 case HttpVersions.HTTP_1_1_ORDINAL:
819 _generator.setHead(_head);
820
821 if (_server.getSendDateHeader())
822 _responseFields.put(HttpHeaders.DATE_BUFFER, _request.getTimeStampBuffer(),_request.getTimeStamp());
823
824 if (!_host)
825 {
826 _generator.setResponse(HttpStatus.ORDINAL_400_Bad_Request, null);
827 _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
828 _generator.completeHeader(_responseFields, true);
829 _generator.complete();
830 return;
831 }
832
833 if (_expect != UNKNOWN)
834 {
835 if (_expect == HttpHeaderValues.CONTINUE_ORDINAL)
836 {
837 }
838 else if (_expect == HttpHeaderValues.PROCESSING_ORDINAL)
839 {
840 }
841 else
842 {
843 _generator.sendError(HttpStatus.ORDINAL_417_Expectation_Failed, null, null, true);
844 return;
845 }
846 }
847
848 break;
849 default:
850 }
851
852 if(_charset!=null)
853 _request.setCharacterEncodingUnchecked(_charset);
854
855
856 if ((((HttpParser)_parser).getContentLength()<=0 && !((HttpParser)_parser).isChunking())||_expect==HttpHeaderValues.CONTINUE_ORDINAL)
857 handleRequest();
858 else
859 _delayedHandling=true;
860 }
861
862
863
864
865
866 public void content(Buffer ref) throws IOException
867 {
868 if (_delayedHandling)
869 {
870 _delayedHandling=false;
871 handleRequest();
872 }
873 }
874
875
876
877
878
879
880 public void messageComplete(long contextLength) throws IOException
881 {
882 if (_delayedHandling)
883 {
884 _delayedHandling=false;
885 handleRequest();
886 }
887 }
888
889
890
891
892
893
894
895 public void startResponse(Buffer version, int status, Buffer reason)
896 {
897 Log.debug("Bad request!: "+version+" "+status+" "+reason);
898 }
899
900 }
901
902
903
904
905
906 public class Output extends AbstractGenerator.Output
907 {
908 Output()
909 {
910 super((AbstractGenerator)HttpConnection.this._generator,_connector.getMaxIdleTime());
911 }
912
913
914
915
916
917 public void close() throws IOException
918 {
919 if (_closed)
920 return;
921
922 if (!isIncluding() && !_generator.isCommitted())
923 commitResponse(HttpGenerator.LAST);
924 else
925 flushResponse();
926
927 super.close();
928 }
929
930
931
932
933
934
935 public void flush() throws IOException
936 {
937 if (!_generator.isCommitted())
938 commitResponse(HttpGenerator.MORE);
939 super.flush();
940 }
941
942
943
944
945
946 public void print(String s) throws IOException
947 {
948 if (_closed)
949 throw new IOException("Closed");
950 PrintWriter writer=getPrintWriter(null);
951 writer.print(s);
952 }
953
954
955 public void sendContent(Object content) throws IOException
956 {
957 Resource resource=null;
958
959 if (_closed)
960 throw new IOException("Closed");
961
962 if (_generator.getContentWritten() > 0) throw new IllegalStateException("!empty");
963
964 if (content instanceof HttpContent)
965 {
966 HttpContent c = (HttpContent) content;
967 if (c.getContentType() != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
968 _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, c.getContentType());
969 if (c.getContentLength() > 0)
970 _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER, c.getContentLength());
971 Buffer lm = c.getLastModified();
972 long lml=c.getResource().lastModified();
973 if (lm != null)
974 _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm,lml);
975 else if (c.getResource()!=null)
976 {
977 if (lml!=-1)
978 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml);
979 }
980
981 content = c.getBuffer();
982 if (content==null)
983 content=c.getInputStream();
984 }
985 else if (content instanceof Resource)
986 {
987 resource=(Resource)content;
988 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, resource.lastModified());
989 content=resource.getInputStream();
990 }
991
992
993 if (content instanceof Buffer)
994 {
995 _generator.addContent((Buffer) content, HttpGenerator.LAST);
996 commitResponse(HttpGenerator.LAST);
997 }
998 else if (content instanceof InputStream)
999 {
1000 InputStream in = (InputStream)content;
1001
1002 try
1003 {
1004 int max = _generator.prepareUncheckedAddContent();
1005 Buffer buffer = _generator.getUncheckedBuffer();
1006
1007 int len=buffer.readFrom(in,max);
1008
1009 while (len>=0)
1010 {
1011 _generator.completeUncheckedAddContent();
1012 _out.flush();
1013
1014 max = _generator.prepareUncheckedAddContent();
1015 buffer = _generator.getUncheckedBuffer();
1016 len=buffer.readFrom(in,max);
1017 }
1018 _generator.completeUncheckedAddContent();
1019 _out.flush();
1020 }
1021 finally
1022 {
1023 if (resource!=null)
1024 resource.release();
1025 else
1026 in.close();
1027
1028 }
1029 }
1030 else
1031 throw new IllegalArgumentException("unknown content type?");
1032
1033
1034 }
1035 }
1036
1037
1038
1039
1040 public class OutputWriter extends AbstractGenerator.OutputWriter
1041 {
1042 OutputWriter()
1043 {
1044 super(HttpConnection.this._out);
1045 }
1046 }
1047
1048 }