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