comparison src/org/eclipse/jetty/server/AbstractHttpConnection.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 8e9db0bbf4f9
comparison
equal deleted inserted replaced
801:6a21393191c1 802:3428c60d7cfc
1 //
2 // ========================================================================
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.server;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.PrintWriter;
24
25 import javax.servlet.DispatcherType;
26 import javax.servlet.RequestDispatcher;
27 import javax.servlet.ServletInputStream;
28 import javax.servlet.ServletOutputStream;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31
32 import org.eclipse.jetty.continuation.ContinuationThrowable;
33 import org.eclipse.jetty.http.EncodedHttpURI;
34 import org.eclipse.jetty.http.Generator;
35 import org.eclipse.jetty.http.HttpBuffers;
36 import org.eclipse.jetty.http.HttpContent;
37 import org.eclipse.jetty.http.HttpException;
38 import org.eclipse.jetty.http.HttpFields;
39 import org.eclipse.jetty.http.HttpGenerator;
40 import org.eclipse.jetty.http.HttpHeaderValues;
41 import org.eclipse.jetty.http.HttpHeaders;
42 import org.eclipse.jetty.http.HttpMethods;
43 import org.eclipse.jetty.http.HttpParser;
44 import org.eclipse.jetty.http.HttpStatus;
45 import org.eclipse.jetty.http.HttpURI;
46 import org.eclipse.jetty.http.HttpVersions;
47 import org.eclipse.jetty.http.MimeTypes;
48 import org.eclipse.jetty.http.Parser;
49 import org.eclipse.jetty.http.PathMap;
50 import org.eclipse.jetty.io.AbstractConnection;
51 import org.eclipse.jetty.io.Buffer;
52 import org.eclipse.jetty.io.BufferCache.CachedBuffer;
53 import org.eclipse.jetty.io.Buffers;
54 import org.eclipse.jetty.io.Connection;
55 import org.eclipse.jetty.io.EndPoint;
56 import org.eclipse.jetty.io.EofException;
57 import org.eclipse.jetty.io.RuntimeIOException;
58 import org.eclipse.jetty.io.UncheckedPrintWriter;
59 import org.eclipse.jetty.server.handler.ErrorHandler;
60 import org.eclipse.jetty.server.nio.NIOConnector;
61 import org.eclipse.jetty.server.ssl.SslConnector;
62 import org.eclipse.jetty.util.QuotedStringTokenizer;
63 import org.eclipse.jetty.util.StringUtil;
64 import org.eclipse.jetty.util.URIUtil;
65 import org.eclipse.jetty.util.log.Log;
66 import org.eclipse.jetty.util.log.Logger;
67 import org.eclipse.jetty.util.resource.Resource;
68
69 /**
70 * <p>A HttpConnection represents the connection of a HTTP client to the server
71 * and is created by an instance of a {@link Connector}. It's prime function is
72 * to associate {@link Request} and {@link Response} instances with a {@link EndPoint}.
73 * </p>
74 * <p>
75 * A connection is also the prime mechanism used by jetty to recycle objects without
76 * pooling. The {@link Request}, {@link Response}, {@link HttpParser}, {@link HttpGenerator}
77 * and {@link HttpFields} instances are all recycled for the duraction of
78 * a connection. Where appropriate, allocated buffers are also kept associated
79 * with the connection via the parser and/or generator.
80 * </p>
81 * <p>
82 * The connection state is held by 3 separate state machines: The request state, the
83 * response state and the continuation state. All three state machines must be driven
84 * to completion for every request, and all three can complete in any order.
85 * </p>
86 * <p>
87 * The HttpConnection support protocol upgrade. If on completion of a request, the
88 * response code is 101 (switch protocols), then the org.eclipse.jetty.io.Connection
89 * request attribute is checked to see if there is a new Connection instance. If so,
90 * the new connection is returned from {@link #handle()} and is used for future
91 * handling of the underlying connection. Note that for switching protocols that
92 * don't use 101 responses (eg CONNECT), the response should be sent and then the
93 * status code changed to 101 before returning from the handler. Implementors
94 * of new Connection types should be careful to extract any buffered data from
95 * (HttpParser)http.getParser()).getHeaderBuffer() and
96 * (HttpParser)http.getParser()).getBodyBuffer() to initialise their new connection.
97 * </p>
98 *
99 */
100 public abstract class AbstractHttpConnection extends AbstractConnection
101 {
102 private static final Logger LOG = Log.getLogger(AbstractHttpConnection.class);
103
104 private static final int UNKNOWN = -2;
105 private static final ThreadLocal<AbstractHttpConnection> __currentConnection = new ThreadLocal<AbstractHttpConnection>();
106
107 private int _requests;
108
109 protected final Connector _connector;
110 protected final Server _server;
111 protected final HttpURI _uri;
112
113 protected final Parser _parser;
114 protected final HttpFields _requestFields;
115 protected final Request _request;
116 protected volatile ServletInputStream _in;
117
118 protected final Generator _generator;
119 protected final HttpFields _responseFields;
120 protected final Response _response;
121 protected volatile Output _out;
122 protected volatile OutputWriter _writer;
123 protected volatile PrintWriter _printWriter;
124
125 int _include;
126
127 private Object _associatedObject; // associated object
128
129 private int _version = UNKNOWN;
130
131 private String _charset;
132 private boolean _expect = false;
133 private boolean _expect100Continue = false;
134 private boolean _expect102Processing = false;
135 private boolean _head = false;
136 private boolean _host = false;
137 private boolean _delayedHandling=false;
138 private boolean _earlyEOF = false;
139
140 /* ------------------------------------------------------------ */
141 public static AbstractHttpConnection getCurrentConnection()
142 {
143 return __currentConnection.get();
144 }
145
146 /* ------------------------------------------------------------ */
147 protected static void setCurrentConnection(AbstractHttpConnection connection)
148 {
149 __currentConnection.set(connection);
150 }
151
152 /* ------------------------------------------------------------ */
153 public AbstractHttpConnection(Connector connector, EndPoint endpoint, Server server)
154 {
155 super(endpoint);
156 _uri = StringUtil.__UTF8.equals(URIUtil.__CHARSET)?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
157 _connector = connector;
158 HttpBuffers ab = (HttpBuffers)_connector;
159 _parser = newHttpParser(ab.getRequestBuffers(), endpoint, new RequestHandler());
160 _requestFields = new HttpFields();
161 _responseFields = new HttpFields();
162 _request = new Request(this);
163 _response = new Response(this);
164 _generator = newHttpGenerator(ab.getResponseBuffers(), endpoint);
165 _generator.setSendServerVersion(server.getSendServerVersion());
166 _server = server;
167 }
168
169 /* ------------------------------------------------------------ */
170 protected AbstractHttpConnection(Connector connector, EndPoint endpoint, Server server,
171 Parser parser, Generator generator, Request request)
172 {
173 super(endpoint);
174
175 _uri = URIUtil.__CHARSET.equals(StringUtil.__UTF8)?new HttpURI():new EncodedHttpURI(URIUtil.__CHARSET);
176 _connector = connector;
177 _parser = parser;
178 _requestFields = new HttpFields();
179 _responseFields = new HttpFields();
180 _request = request;
181 _response = new Response(this);
182 _generator = generator;
183 _generator.setSendServerVersion(server.getSendServerVersion());
184 _server = server;
185 }
186
187 protected HttpParser newHttpParser(Buffers requestBuffers, EndPoint endpoint, HttpParser.EventHandler requestHandler)
188 {
189 return new HttpParser(requestBuffers, endpoint, requestHandler);
190 }
191
192 protected HttpGenerator newHttpGenerator(Buffers responseBuffers, EndPoint endPoint)
193 {
194 return new HttpGenerator(responseBuffers, endPoint);
195 }
196
197 /* ------------------------------------------------------------ */
198 /**
199 * @return the parser used by this connection
200 */
201 public Parser getParser()
202 {
203 return _parser;
204 }
205
206 /* ------------------------------------------------------------ */
207 /**
208 * @return the number of requests handled by this connection
209 */
210 public int getRequests()
211 {
212 return _requests;
213 }
214
215 /* ------------------------------------------------------------ */
216 public Server getServer()
217 {
218 return _server;
219 }
220
221 /* ------------------------------------------------------------ */
222 /**
223 * @return Returns the associatedObject.
224 */
225 public Object getAssociatedObject()
226 {
227 return _associatedObject;
228 }
229
230 /* ------------------------------------------------------------ */
231 /**
232 * @param associatedObject The associatedObject to set.
233 */
234 public void setAssociatedObject(Object associatedObject)
235 {
236 _associatedObject = associatedObject;
237 }
238
239 /* ------------------------------------------------------------ */
240 /**
241 * @return Returns the connector.
242 */
243 public Connector getConnector()
244 {
245 return _connector;
246 }
247
248 /* ------------------------------------------------------------ */
249 /**
250 * @return Returns the requestFields.
251 */
252 public HttpFields getRequestFields()
253 {
254 return _requestFields;
255 }
256
257 /* ------------------------------------------------------------ */
258 /**
259 * @return Returns the responseFields.
260 */
261 public HttpFields getResponseFields()
262 {
263 return _responseFields;
264 }
265
266 /* ------------------------------------------------------------ */
267 /**
268 * Find out if the request supports CONFIDENTIAL security.
269 * @param request the incoming HTTP request
270 * @return the result of calling {@link Connector#isConfidential(Request)}, or false
271 * if there is no connector
272 */
273 public boolean isConfidential(Request request)
274 {
275 return _connector != null && _connector.isConfidential(request);
276 }
277
278 /* ------------------------------------------------------------ */
279 /**
280 * Find out if the request supports INTEGRAL security.
281 * @param request the incoming HTTP request
282 * @return the result of calling {@link Connector#isIntegral(Request)}, or false
283 * if there is no connector
284 */
285 public boolean isIntegral(Request request)
286 {
287 return _connector != null && _connector.isIntegral(request);
288 }
289
290 /* ------------------------------------------------------------ */
291 /**
292 * @return <code>false</code> (this method is not yet implemented)
293 */
294 public boolean getResolveNames()
295 {
296 return _connector.getResolveNames();
297 }
298
299 /* ------------------------------------------------------------ */
300 /**
301 * @return Returns the request.
302 */
303 public Request getRequest()
304 {
305 return _request;
306 }
307
308 /* ------------------------------------------------------------ */
309 /**
310 * @return Returns the response.
311 */
312 public Response getResponse()
313 {
314 return _response;
315 }
316
317 /* ------------------------------------------------------------ */
318 /**
319 * Get the inputStream from the connection.
320 * <p>
321 * If the associated response has the Expect header set to 100 Continue,
322 * then accessing the input stream indicates that the handler/servlet
323 * is ready for the request body and thus a 100 Continue response is sent.
324 *
325 * @return The input stream for this connection.
326 * The stream will be created if it does not already exist.
327 * @throws IOException if the input stream cannot be retrieved
328 */
329 public ServletInputStream getInputStream() throws IOException
330 {
331 // If the client is expecting 100 CONTINUE, then send it now.
332 if (_expect100Continue)
333 {
334 // is content missing?
335 if (((HttpParser)_parser).getHeaderBuffer()==null || ((HttpParser)_parser).getHeaderBuffer().length()<2)
336 {
337 if (_generator.isCommitted())
338 throw new IllegalStateException("Committed before 100 Continues");
339
340 ((HttpGenerator)_generator).send1xx(HttpStatus.CONTINUE_100);
341 }
342 _expect100Continue=false;
343 }
344
345 if (_in == null)
346 _in = new HttpInput(AbstractHttpConnection.this);
347 return _in;
348 }
349
350 /* ------------------------------------------------------------ */
351 /**
352 * @return The output stream for this connection. The stream will be created if it does not already exist.
353 */
354 public ServletOutputStream getOutputStream()
355 {
356 if (_out == null)
357 _out = new Output();
358 return _out;
359 }
360
361 /* ------------------------------------------------------------ */
362 /**
363 * @param encoding the PrintWriter encoding
364 * @return A {@link PrintWriter} wrapping the {@link #getOutputStream output stream}. The writer is created if it
365 * does not already exist.
366 */
367 public PrintWriter getPrintWriter(String encoding)
368 {
369 getOutputStream();
370 if (_writer==null)
371 {
372 _writer=new OutputWriter();
373 if (_server.isUncheckedPrintWriter())
374 _printWriter=new UncheckedPrintWriter(_writer);
375 else
376 _printWriter = new PrintWriter(_writer)
377 {
378 public void close()
379 {
380 synchronized (lock)
381 {
382 try
383 {
384 out.close();
385 }
386 catch (IOException e)
387 {
388 setError();
389 }
390 }
391 }
392 };
393 }
394 _writer.setCharacterEncoding(encoding);
395 return _printWriter;
396 }
397
398 /* ------------------------------------------------------------ */
399 public boolean isResponseCommitted()
400 {
401 return _generator.isCommitted();
402 }
403
404 /* ------------------------------------------------------------ */
405 public boolean isEarlyEOF()
406 {
407 return _earlyEOF;
408 }
409
410 /* ------------------------------------------------------------ */
411 public void reset()
412 {
413 _parser.reset();
414 _parser.returnBuffers(); // TODO maybe only on unhandle
415 _requestFields.clear();
416 _request.recycle();
417 _generator.reset();
418 _generator.returnBuffers();// TODO maybe only on unhandle
419 _responseFields.clear();
420 _response.recycle();
421 _uri.clear();
422 _writer=null;
423 _earlyEOF = false;
424 }
425
426 /* ------------------------------------------------------------ */
427 protected void handleRequest() throws IOException
428 {
429 boolean error = false;
430
431 String threadName=null;
432 Throwable async_exception=null;
433 try
434 {
435 if (LOG.isDebugEnabled())
436 {
437 threadName=Thread.currentThread().getName();
438 Thread.currentThread().setName(threadName+" - "+_uri);
439 }
440
441
442 // Loop here to handle async request redispatches.
443 // The loop is controlled by the call to async.unhandle in the
444 // finally block below. If call is from a non-blocking connector,
445 // then the unhandle will return false only if an async dispatch has
446 // already happened when unhandle is called. For a blocking connector,
447 // the wait for the asynchronous dispatch or timeout actually happens
448 // within the call to unhandle().
449
450 final Server server=_server;
451 boolean was_continuation=_request._async.isContinuation();
452 boolean handling=_request._async.handling() && server!=null && server.isRunning();
453 while (handling)
454 {
455 _request.setHandled(false);
456
457 String info=null;
458 try
459 {
460 _uri.getPort();
461 String path = null;
462
463 try
464 {
465 path = _uri.getDecodedPath();
466 }
467 catch (Exception e)
468 {
469 LOG.warn("Failed UTF-8 decode for request path, trying ISO-8859-1");
470 LOG.ignore(e);
471 path = _uri.getDecodedPath(StringUtil.__ISO_8859_1);
472 }
473
474 info=URIUtil.canonicalPath(path);
475 if (info==null && !_request.getMethod().equals(HttpMethods.CONNECT))
476 {
477 if (path==null && _uri.getScheme()!=null && _uri.getHost()!=null)
478 {
479 info="/";
480 _request.setRequestURI("");
481 }
482 else
483 throw new HttpException(400);
484 }
485 _request.setPathInfo(info);
486
487 if (_out!=null)
488 _out.reopen();
489
490 if (_request._async.isInitial())
491 {
492 _request.setDispatcherType(DispatcherType.REQUEST);
493 _connector.customize(_endp, _request);
494 server.handle(this);
495 }
496 else
497 {
498 if (_request._async.isExpired()&&!was_continuation)
499 {
500 async_exception = (Throwable)_request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
501 _response.setStatus(500,async_exception==null?"Async Timeout":"Async Exception");
502 _request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500));
503 _request.setAttribute(RequestDispatcher.ERROR_MESSAGE, _response.getReason());
504 _request.setDispatcherType(DispatcherType.ERROR);
505
506 ErrorHandler eh = _request._async.getContextHandler().getErrorHandler();
507 if (eh instanceof ErrorHandler.ErrorPageMapper)
508 {
509 String error_page=((ErrorHandler.ErrorPageMapper)eh).getErrorPage((HttpServletRequest)_request._async.getRequest());
510 if (error_page!=null)
511 {
512 AsyncContinuation.AsyncEventState state = _request._async.getAsyncEventState();
513 state.setPath(error_page);
514 }
515 }
516 }
517 else
518 _request.setDispatcherType(DispatcherType.ASYNC);
519 server.handleAsync(this);
520 }
521 }
522 catch (ContinuationThrowable e)
523 {
524 LOG.ignore(e);
525 }
526 catch (EofException e)
527 {
528 async_exception=e;
529 LOG.debug(e);
530 error=true;
531 _request.setHandled(true);
532 if (!_response.isCommitted())
533 _generator.sendError(500, null, null, true);
534 }
535 catch (RuntimeIOException e)
536 {
537 async_exception=e;
538 LOG.debug(e);
539 error=true;
540 _request.setHandled(true);
541 }
542 catch (HttpException e)
543 {
544 LOG.debug(e);
545 error=true;
546 _request.setHandled(true);
547 _response.sendError(e.getStatus(), e.getReason());
548 }
549 catch (Throwable e)
550 {
551 async_exception=e;
552 LOG.warn(String.valueOf(_uri),e);
553 error=true;
554 _request.setHandled(true);
555 _generator.sendError(info==null?400:500, null, null, true);
556
557 }
558 finally
559 {
560 // Complete async requests
561 if (error && _request.isAsyncStarted())
562 _request.getAsyncContinuation().errorComplete();
563
564 was_continuation=_request._async.isContinuation();
565 handling = !_request._async.unhandle() && server.isRunning() && _server!=null;
566 }
567 }
568 }
569 finally
570 {
571 if (threadName!=null)
572 Thread.currentThread().setName(threadName);
573
574 if (_request._async.isUncompleted())
575 {
576
577 _request._async.doComplete(async_exception);
578
579 if (_expect100Continue)
580 {
581 LOG.debug("100 continues not sent");
582 // We didn't send 100 continues, but the latest interpretation
583 // of the spec (see httpbis) is that the client will either
584 // send the body anyway, or close. So we no longer need to
585 // do anything special here other than make the connection not persistent
586 _expect100Continue = false;
587 if (!_response.isCommitted())
588 _generator.setPersistent(false);
589 }
590
591 if(_endp.isOpen())
592 {
593 if (error)
594 {
595 _endp.shutdownOutput();
596 _generator.setPersistent(false);
597 if (!_generator.isComplete())
598 _response.complete();
599 }
600 else
601 {
602 if (!_response.isCommitted() && !_request.isHandled())
603 _response.sendError(HttpServletResponse.SC_NOT_FOUND);
604 _response.complete();
605 if (_generator.isPersistent())
606 _connector.persist(_endp);
607 }
608 }
609 else
610 {
611 _response.complete();
612 }
613
614 _request.setHandled(true);
615 }
616 }
617 }
618
619 /* ------------------------------------------------------------ */
620 public abstract Connection handle() throws IOException;
621
622 /* ------------------------------------------------------------ */
623 public void commitResponse(boolean last) throws IOException
624 {
625 if (!_generator.isCommitted())
626 {
627 _generator.setResponse(_response.getStatus(), _response.getReason());
628 try
629 {
630 // If the client was expecting 100 continues, but we sent something
631 // else, then we need to close the connection
632 if (_expect100Continue && _response.getStatus()!=100)
633 _generator.setPersistent(false);
634 _generator.completeHeader(_responseFields, last);
635 }
636 catch(RuntimeException e)
637 {
638 LOG.warn("header full: " + e);
639
640 _response.reset();
641 _generator.reset();
642 _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500,null);
643 _generator.completeHeader(_responseFields,Generator.LAST);
644 _generator.complete();
645 throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500);
646 }
647
648 }
649 if (last)
650 _generator.complete();
651 }
652
653 /* ------------------------------------------------------------ */
654 public void completeResponse() throws IOException
655 {
656 if (!_generator.isCommitted())
657 {
658 _generator.setResponse(_response.getStatus(), _response.getReason());
659 try
660 {
661 _generator.completeHeader(_responseFields, Generator.LAST);
662 }
663 catch(RuntimeException e)
664 {
665 LOG.warn("header full: "+e);
666 LOG.debug(e);
667
668 _response.reset();
669 _generator.reset();
670 _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500,null);
671 _generator.completeHeader(_responseFields,Generator.LAST);
672 _generator.complete();
673 throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500);
674 }
675 }
676
677 _generator.complete();
678 }
679
680 /* ------------------------------------------------------------ */
681 public void flushResponse() throws IOException
682 {
683 try
684 {
685 commitResponse(Generator.MORE);
686 _generator.flushBuffer();
687 }
688 catch(IOException e)
689 {
690 throw (e instanceof EofException) ? e:new EofException(e);
691 }
692 }
693
694 /* ------------------------------------------------------------ */
695 public Generator getGenerator()
696 {
697 return _generator;
698 }
699
700 /* ------------------------------------------------------------ */
701 public boolean isIncluding()
702 {
703 return _include>0;
704 }
705
706 /* ------------------------------------------------------------ */
707 public void include()
708 {
709 _include++;
710 }
711
712 /* ------------------------------------------------------------ */
713 public void included()
714 {
715 _include--;
716 if (_out!=null)
717 _out.reopen();
718 }
719
720 /* ------------------------------------------------------------ */
721 public boolean isIdle()
722 {
723 return _generator.isIdle() && (_parser.isIdle() || _delayedHandling);
724 }
725
726 /* ------------------------------------------------------------ */
727 /**
728 * @see org.eclipse.jetty.io.Connection#isSuspended()
729 */
730 public boolean isSuspended()
731 {
732 return _request.getAsyncContinuation().isSuspended();
733 }
734
735 /* ------------------------------------------------------------ */
736 public void onClose()
737 {
738 LOG.debug("closed {}",this);
739 }
740
741 /* ------------------------------------------------------------ */
742 public boolean isExpecting100Continues()
743 {
744 return _expect100Continue;
745 }
746
747 /* ------------------------------------------------------------ */
748 public boolean isExpecting102Processing()
749 {
750 return _expect102Processing;
751 }
752
753 /* ------------------------------------------------------------ */
754 public int getMaxIdleTime()
755 {
756 if (_connector.isLowResources() && _endp.getMaxIdleTime()==_connector.getMaxIdleTime())
757 return _connector.getLowResourceMaxIdleTime();
758 if (_endp.getMaxIdleTime()>0)
759 return _endp.getMaxIdleTime();
760 return _connector.getMaxIdleTime();
761 }
762
763 /* ------------------------------------------------------------ */
764 public String toString()
765 {
766 return String.format("%s,g=%s,p=%s,r=%d",
767 super.toString(),
768 _generator,
769 _parser,
770 _requests);
771 }
772
773 /* ------------------------------------------------------------ */
774 protected void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
775 {
776 uri=uri.asImmutableBuffer();
777
778 _host = false;
779 _expect = false;
780 _expect100Continue=false;
781 _expect102Processing=false;
782 _delayedHandling=false;
783 _charset=null;
784
785 if(_request.getTimeStamp()==0)
786 _request.setTimeStamp(System.currentTimeMillis());
787 _request.setMethod(method.toString());
788
789 try
790 {
791 _head=false;
792 switch (HttpMethods.CACHE.getOrdinal(method))
793 {
794 case HttpMethods.CONNECT_ORDINAL:
795 _uri.parseConnect(uri.array(), uri.getIndex(), uri.length());
796 break;
797
798 case HttpMethods.HEAD_ORDINAL:
799 _head=true;
800 _uri.parse(uri.array(), uri.getIndex(), uri.length());
801 break;
802
803 default:
804 _uri.parse(uri.array(), uri.getIndex(), uri.length());
805 }
806
807 _request.setUri(_uri);
808
809 if (version==null)
810 {
811 _request.setProtocol(HttpVersions.HTTP_0_9);
812 _version=HttpVersions.HTTP_0_9_ORDINAL;
813 }
814 else
815 {
816 version= HttpVersions.CACHE.get(version);
817 if (version==null)
818 throw new HttpException(HttpStatus.BAD_REQUEST_400,null);
819 _version = HttpVersions.CACHE.getOrdinal(version);
820 if (_version <= 0) _version = HttpVersions.HTTP_1_0_ORDINAL;
821 _request.setProtocol(version.toString());
822 }
823 }
824 catch (Exception e)
825 {
826 LOG.debug(e);
827 if (e instanceof HttpException)
828 throw (HttpException)e;
829 throw new HttpException(HttpStatus.BAD_REQUEST_400,null,e);
830 }
831 }
832
833 /* ------------------------------------------------------------ */
834 protected void parsedHeader(Buffer name, Buffer value) throws IOException
835 {
836 int ho = HttpHeaders.CACHE.getOrdinal(name);
837 switch (ho)
838 {
839 case HttpHeaders.HOST_ORDINAL:
840 // TODO check if host matched a host in the URI.
841 _host = true;
842 break;
843
844 case HttpHeaders.EXPECT_ORDINAL:
845 if (_version>=HttpVersions.HTTP_1_1_ORDINAL)
846 {
847 value = HttpHeaderValues.CACHE.lookup(value);
848 switch(HttpHeaderValues.CACHE.getOrdinal(value))
849 {
850 case HttpHeaderValues.CONTINUE_ORDINAL:
851 _expect100Continue=_generator instanceof HttpGenerator;
852 break;
853
854 case HttpHeaderValues.PROCESSING_ORDINAL:
855 _expect102Processing=_generator instanceof HttpGenerator;
856 break;
857
858 default:
859 String[] values = value.toString().split(",");
860 for (int i=0;values!=null && i<values.length;i++)
861 {
862 CachedBuffer cb=HttpHeaderValues.CACHE.get(values[i].trim());
863 if (cb==null)
864 _expect=true;
865 else
866 {
867 switch(cb.getOrdinal())
868 {
869 case HttpHeaderValues.CONTINUE_ORDINAL:
870 _expect100Continue=_generator instanceof HttpGenerator;
871 break;
872 case HttpHeaderValues.PROCESSING_ORDINAL:
873 _expect102Processing=_generator instanceof HttpGenerator;
874 break;
875 default:
876 _expect=true;
877 }
878 }
879 }
880 }
881 }
882 break;
883
884 case HttpHeaders.ACCEPT_ENCODING_ORDINAL:
885 case HttpHeaders.USER_AGENT_ORDINAL:
886 value = HttpHeaderValues.CACHE.lookup(value);
887 break;
888
889 case HttpHeaders.CONTENT_TYPE_ORDINAL:
890 value = MimeTypes.CACHE.lookup(value);
891 _charset=MimeTypes.getCharsetFromContentType(value);
892 break;
893 }
894
895 _requestFields.add(name, value);
896 }
897
898 /* ------------------------------------------------------------ */
899 protected void headerComplete() throws IOException
900 {
901 // Handle idle race
902 if (_endp.isOutputShutdown())
903 {
904 _endp.close();
905 return;
906 }
907
908 _requests++;
909 _generator.setVersion(_version);
910 switch (_version)
911 {
912 case HttpVersions.HTTP_0_9_ORDINAL:
913 break;
914 case HttpVersions.HTTP_1_0_ORDINAL:
915 _generator.setHead(_head);
916 if (_parser.isPersistent())
917 {
918 _responseFields.add(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.KEEP_ALIVE_BUFFER);
919 _generator.setPersistent(true);
920 }
921 else if (HttpMethods.CONNECT.equals(_request.getMethod()))
922 {
923 _generator.setPersistent(true);
924 _parser.setPersistent(true);
925 }
926
927 if (_server.getSendDateHeader())
928 _generator.setDate(_request.getTimeStampBuffer());
929 break;
930
931 case HttpVersions.HTTP_1_1_ORDINAL:
932 _generator.setHead(_head);
933
934 if (!_parser.isPersistent())
935 {
936 _responseFields.add(HttpHeaders.CONNECTION_BUFFER,HttpHeaderValues.CLOSE_BUFFER);
937 _generator.setPersistent(false);
938 }
939 if (_server.getSendDateHeader())
940 _generator.setDate(_request.getTimeStampBuffer());
941
942 if (!_host)
943 {
944 LOG.debug("!host {}",this);
945 _generator.setResponse(HttpStatus.BAD_REQUEST_400, null);
946 _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
947 _generator.completeHeader(_responseFields, true);
948 _generator.complete();
949 return;
950 }
951
952 if (_expect)
953 {
954 LOG.debug("!expectation {}",this);
955 _generator.setResponse(HttpStatus.EXPECTATION_FAILED_417, null);
956 _responseFields.put(HttpHeaders.CONNECTION_BUFFER, HttpHeaderValues.CLOSE_BUFFER);
957 _generator.completeHeader(_responseFields, true);
958 _generator.complete();
959 return;
960 }
961
962 break;
963 default:
964 }
965
966 if(_charset!=null)
967 _request.setCharacterEncodingUnchecked(_charset);
968
969 // Either handle now or wait for first content
970 if ((((HttpParser)_parser).getContentLength()<=0 && !((HttpParser)_parser).isChunking())||_expect100Continue)
971 handleRequest();
972 else
973 _delayedHandling=true;
974 }
975
976 /* ------------------------------------------------------------ */
977 protected void content(Buffer buffer) throws IOException
978 {
979 if (_delayedHandling)
980 {
981 _delayedHandling=false;
982 handleRequest();
983 }
984 }
985
986 /* ------------------------------------------------------------ */
987 public void messageComplete(long contentLength) throws IOException
988 {
989 if (_delayedHandling)
990 {
991 _delayedHandling=false;
992 handleRequest();
993 }
994 }
995
996 /* ------------------------------------------------------------ */
997 public void earlyEOF()
998 {
999 _earlyEOF = true;
1000 }
1001
1002 /* ------------------------------------------------------------ */
1003 /* ------------------------------------------------------------ */
1004 /* ------------------------------------------------------------ */
1005 private class RequestHandler extends HttpParser.EventHandler
1006 {
1007 /*
1008 *
1009 * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startRequest(org.eclipse.io.Buffer,
1010 * org.eclipse.io.Buffer, org.eclipse.io.Buffer)
1011 */
1012 @Override
1013 public void startRequest(Buffer method, Buffer uri, Buffer version) throws IOException
1014 {
1015 AbstractHttpConnection.this.startRequest(method, uri, version);
1016 }
1017
1018 /*
1019 * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#parsedHeaderValue(org.eclipse.io.Buffer)
1020 */
1021 @Override
1022 public void parsedHeader(Buffer name, Buffer value) throws IOException
1023 {
1024 AbstractHttpConnection.this.parsedHeader(name, value);
1025 }
1026
1027 /*
1028 * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#headerComplete()
1029 */
1030 @Override
1031 public void headerComplete() throws IOException
1032 {
1033 AbstractHttpConnection.this.headerComplete();
1034 }
1035
1036 /* ------------------------------------------------------------ */
1037 /*
1038 * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#content(int, org.eclipse.io.Buffer)
1039 */
1040 @Override
1041 public void content(Buffer ref) throws IOException
1042 {
1043 AbstractHttpConnection.this.content(ref);
1044 }
1045
1046 /* ------------------------------------------------------------ */
1047 /*
1048 * (non-Javadoc)
1049 *
1050 * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#messageComplete(int)
1051 */
1052 @Override
1053 public void messageComplete(long contentLength) throws IOException
1054 {
1055 AbstractHttpConnection.this.messageComplete(contentLength);
1056 }
1057
1058 /* ------------------------------------------------------------ */
1059 /*
1060 * (non-Javadoc)
1061 *
1062 * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#startResponse(org.eclipse.io.Buffer, int,
1063 * org.eclipse.io.Buffer)
1064 */
1065 @Override
1066 public void startResponse(Buffer version, int status, Buffer reason)
1067 {
1068 if (LOG.isDebugEnabled())
1069 LOG.debug("Bad request!: "+version+" "+status+" "+reason);
1070 }
1071
1072 /* ------------------------------------------------------------ */
1073 /*
1074 * (non-Javadoc)
1075 *
1076 * @see org.eclipse.jetty.server.server.HttpParser.EventHandler#earlyEOF()
1077 */
1078 @Override
1079 public void earlyEOF()
1080 {
1081 AbstractHttpConnection.this.earlyEOF();
1082 }
1083 }
1084
1085 /* ------------------------------------------------------------ */
1086 /* ------------------------------------------------------------ */
1087 /* ------------------------------------------------------------ */
1088 public class Output extends HttpOutput
1089 {
1090 Output()
1091 {
1092 super(AbstractHttpConnection.this);
1093 }
1094
1095 /* ------------------------------------------------------------ */
1096 /*
1097 * @see java.io.OutputStream#close()
1098 */
1099 @Override
1100 public void close() throws IOException
1101 {
1102 if (isClosed())
1103 return;
1104
1105 if (!isIncluding() && !super._generator.isCommitted())
1106 commitResponse(Generator.LAST);
1107 else
1108 flushResponse();
1109
1110 super.close();
1111 }
1112
1113
1114 /* ------------------------------------------------------------ */
1115 /*
1116 * @see java.io.OutputStream#flush()
1117 */
1118 @Override
1119 public void flush() throws IOException
1120 {
1121 if (!super._generator.isCommitted())
1122 commitResponse(Generator.MORE);
1123 super.flush();
1124 }
1125
1126 /* ------------------------------------------------------------ */
1127 /*
1128 * @see javax.servlet.ServletOutputStream#print(java.lang.String)
1129 */
1130 @Override
1131 public void print(String s) throws IOException
1132 {
1133 if (isClosed())
1134 throw new IOException("Closed");
1135 PrintWriter writer=getPrintWriter(null);
1136 writer.print(s);
1137 }
1138
1139 /* ------------------------------------------------------------ */
1140 public void sendResponse(Buffer response) throws IOException
1141 {
1142 ((HttpGenerator)super._generator).sendResponse(response);
1143 }
1144
1145 /* ------------------------------------------------------------ */
1146 public void sendContent(Object content) throws IOException
1147 {
1148 Resource resource=null;
1149
1150 if (isClosed())
1151 throw new IOException("Closed");
1152
1153 if (super._generator.isWritten())
1154 throw new IllegalStateException("!empty");
1155
1156 // Convert HTTP content to content
1157 if (content instanceof HttpContent)
1158 {
1159 HttpContent httpContent = (HttpContent) content;
1160 Buffer contentType = httpContent.getContentType();
1161 if (contentType != null && !_responseFields.containsKey(HttpHeaders.CONTENT_TYPE_BUFFER))
1162 {
1163 String enc = _response.getSetCharacterEncoding();
1164 if(enc==null)
1165 _responseFields.add(HttpHeaders.CONTENT_TYPE_BUFFER, contentType);
1166 else
1167 {
1168 if(contentType instanceof CachedBuffer)
1169 {
1170 CachedBuffer content_type = ((CachedBuffer)contentType).getAssociate(enc);
1171 if(content_type!=null)
1172 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER, content_type);
1173 else
1174 {
1175 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1176 contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1177 }
1178 }
1179 else
1180 {
1181 _responseFields.put(HttpHeaders.CONTENT_TYPE_BUFFER,
1182 contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(enc,";= "));
1183 }
1184 }
1185 }
1186 if (httpContent.getContentLength() > 0)
1187 _responseFields.putLongField(HttpHeaders.CONTENT_LENGTH_BUFFER, httpContent.getContentLength());
1188 Buffer lm = httpContent.getLastModified();
1189 long lml=httpContent.getResource().lastModified();
1190 if (lm != null)
1191 {
1192 _responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm);
1193 }
1194 else if (httpContent.getResource()!=null)
1195 {
1196 if (lml!=-1)
1197 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, lml);
1198 }
1199
1200 Buffer etag=httpContent.getETag();
1201 if (etag!=null)
1202 _responseFields.put(HttpHeaders.ETAG_BUFFER,etag);
1203
1204
1205 boolean direct=_connector instanceof NIOConnector && ((NIOConnector)_connector).getUseDirectBuffers() && !(_connector instanceof SslConnector);
1206 content = direct?httpContent.getDirectBuffer():httpContent.getIndirectBuffer();
1207 if (content==null)
1208 content=httpContent.getInputStream();
1209 }
1210 else if (content instanceof Resource)
1211 {
1212 resource=(Resource)content;
1213 _responseFields.putDateField(HttpHeaders.LAST_MODIFIED_BUFFER, resource.lastModified());
1214 content=resource.getInputStream();
1215 }
1216
1217 // Process content.
1218 if (content instanceof Buffer)
1219 {
1220 super._generator.addContent((Buffer) content, Generator.LAST);
1221 commitResponse(Generator.LAST);
1222 }
1223 else if (content instanceof InputStream)
1224 {
1225 InputStream in = (InputStream)content;
1226
1227 try
1228 {
1229 int max = super._generator.prepareUncheckedAddContent();
1230 Buffer buffer = super._generator.getUncheckedBuffer();
1231
1232 int len=buffer.readFrom(in,max);
1233
1234 while (len>=0)
1235 {
1236 super._generator.completeUncheckedAddContent();
1237 _out.flush();
1238
1239 max = super._generator.prepareUncheckedAddContent();
1240 buffer = super._generator.getUncheckedBuffer();
1241 len=buffer.readFrom(in,max);
1242 }
1243 super._generator.completeUncheckedAddContent();
1244 _out.flush();
1245 }
1246 finally
1247 {
1248 if (resource!=null)
1249 resource.release();
1250 else
1251 in.close();
1252 }
1253 }
1254 else
1255 throw new IllegalArgumentException("unknown content type?");
1256
1257
1258 }
1259 }
1260
1261 /* ------------------------------------------------------------ */
1262 /* ------------------------------------------------------------ */
1263 /* ------------------------------------------------------------ */
1264 public class OutputWriter extends HttpWriter
1265 {
1266 OutputWriter()
1267 {
1268 super(AbstractHttpConnection.this._out);
1269 }
1270 }
1271
1272
1273 }