View Javadoc

1   // ========================================================================
2   // Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses.
12  // ========================================================================
13  
14  package org.eclipse.jetty.server;
15  
16  import java.io.IOException;
17  
18  import org.eclipse.jetty.http.HttpException;
19  import org.eclipse.jetty.http.HttpStatus;
20  import org.eclipse.jetty.io.AsyncEndPoint;
21  import org.eclipse.jetty.io.Connection;
22  import org.eclipse.jetty.io.EndPoint;
23  import org.eclipse.jetty.io.nio.AsyncConnection;
24  import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
25  import org.eclipse.jetty.util.log.Log;
26  import org.eclipse.jetty.util.log.Logger;
27  
28  
29  /* ------------------------------------------------------------ */
30  /** Asychronous Server HTTP connection
31   *
32   */
33  public class AsyncHttpConnection extends AbstractHttpConnection implements AsyncConnection
34  {
35      private final static int NO_PROGRESS_INFO = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_INFO",100);
36      private final static int NO_PROGRESS_CLOSE = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_CLOSE",200);
37  
38      private static final Logger LOG = Log.getLogger(AsyncHttpConnection.class);
39      private int _total_no_progress;
40      private final AsyncEndPoint _asyncEndp;
41  
42      public AsyncHttpConnection(Connector connector, EndPoint endpoint, Server server)
43      {
44          super(connector,endpoint,server);
45          _asyncEndp=(AsyncEndPoint)endpoint;
46      }
47  
48      public Connection handle() throws IOException
49      {
50          Connection connection = this;
51          boolean some_progress=false;
52          boolean progress=true;
53  
54          try
55          {
56              setCurrentConnection(this);
57  
58              // While progress and the connection has not changed
59              while (progress && connection==this)
60              {
61                  progress=false;
62                  try
63                  {
64                      // Handle resumed request
65                      if (_request._async.isAsync() && !_request._async.isComplete())
66                          handleRequest();
67                      // else Parse more input
68                      else if (!_parser.isComplete() && _parser.parseAvailable())
69                          progress=true;
70  
71                      // Generate more output
72                      if (_generator.isCommitted() && !_generator.isComplete() && !_endp.isOutputShutdown())
73                          if (_generator.flushBuffer()>0)
74                              progress=true;
75  
76                      // Flush output
77                      _endp.flush();
78  
79                      // Has any IO been done by the endpoint itself since last loop
80                      if (_asyncEndp.hasProgressed())
81                          progress=true;
82                  }
83                  catch (HttpException e)
84                  {
85                      if (LOG.isDebugEnabled())
86                      {
87                          LOG.debug("uri="+_uri);
88                          LOG.debug("fields="+_requestFields);
89                          LOG.debug(e);
90                      }
91                      progress=true;
92                      _generator.sendError(e.getStatus(), e.getReason(), null, true);
93                  }
94                  finally
95                  {
96                      some_progress|=progress;
97                      //  Is this request/response round complete and are fully flushed?
98                      if (_parser.isComplete() && _generator.isComplete())
99                      {
100                         // Reset the parser/generator
101                         progress=true;
102 
103                         // look for a switched connection instance?
104                         if (_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101)
105                         {
106                             Connection switched=(Connection)_request.getAttribute("org.eclipse.jetty.io.Connection");
107                             if (switched!=null)
108                                 connection=switched;
109                         }
110 
111                         reset();
112 
113                         // TODO Is this still required?
114                         if (!_generator.isPersistent() && !_endp.isOutputShutdown())
115                         {
116                             LOG.warn("Safety net oshut!!!  IF YOU SEE THIS, PLEASE RAISE BUGZILLA");
117                             _endp.shutdownOutput();
118                         }
119                     }
120                     else if (_request.getAsyncContinuation().isAsyncStarted())
121                     {
122                         // The request is suspended, so even though progress has been made, break the while loop
123                         LOG.debug("suspended {}",this);
124                         // TODO: breaking inside finally blocks is bad: rethink how we should exit from here
125                         break;
126                     }
127                 }
128             }
129         }
130         finally
131         {
132             setCurrentConnection(null);
133             if (!_request.isAsyncStarted())
134             {
135                 _parser.returnBuffers();
136                 _generator.returnBuffers();
137             }
138 
139             // Safety net to catch spinning
140             if (some_progress)
141                 _total_no_progress=0;
142             else
143             {
144                 _total_no_progress++;
145                 if (NO_PROGRESS_INFO>0 && _total_no_progress%NO_PROGRESS_INFO==0 && (NO_PROGRESS_CLOSE<=0 || _total_no_progress< NO_PROGRESS_CLOSE))
146                     LOG.info("EndPoint making no progress: "+_total_no_progress+" "+_endp+" "+this);
147                 if (NO_PROGRESS_CLOSE>0 && _total_no_progress==NO_PROGRESS_CLOSE)
148                 {
149                     LOG.warn("Closing EndPoint making no progress: "+_total_no_progress+" "+_endp+" "+this);
150                     if (_endp instanceof SelectChannelEndPoint)
151                         ((SelectChannelEndPoint)_endp).getChannel().close();
152                 }
153             }
154         }
155         return connection;
156     }
157 
158     public void onInputShutdown() throws IOException
159     {
160         // If we don't have a committed response and we are not suspended
161         if (_generator.isIdle() && !_request.getAsyncContinuation().isSuspended())
162         {
163             // then no more can happen, so close.
164             _endp.close();
165         }
166     }
167 
168 }