View Javadoc

1   package org.eclipse.jetty.server;
2   
3   import java.io.IOException;
4   
5   import org.eclipse.jetty.http.HttpException;
6   import org.eclipse.jetty.http.HttpStatus;
7   import org.eclipse.jetty.io.AsyncEndPoint;
8   import org.eclipse.jetty.io.Connection;
9   import org.eclipse.jetty.io.EndPoint;
10  import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
11  import org.eclipse.jetty.util.log.Log;
12  import org.eclipse.jetty.util.log.Logger;
13  
14  public class AsyncHttpConnection extends HttpConnection
15  {
16      private final static int NO_PROGRESS_INFO = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_INFO",100);
17      private final static int NO_PROGRESS_CLOSE = Integer.getInteger("org.mortbay.jetty.NO_PROGRESS_CLOSE",200);
18  
19      private static final Logger LOG = Log.getLogger(AsyncHttpConnection.class);
20      private int _total_no_progress;
21  
22      public AsyncHttpConnection(Connector connector, EndPoint endpoint, Server server)
23      {
24          super(connector,endpoint,server);
25      }
26  
27      public Connection handle() throws IOException
28      {
29          Connection connection = this;
30          boolean some_progress=false;
31          boolean progress=true;
32  
33          // Loop while more in buffer
34          try
35          {
36              setCurrentConnection(this);
37  
38              boolean more_in_buffer =false;
39  
40              while (_endp.isOpen() && (more_in_buffer || progress) && connection==this)
41              {
42                  progress=false;
43                  try
44                  {
45  
46                      // Handle resumed request
47                      if (_request._async.isAsync() && !_request._async.isComplete())
48                          handleRequest();
49  
50                      // else Parse more input
51                      else if (!_parser.isComplete() && _parser.parseAvailable()>0)
52                          progress=true;
53  
54                      // Generate more output
55                      if (_generator.isCommitted() && !_generator.isComplete() && _generator.flushBuffer()>0)
56                          progress=true;
57  
58                      // Flush output from buffering endpoint
59                      if (_endp.isBufferingOutput())
60                          _endp.flush();
61  
62                      // Special case close handling.
63                      // If we were dispatched and have made no progress, but io is shutdown, then close
64                      if (!progress && !some_progress && (_endp.isInputShutdown()||_endp.isOutputShutdown()))
65                         _endp.close();
66                  }
67                  catch (HttpException e)
68                  {
69                      if (LOG.isDebugEnabled())
70                      {
71                          LOG.debug("uri="+_uri);
72                          LOG.debug("fields="+_requestFields);
73                          LOG.debug(e);
74                      }
75                      _generator.sendError(e.getStatus(), e.getReason(), null, true);
76                      _parser.reset();
77                      _endp.close();
78                  }
79                  finally
80                  {
81                      // Do we need to complete a half close?
82                      if (_endp.isInputShutdown() && (_parser.isIdle() || _parser.isComplete()))
83                      {
84                          LOG.debug("complete half close {}",this);
85                          more_in_buffer=false;
86                          _endp.close();
87                          reset(true);
88                      }
89  
90                      // else Is this request/response round complete?
91                      else if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput())
92                      {
93                          // look for a switched connection instance?
94                          if (_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101)
95                          {
96                              Connection switched=(Connection)_request.getAttribute("org.eclipse.jetty.io.Connection");
97                              if (switched!=null)
98                              {
99                                  _parser.reset();
100                                 _generator.reset(true);
101                                 connection=switched;
102                             }
103                         }
104 
105                         // Reset the parser/generator
106                         // keep the buffers as we will cycle
107                         progress=true;
108                         reset(false);
109                         more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
110                     }
111                     // else Are we suspended?
112                     else if (_request.isAsyncStarted())
113                     {
114                         LOG.debug("suspended {}",this);
115                         more_in_buffer=false;
116                         progress=false;
117                     }
118                     else
119                         more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
120 
121                     some_progress|=progress|((SelectChannelEndPoint)_endp).isProgressing();
122                 }
123             }
124         }
125         finally
126         {
127             setCurrentConnection(null);
128             _parser.returnBuffers();
129             _generator.returnBuffers();
130 
131             // Check if we are write blocked
132             if (_generator.isCommitted() && !_generator.isComplete() && _endp.isOpen() && !_endp.isOutputShutdown())
133                 ((AsyncEndPoint)_endp).scheduleWrite(); // TODO. This should not be required
134 
135             if (some_progress)
136             {
137                 _total_no_progress=0;
138             }
139             else
140             {
141                 int totalNoProgress=++_total_no_progress;
142 
143                 if (NO_PROGRESS_INFO>0 && totalNoProgress==NO_PROGRESS_INFO && (NO_PROGRESS_CLOSE<=0 || totalNoProgress<NO_PROGRESS_CLOSE))
144                 {
145                     LOG.info("EndPoint making no progress: {} {}", totalNoProgress, _endp);
146                 }
147 
148                 if (NO_PROGRESS_CLOSE>0 && totalNoProgress==NO_PROGRESS_CLOSE)
149                 {
150                     LOG.warn("Closing EndPoint making no progress: {} {}", totalNoProgress, _endp);
151                     if (_endp instanceof SelectChannelEndPoint)
152                     {
153                         System.err.println(((SelectChannelEndPoint)_endp).getSelectManager().dump());
154                         ((SelectChannelEndPoint)_endp).getChannel().close();
155                     }
156                 }
157             }
158         }
159         return connection;
160     }
161 
162 }