You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2011/09/08 11:07:34 UTC

svn commit: r1166576 - in /tomcat/tc7.0.x/trunk: ./ java/org/apache/coyote/http11/ java/org/apache/tomcat/util/net/ webapps/docs/config/

Author: markt
Date: Thu Sep  8 09:07:34 2011
New Revision: 1166576

URL: http://svn.apache.org/viewvc?rev=1166576&view=rev
Log:
Merge re-factoring from trunk that pulled up HttpXXXProcessor.process(), better aligned the behaviour of the HTTP connectors and provided better support for infinite connection and/or keep-alive timeouts

Modified:
    tomcat/tc7.0.x/trunk/   (props changed)
    tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
    tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
    tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
    tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java
    tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java
    tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
    tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java
    tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
    tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml

Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Sep  8 09:07:34 2011
@@ -1 +1 @@
-/tomcat/trunk:1156171,1156276,1156304,1156530,1156602,1157015,1157018,1157151,1157198,1157204,1157810,1157832,1157834,1157847,1157908,1157939,1158155,1158160,1158176,1158195,1158198-1158199,1158227,1158331,1158334-1158335,1158426,1160347,1160592,1160611,1160619,1160626,1160639,1160652,1160720-1160721,1160772,1160774,1160776,1161303,1161310,1161322,1161339,1161486,1161540,1161549,1161584,1162082,1162149,1162169,1162721,1162769,1162836,1162932,1163630,1164419,1164438,1164469,1164480,1164567,1165234,1166077,1166290,1166366
+/tomcat/trunk:1156171,1156276,1156304,1156530,1156602,1157015,1157018,1157151,1157198,1157204,1157810,1157832,1157834,1157847,1157908,1157939,1158155,1158160,1158176,1158195,1158198-1158199,1158227,1158331,1158334-1158335,1158426,1160347,1160592,1160611,1160619,1160626,1160639,1160652,1160720-1160721,1160772,1160774,1160776,1161303,1161310,1161322,1161339,1161486,1161540,1161549,1161584,1162082,1162149,1162169,1162721,1162769,1162836,1162932,1163630,1164419,1164438,1164469,1164480,1164567,1165234,1165247-1165248,1165253,1165273,1165282,1165309,1165331,1165338,1165347,1165360-1165361,1165367-1165368,1165602,1165608,1165677,1165693,1165721,1165723,1165728,1165730,1165738,1165746,1165765,1165777,1165918,1165921,1166077,1166150-1166151,1166290,1166366

Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java Thu Sep  8 09:07:34 2011
@@ -47,6 +47,7 @@ import org.apache.tomcat.util.http.MimeH
 import org.apache.tomcat.util.net.AbstractEndpoint;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
 import org.apache.tomcat.util.net.SocketStatus;
+import org.apache.tomcat.util.net.SocketWrapper;
 import org.apache.tomcat.util.res.StringManager;
 
 public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {
@@ -79,6 +80,36 @@ public abstract class AbstractHttp11Proc
 
 
     /**
+     * Flag used to indicate that the socket should be kept open (e.g. for keep
+     * alive or send file.
+     */
+    protected boolean openSocket = false;
+
+
+    /**
+     * Flag used to indicate that the socket should treat the next request
+     * processed like a keep-alive connection - i.e. one where there may not be
+     * any data to process. The initial value of this flag on entering the
+     * process method is different for connectors that use polling (NIO / APR -
+     * data is always expected) compared to those that use blocking (BIO - data
+     * is only expected if the connection isn't in the keep-alive state).
+     */
+    protected boolean keptAlive;
+
+
+    /**
+     * Flag that indicates that send file processing is in progress and that the
+     * socket should not be returned to the poller (where a poller is used).
+     */
+    protected boolean sendfileInProgress = false;
+
+
+    /**
+     * Flag that indicates if the request headers have been completely read.
+     */
+    protected boolean readComplete = true;
+
+    /**
      * HTTP/1.1 flag.
      */
     protected boolean http11 = true;
@@ -607,6 +638,12 @@ public abstract class AbstractHttp11Proc
                status == 501 /* SC_NOT_IMPLEMENTED */;
     }
 
+    
+    /**
+     * Allows the super class to set the socket wrapper being used.
+     */
+    protected abstract void setSocketWrapper(SocketWrapper<S> socketWrapper);
+
 
     /**
      * Exposes input buffer to super class to allow better code re-use.
@@ -786,6 +823,232 @@ public abstract class AbstractHttp11Proc
 
 
     /**
+     * Configures the timeout to be used for reading the request line.
+     */
+    protected abstract void setRequestLineReadTimeout() throws IOException;
+
+
+    /**
+     * Defines how a connector handles an incomplete request line read.
+     * 
+     * @returns <code>true</code> if the processor should break out of the
+     *          processing loop, otherwise <code>false</code>.
+     */
+    protected abstract boolean handleIncompleteRequestLineRead();
+
+
+    /**
+     * Set the socket timeout.
+     */
+    protected abstract void setSocketTimeout(int timeout) throws IOException;
+
+
+    /**
+     * Process pipelined HTTP requests using the specified input and output
+     * streams.
+     *
+     * @param socketWrapper Socket from which the HTTP requests will be read
+     *               and the HTTP responses will be written.
+     *  
+     * @throws IOException error during an I/O operation
+     */
+    @Override
+    public SocketState process(SocketWrapper<S> socketWrapper)
+        throws IOException {
+        RequestInfo rp = request.getRequestProcessor();
+        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
+
+        // Setting up the I/O
+        setSocketWrapper(socketWrapper);
+        getInputBuffer().init(socketWrapper, endpoint);
+        getOutputBuffer().init(socketWrapper, endpoint);
+
+        // Flags
+        error = false;
+        keepAlive = true;
+        comet = false;
+        openSocket = false;
+        sendfileInProgress = false;
+        readComplete = true;
+        if (endpoint.getUsePolling()) {
+            keptAlive = false;
+        } else {
+            keptAlive = socketWrapper.isKeptAlive();
+        }
+
+        if (disableKeepAlive()) {
+            socketWrapper.setKeepAliveLeft(0);
+        }
+
+        while (!error && keepAlive && !comet && !isAsync() &&
+                !endpoint.isPaused()) {
+
+            // Parsing the request header
+            try {
+                setRequestLineReadTimeout();
+                
+                if (!getInputBuffer().parseRequestLine(keptAlive)) {
+                    if (handleIncompleteRequestLineRead()) {
+                        break;
+                    }
+                }
+
+                if (endpoint.isPaused()) {
+                    // 503 - Service unavailable
+                    response.setStatus(503);
+                    adapter.log(request, response, 0);
+                    error = true;
+                } else {
+                    request.setStartTime(System.currentTimeMillis());
+                    keptAlive = true;
+                    // Currently only NIO will ever return false here
+                    if (!getInputBuffer().parseHeaders()) {
+                        // We've read part of the request, don't recycle it
+                        // instead associate it with the socket
+                        openSocket = true;
+                        readComplete = false;
+                        break;
+                    }
+                    if (!disableUploadTimeout) {
+                        setSocketTimeout(connectionUploadTimeout);
+                    }
+                }
+            } catch (IOException e) {
+                if (getLog().isDebugEnabled()) {
+                    getLog().debug(
+                            sm.getString("http11processor.header.parse"), e);
+                }
+                error = true;
+                break;
+            } catch (Throwable t) {
+                ExceptionUtils.handleThrowable(t);
+                if (getLog().isDebugEnabled()) {
+                    getLog().debug(
+                            sm.getString("http11processor.header.parse"), t);
+                }
+                // 400 - Bad Request
+                response.setStatus(400);
+                adapter.log(request, response, 0);
+                error = true;
+            }
+
+            if (!error) {
+                // Setting up filters, and parse some request headers
+                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
+                try {
+                    prepareRequest();
+                } catch (Throwable t) {
+                    ExceptionUtils.handleThrowable(t);
+                    if (getLog().isDebugEnabled()) {
+                        getLog().debug(sm.getString(
+                                "http11processor.request.prepare"), t);
+                    }
+                    // 400 - Internal Server Error
+                    response.setStatus(400);
+                    adapter.log(request, response, 0);
+                    error = true;
+                }
+            }
+
+            if (maxKeepAliveRequests == 1) {
+                keepAlive = false;
+            } else if (maxKeepAliveRequests > 0 &&
+                    socketWrapper.decrementKeepAlive() <= 0) {
+                keepAlive = false;
+            }
+
+            // Process the request in the adapter
+            if (!error) {
+                try {
+                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
+                    adapter.service(request, response);
+                    // Handle when the response was committed before a serious
+                    // error occurred.  Throwing a ServletException should both
+                    // set the status to 500 and set the errorException.
+                    // If we fail here, then the response is likely already
+                    // committed, so we can't try and set headers.
+                    if(keepAlive && !error) { // Avoid checking twice.
+                        error = response.getErrorException() != null ||
+                                (!isAsync() &&
+                                statusDropsConnection(response.getStatus()));
+                    }
+                    setCometTimeouts(socketWrapper);
+                } catch (InterruptedIOException e) {
+                    error = true;
+                } catch (Throwable t) {
+                    ExceptionUtils.handleThrowable(t);
+                    getLog().error(sm.getString(
+                            "http11processor.request.process"), t);
+                    // 500 - Internal Server Error
+                    response.setStatus(500);
+                    adapter.log(request, response, 0);
+                    error = true;
+                }
+            }
+
+            // Finish the handling of the request
+            rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
+
+            if (!isAsync() && !comet) {
+                if (error) {
+                    // If we know we are closing the connection, don't drain
+                    // input. This way uploading a 100GB file doesn't tie up the
+                    // thread if the servlet has rejected it.
+                    getInputBuffer().setSwallowInput(false);
+                }
+                endRequest();
+            }
+
+            rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
+
+            // If there was an error, make sure the request is counted as
+            // and error, and update the statistics counter
+            if (error) {
+                response.setStatus(500);
+            }
+            request.updateCounters();
+
+            if (!isAsync() && !comet || error) {
+                getInputBuffer().nextRequest();
+                getOutputBuffer().nextRequest();
+            }
+
+            if (!disableUploadTimeout) {
+                setSocketTimeout(endpoint.getSoTimeout());
+            }
+
+            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
+
+            if (breakKeepAliveLoop(socketWrapper)) {
+                break;
+            }
+        }
+
+        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
+
+        if (error || endpoint.isPaused()) {
+            return SocketState.CLOSED;
+        } else if (isAsync() || comet) {
+            return SocketState.LONG;
+        } else {
+            if (sendfileInProgress) {
+                return SocketState.SENDFILE;
+            } else {
+                if (openSocket) {
+                    if (readComplete) {
+                        return SocketState.OPEN;
+                    } else {
+                        return SocketState.LONG;
+                    }
+                } else {
+                    return SocketState.CLOSED;
+                }
+            }
+        }
+    }
+
+
+    /**
      * After reading the request headers, we have to setup the request filters.
      */
     protected void prepareRequest() {
@@ -1271,6 +1534,12 @@ public abstract class AbstractHttp11Proc
     protected abstract void resetTimeouts();
 
 
+    /**
+     * Provides a mechanism for those connectors (currently only NIO) that need
+     * that need to set comet timeouts.
+     */
+    protected abstract void setCometTimeouts(SocketWrapper<S> socketWrapper);
+
     public void endRequest() {
 
         // Finish the handling of the request
@@ -1297,7 +1566,18 @@ public abstract class AbstractHttp11Proc
         }
 
     }
-    
+
+
+    /**
+     * Checks to see of the keep-alive loop should be broken, performing any
+     * processing (e.g. send file handling) that may have an impact on whether
+     * or not the keep-alive loop should be broken.
+     * @return
+     */
+    protected abstract boolean breakKeepAliveLoop(
+            SocketWrapper<S> socketWrapper);
+
+
     public final void recycle() {
         getInputBuffer().recycle();
         getOutputBuffer().recycle();

Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java Thu Sep  8 09:07:34 2011
@@ -157,207 +157,91 @@ public class Http11AprProcessor extends 
         }
     }
     
-    /**
-     * Process pipelined HTTP requests using the specified input and output
-     * streams.
-     *
-     * @param socketWrapper Socket from which the HTTP requests will be read
-     *               and the HTTP responses will be written.
-     *  
-     * @throws IOException error during an I/O operation
-     */
     @Override
-    public SocketState process(SocketWrapper<Long> socketWrapper)
-        throws IOException {
-        RequestInfo rp = request.getRequestProcessor();
-        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
+    protected boolean disableKeepAlive() {
+        return false;
+    }
 
-        // Setting up the socket
-        this.socket = socketWrapper;
-        inputBuffer.init(socketWrapper, endpoint);
-        outputBuffer.init(socketWrapper, endpoint);
 
-        // Error flag
-        error = false;
-        keepAlive = true;
-        comet = false;
+    @Override
+    protected void setRequestLineReadTimeout() throws IOException {
+        // Timeouts while in the poller are handled entirely by the poller
+        // Only need to be concerned with socket timeouts
 
-        int soTimeout = endpoint.getSoTimeout();
+        // APR uses simulated blocking so if some request line data is present
+        // then it must all be presented (with the normal socket timeout).
+        
+        // When entering the processing loop for the first time there will
+        // always be some data to read so the keep-alive timeout is not required
+        
+        // For the second and subsequent executions of the processing loop, if
+        // there is no request line data present then no further data will be
+        // read from the socket. If there is request line data present then it
+        // must all be presented (with the normal socket timeout)
+
+        // When the socket is created it is given the correct timeout.
+        // sendfile may change the timeout but will restore it
+        // This processor may change the timeout for uploads but will restore it
+        
+        // NO-OP
+    }
 
-        if (disableKeepAlive()) {
-            socketWrapper.setKeepAliveLeft(0);
-        }
 
-        boolean keptAlive = false;
-        boolean openSocket = false;
-        boolean sendfileInProgress = false;
+    @Override
+    protected boolean handleIncompleteRequestLineRead() {
+        // This means that no data is available right now
+        // (long keepalive), so that the processor should be recycled
+        // and the method should return true
+        openSocket = true;
+        if (endpoint.isPaused()) {
+            // 503 - Service unavailable
+            response.setStatus(503);
+            adapter.log(request, response, 0);
+            error = true;
+        } else {
+            return true;
+        }
+        return false;
+    }
 
-        long socketRef = socketWrapper.getSocket().longValue();
 
-        while (!error && keepAlive && !comet && !isAsync() && !endpoint.isPaused()) {
+    @Override
+    protected void setSocketTimeout(int timeout) {
+        Socket.timeoutSet(socket.getSocket().longValue(), timeout * 1000);
+    }
+    
+    
+    @Override
+    protected void setCometTimeouts(SocketWrapper<Long> socketWrapper) {
+        // NO-OP for APR/native
+    }
 
-            // Parsing the request header
-            try {
-                if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) {
-                    Socket.timeoutSet(socketRef, soTimeout * 1000);
-                }
-                if (!inputBuffer.parseRequestLine(keptAlive)) {
-                    // This means that no data is available right now
-                    // (long keepalive), so that the processor should be recycled
-                    // and the method should return true
-                    openSocket = true;
-                    if (endpoint.isPaused()) {
-                        // 503 - Service unavailable
-                        response.setStatus(503);
-                        adapter.log(request, response, 0);
-                        error = true;
-                    } else {
-                        break;
-                    }
-                }
-                if (!endpoint.isPaused()) {
-                    request.setStartTime(System.currentTimeMillis());
-                    keptAlive = true;
-                    if (!disableUploadTimeout) {
-                        Socket.timeoutSet(socketRef,
-                                connectionUploadTimeout * 1000);
-                    }
-                    inputBuffer.parseHeaders();
-                }
-            } catch (IOException e) {
-                error = true;
-                break;
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("http11processor.header.parse"), t);
-                }
-                // 400 - Bad Request
-                response.setStatus(400);
-                adapter.log(request, response, 0);
-                error = true;
-            }
 
-            if (!error) {
-                // Setting up filters, and parse some request headers
-                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
-                try {
-                    prepareRequest();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
+    @Override
+    protected boolean breakKeepAliveLoop(SocketWrapper<Long> socketWrapper) {
+        openSocket = keepAlive;
+        // Do sendfile as needed: add socket to sendfile and end
+        if (sendfileData != null && !error) {
+            sendfileData.socket = socketWrapper.getSocket().longValue();
+            sendfileData.keepAlive = keepAlive;
+            if (!((AprEndpoint)endpoint).getSendfile().add(sendfileData)) {
+                // Didn't send all of the data to sendfile.
+                if (sendfileData.socket == 0) {
+                    // The socket is no longer set. Something went wrong.
+                    // Close the connection. Too late to set status code.
                     if (log.isDebugEnabled()) {
-                        log.debug(sm.getString("http11processor.request.prepare"), t);
+                        log.debug(sm.getString(
+                                "http11processor.sendfile.error"));
                     }
-                    // 400 - Internal Server Error
-                    response.setStatus(400);
-                    adapter.log(request, response, 0);
                     error = true;
+                } else {
+                    // The sendfile Poller will add the socket to the main
+                    // Poller once sendfile processing is complete
+                    sendfileInProgress = true;
                 }
+                return true;
             }
-
-            if (maxKeepAliveRequests == 1) {
-                keepAlive = false;
-            } else if (maxKeepAliveRequests > 0 &&
-                    socketWrapper.decrementKeepAlive() <= 0) {
-                keepAlive = false;
-            }
-
-            // Process the request in the adapter
-            if (!error) {
-                try {
-                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
-                    adapter.service(request, response);
-                    // Handle when the response was committed before a serious
-                    // error occurred.  Throwing a ServletException should both
-                    // set the status to 500 and set the errorException.
-                    // If we fail here, then the response is likely already
-                    // committed, so we can't try and set headers.
-                    if(keepAlive && !error) { // Avoid checking twice.
-                        error = response.getErrorException() != null ||
-                                (!isAsync() &&
-                                statusDropsConnection(response.getStatus()));
-                    }
-                } catch (InterruptedIOException e) {
-                    error = true;
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    log.error(sm.getString("http11processor.request.process"), t);
-                    // 500 - Internal Server Error
-                    response.setStatus(500);
-                    adapter.log(request, response, 0);
-                    error = true;
-                }
-            }
-
-            // Finish the handling of the request
-            if (!comet && !isAsync()) {
-                // If we know we are closing the connection, don't drain input.
-                // This way uploading a 100GB file doesn't tie up the thread 
-                // if the servlet has rejected it.
-                if(error)
-                    inputBuffer.setSwallowInput(false);
-                endRequest();
-            }
-
-            // If there was an error, make sure the request is counted as
-            // and error, and update the statistics counter
-            if (error) {
-                response.setStatus(500);
-            }
-            request.updateCounters();
-
-            if (!comet && !isAsync()) {
-                // Next request
-                inputBuffer.nextRequest();
-                outputBuffer.nextRequest();
-            }
-            
-            // Do sendfile as needed: add socket to sendfile and end
-            if (sendfileData != null && !error) {
-                sendfileData.socket = socketRef;
-                sendfileData.keepAlive = keepAlive;
-                if (!((AprEndpoint)endpoint).getSendfile().add(sendfileData)) {
-                    // Didn't send all of the data to sendfile.
-                    if (sendfileData.socket == 0) {
-                        // The socket is no longer set. Something went wrong.
-                        // Close the connection. Too late to set status code.
-                        if (log.isDebugEnabled()) {
-                            log.debug(sm.getString(
-                                    "http11processor.sendfile.error"));
-                        }
-                        error = true;
-                    } else {
-                        // The sendfile Poller will add the socket to the main
-                        // Poller once sendfile processing is complete
-                        sendfileInProgress = true;
-                    }
-                    break;
-                }
-            }
-            
-            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
-
         }
-
-        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
-
-        if (error || endpoint.isPaused()) {
-            return SocketState.CLOSED;
-        } else if (comet  || isAsync()) {
-            return SocketState.LONG;
-        } else {
-            if (sendfileInProgress) {
-                return SocketState.SENDFILE;
-            } else {
-                return (openSocket) ? SocketState.OPEN : SocketState.CLOSED;
-            }
-        }
-        
-    }
-
-
-    @Override
-    protected boolean disableKeepAlive() {
         return false;
     }
 
@@ -633,6 +517,11 @@ public class Http11AprProcessor extends 
     }
 
     @Override
+    protected void setSocketWrapper(SocketWrapper<Long> socketWrapper) {
+        this.socket = socketWrapper;
+    }
+
+    @Override
     protected AbstractInputBuffer<Long> getInputBuffer() {
         return inputBuffer;
     }

Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Thu Sep  8 09:07:34 2011
@@ -137,7 +137,7 @@ public class Http11NioProcessor extends 
                         if (comettimeout != null) attach.setTimeout(comettimeout.longValue());
                     } else {
                         //reset the timeout
-                        if (keepAlive && keepAliveTimeout>0) {
+                        if (keepAlive) {
                             attach.setTimeout(keepAliveTimeout);
                         } else {
                             attach.setTimeout(soTimeout);
@@ -177,7 +177,7 @@ public class Http11NioProcessor extends 
             long soTimeout = endpoint.getSoTimeout();
 
             //reset the timeout
-            if (keepAlive && keepAliveTimeout>0) {
+            if (keepAlive) {
                 attach.setTimeout(keepAliveTimeout);
             } else {
                 attach.setTimeout(soTimeout);
@@ -186,224 +186,102 @@ public class Http11NioProcessor extends 
     }
 
 
-    /**
-     * Process pipelined HTTP requests using the specified input and output
-     * streams.
-     *
-     * @param socketWrapper Socket from which the HTTP requests will be read
-     *               and the HTTP responses will be written.
-     *  
-     * @throws IOException error during an I/O operation
-     */
     @Override
-    public SocketState process(SocketWrapper<NioChannel> socketWrapper)
-        throws IOException {
-        RequestInfo rp = request.getRequestProcessor();
-        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
-
-        // Setting up the socket
-        this.socket = socketWrapper;
-        inputBuffer.init(socketWrapper, endpoint);
-        outputBuffer.init(socketWrapper, endpoint);
+    protected boolean disableKeepAlive() {
+        return false;
+    }
 
-        // Error flag
-        error = false;
-        keepAlive = true;
-        comet = false;
-        
-        int soTimeout = endpoint.getSoTimeout();
 
-        if (disableKeepAlive()) {
-            socketWrapper.setKeepAliveLeft(0);
-        }
+    @Override
+    protected void setRequestLineReadTimeout() throws IOException {
+        // socket.setTimeout()
+        //     - timeout used by poller
+        // socket.getSocket().getIOChannel().socket().setSoTimeout()
+        //     - timeout used for blocking reads
 
-        boolean keptAlive = false;
-        boolean openSocket = false;
-        boolean readComplete = true;
+        // When entering the processing loop there will always be data to read
+        // so no point changing timeouts at this point
         
-        while (!error && keepAlive && !comet && !isAsync() && !endpoint.isPaused()) {
-            //always default to our soTimeout
-            socketWrapper.setTimeout(soTimeout);
-            // Parsing the request header
-            try {
-                if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) {
-                    socketWrapper.getSocket().getIOChannel().socket().setSoTimeout(soTimeout);
-                }
-                if (!inputBuffer.parseRequestLine(keptAlive)) {
-                    // Haven't finished reading the request so keep the socket
-                    // open
-                    openSocket = true;
-                    // Check to see if we have read any of the request line yet
-                    if (inputBuffer.getParsingRequestLinePhase()<2) {
-                        // No data read, OK to recycle the processor
-                        // Continue to use keep alive timeout
-                        if (keepAliveTimeout>0) {
-                            socketWrapper.setTimeout(keepAliveTimeout);
-                        }
-                    } else {
-                        // Started to read request line. Need to keep processor
-                        // associated with socket
-                        readComplete = false;
-                    }
-                    if (endpoint.isPaused()) {
-                        // 503 - Service unavailable
-                        response.setStatus(503);
-                        adapter.log(request, response, 0);
-                        error = true;
-                    } else {
-                        break;
-                    }
-                }
-                if (!endpoint.isPaused()) {
-                    keptAlive = true;
-                    if ( !inputBuffer.parseHeaders() ) {
-                        //we've read part of the request, don't recycle it
-                        //instead associate it with the socket
-                        openSocket = true;
-                        readComplete = false;
-                        break;
-                    }
-                    request.setStartTime(System.currentTimeMillis());
-                    if (!disableUploadTimeout) { //only for body, not for request headers
-                        socketWrapper.getSocket().getIOChannel().socket().setSoTimeout(
-                                connectionUploadTimeout);
-                    }
-                }
-            } catch (IOException e) {
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("http11processor.header.parse"), e);
-                }
-                error = true;
-                break;
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("http11processor.header.parse"), t);
-                }
-                // 400 - Bad Request
-                response.setStatus(400);
-                adapter.log(request, response, 0);
-                error = true;
-            }
-
-            if (!error) {
-                // Setting up filters, and parse some request headers
-                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
-                try {
-                    prepareRequest();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    if (log.isDebugEnabled()) {
-                        log.debug(sm.getString("http11processor.request.prepare"), t);
-                    }
-                    // 400 - Internal Server Error
-                    response.setStatus(400);
-                    adapter.log(request, response, 0);
-                    error = true;
-                }
-            }
-            
-            if (maxKeepAliveRequests == 1) {
-                keepAlive = false;
-            } else if (maxKeepAliveRequests > 0 &&
-                    socketWrapper.decrementKeepAlive() <= 0) {
-                keepAlive = false;
-            }
+        // For the second and subsequent executions of the processing loop, a
+        // non-blocking read is used so again no need to set the timeouts
+        
+        // Because NIO supports non-blocking reading of the request line and
+        // headers the timeouts need to be set when returning the socket to
+        // the poller rather than here.
+        
+        // NO-OP
+    }
 
-            // Process the request in the adapter
-            if (!error) {
-                try {
-                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
-                    adapter.service(request, response);
-                    // Handle when the response was committed before a serious
-                    // error occurred.  Throwing a ServletException should both
-                    // set the status to 500 and set the errorException.
-                    // If we fail here, then the response is likely already
-                    // committed, so we can't try and set headers.
-                    if(keepAlive && !error) { // Avoid checking twice.
-                        error = response.getErrorException() != null ||
-                                (!isAsync() &&
-                                statusDropsConnection(response.getStatus()));
-                    }
-                    // Comet support
-                    SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
-                            socketWrapper.getSocket().getPoller().getSelector());
-                    if (key != null) {
-                        NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();
-                        if (attach != null)  {
-                            attach.setComet(comet);
-                            if (comet) {
-                                Integer comettimeout = (Integer) request.getAttribute("org.apache.tomcat.comet.timeout");
-                                if (comettimeout != null) attach.setTimeout(comettimeout.longValue());
-                            }
-                        }
-                    }
-                } catch (InterruptedIOException e) {
-                    error = true;
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    log.error(sm.getString("http11processor.request.process"), t);
-                    // 500 - Internal Server Error
-                    response.setStatus(500);
-                    adapter.log(request, response, 0);
-                    error = true;
-                }
-            }
 
-            // Finish the handling of the request
-            if (!comet && !isAsync()) {
-                // If we know we are closing the connection, don't drain input.
-                // This way uploading a 100GB file doesn't tie up the thread 
-                // if the servlet has rejected it.
-                if(error)
-                    inputBuffer.setSwallowInput(false);
-                endRequest();
-            }
-
-            // If there was an error, make sure the request is counted as
-            // and error, and update the statistics counter
-            if (error) {
-                response.setStatus(500);
-            }
-            request.updateCounters();
-
-            if (!comet && !isAsync()) {
-                // Next request
-                inputBuffer.nextRequest();
-                outputBuffer.nextRequest();
-            }
-            
-            // Do sendfile as needed: add socket to sendfile and end
-            if (sendfileData != null && !error) {
-                ((KeyAttachment) socketWrapper).setSendfileData(sendfileData);
-                sendfileData.keepAlive = keepAlive;
-                SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
-                        socketWrapper.getSocket().getPoller().getSelector());
-                //do the first write on this thread, might as well
-                openSocket = socketWrapper.getSocket().getPoller().processSendfile(key,
-                        (KeyAttachment) socketWrapper, true, true);
-                break;
+    @Override
+    protected boolean handleIncompleteRequestLineRead() {
+        // Haven't finished reading the request so keep the socket
+        // open
+        openSocket = true;
+        // Check to see if we have read any of the request line yet
+        if (inputBuffer.getParsingRequestLinePhase() < 2) {
+            if (socket.getLastAccess() > -1 || keptAlive) {
+                // Haven't read the request line and have previously processed a
+                // request. Must be keep-alive. Make sure poller uses keepAlive.
+                socket.setTimeout(endpoint.getKeepAliveTimeout());
             }
+        } else {
+            // Started to read request line. Need to keep processor
+            // associated with socket
+            readComplete = false;
+            // Make sure poller uses soTimeout from here onwards
+            socket.setTimeout(endpoint.getSoTimeout());
+        }
+        if (endpoint.isPaused()) {
+            // 503 - Service unavailable
+            response.setStatus(503);
+            adapter.log(request, response, 0);
+            error = true;
+        } else {
+            return true;
+        }
+        return false;
+    }
 
 
-            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
-
-        }//while
+    @Override
+    protected void setSocketTimeout(int timeout) throws IOException {
+        socket.getSocket().getIOChannel().socket().setSoTimeout(timeout);
+    }
 
-        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
-        if (error || endpoint.isPaused()) {
-            return SocketState.CLOSED;
-        } else if (comet || isAsync()) {
-            return SocketState.LONG;
-        } else {
-            return (openSocket) ? (readComplete?SocketState.OPEN:SocketState.LONG) : SocketState.CLOSED;
+    
+    @Override
+    protected void setCometTimeouts(SocketWrapper<NioChannel> socketWrapper) {
+        // Comet support
+        SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
+                socketWrapper.getSocket().getPoller().getSelector());
+        if (key != null) {
+            NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment();
+            if (attach != null)  {
+                attach.setComet(comet);
+                if (comet) {
+                    Integer comettimeout = (Integer) request.getAttribute("org.apache.tomcat.comet.timeout");
+                    if (comettimeout != null) attach.setTimeout(comettimeout.longValue());
+                }
+            }
         }
-
     }
 
 
     @Override
-    protected boolean disableKeepAlive() {
+    protected boolean breakKeepAliveLoop(
+            SocketWrapper<NioChannel> socketWrapper) {
+        // Do sendfile as needed: add socket to sendfile and end
+        if (sendfileData != null && !error) {
+            ((KeyAttachment) socketWrapper).setSendfileData(sendfileData);
+            sendfileData.keepAlive = keepAlive;
+            SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
+                    socketWrapper.getSocket().getPoller().getSelector());
+            //do the first write on this thread, might as well
+            openSocket = socketWrapper.getSocket().getPoller().processSendfile(key,
+                    (KeyAttachment) socketWrapper, true, true);
+            return true;
+        }
         return false;
     }
 
@@ -654,6 +532,11 @@ public class Http11NioProcessor extends 
     }
 
     @Override
+    protected void setSocketWrapper(SocketWrapper<NioChannel> socketWrapper) {
+        this.socket = socketWrapper;
+    }
+
+    @Override
     protected AbstractInputBuffer<NioChannel> getInputBuffer() {
         return inputBuffer;
     }

Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/Http11Processor.java Thu Sep  8 09:07:34 2011
@@ -18,16 +18,13 @@ package org.apache.coyote.http11;
 
 import java.io.EOFException;
 import java.io.IOException;
-import java.io.InterruptedIOException;
 import java.net.InetAddress;
 import java.net.Socket;
 
 import org.apache.coyote.ActionCode;
-import org.apache.coyote.RequestInfo;
 import org.apache.coyote.http11.filters.BufferedInputFilter;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.ExceptionUtils;
 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
 import org.apache.tomcat.util.net.JIoEndpoint;
 import org.apache.tomcat.util.net.SSLSupport;
@@ -121,254 +118,98 @@ public class Http11Processor extends Abs
     }
 
 
-    /**
-     * Process pipelined HTTP requests using the specified input and output
-     * streams.
-     *
-     * @param socketWrapper Socket from which the HTTP requests will be read
-     *               and the HTTP responses will be written.
-     *  
-     * @throws IOException error during an I/O operation
-     */
     @Override
-    public SocketState process(SocketWrapper<Socket> socketWrapper)
-        throws IOException {
-        RequestInfo rp = request.getRequestProcessor();
-        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
-
-        // Setting up the I/O
-        this.socket = socketWrapper;
-        inputBuffer.init(socketWrapper, endpoint);
-        outputBuffer.init(socketWrapper, endpoint);
-
-        // Error flag
-        error = false;
-        keepAlive = true;
-        comet = false;
-
-        int soTimeout = endpoint.getSoTimeout();
-
-        if (disableKeepAlive()) {
-            socketWrapper.setKeepAliveLeft(0);
+    protected boolean disableKeepAlive() {
+        int threadRatio = -1;   
+        // These may return zero or negative values     
+        // Only calculate a thread ratio when both are >0 to ensure we get a    
+        // sensible result      
+        if (endpoint.getCurrentThreadsBusy() >0 &&      
+                endpoint.getMaxThreads() >0) {      
+            threadRatio = (endpoint.getCurrentThreadsBusy() * 100)      
+                    / endpoint.getMaxThreads();     
+        }   
+        // Disable keep-alive if we are running low on threads      
+        if (threadRatio > getDisableKeepAlivePercentage()) {     
+            return true;
         }
+        
+        return false;
+    }
 
-        boolean keptAlive = socketWrapper.isKeptAlive();
-
-        while (!error && keepAlive && !endpoint.isPaused()) {
 
-            // Parsing the request header
-            try {
-                int standardTimeout = 0;
-                if (keptAlive) {
-                    if (keepAliveTimeout > 0) {
-                        standardTimeout = keepAliveTimeout;
-                    } else if (soTimeout > 0) {
-                        standardTimeout = soTimeout;
-                    }
-                }
-                /*
-                 * When there is no data in the buffer and this is not the first
-                 * request on this connection and timeouts are being used the
-                 * first read for this request may need a different timeout to
-                 * take account of time spent waiting for a processing thread.
-                 * 
-                 * This is a little hacky but better than exposing the socket
-                 * and the timeout info to the InputBuffer
-                 */
-                if (inputBuffer.lastValid == 0 &&
-                        socketWrapper.getLastAccess() > -1 &&
-                        standardTimeout > 0) {
-
-                    long queueTime = System.currentTimeMillis() -
-                            socketWrapper.getLastAccess();
-                    int firstReadTimeout;
-                    if (queueTime >= standardTimeout) {
-                        // Queued for longer than timeout but there might be
-                        // data so use shortest possible timeout
-                        firstReadTimeout = 1;
-                    } else {
-                        // Cast is safe since queueTime must be less than
-                        // standardTimeout which is an int
-                        firstReadTimeout = standardTimeout - (int) queueTime;
-                    }
-                    socket.getSocket().setSoTimeout(firstReadTimeout);
-                    if (!inputBuffer.fill()) {
-                        throw new EOFException(sm.getString("iib.eof.error"));
-                    }
-                }
-                if (standardTimeout > 0) {
-                    socket.getSocket().setSoTimeout(standardTimeout);
-                }
+    @Override
+    protected void setRequestLineReadTimeout() throws IOException {
+        
+        /*
+         * When there is no data in the buffer and this is not the first
+         * request on this connection and timeouts are being used the
+         * first read for this request may need a different timeout to
+         * take account of time spent waiting for a processing thread.
+         * 
+         * This is a little hacky but better than exposing the socket
+         * and the timeout info to the InputBuffer
+         */
+        if (inputBuffer.lastValid == 0 && socket.getLastAccess() > -1) {
+            int firstReadTimeout;
+            if (keepAliveTimeout == -1) {
+                firstReadTimeout = 0;
+            } else {
+                long queueTime =
+                    System.currentTimeMillis() - socket.getLastAccess();
 
-                inputBuffer.parseRequestLine(false);
-                if (endpoint.isPaused()) {
-                    // 503 - Service unavailable
-                    response.setStatus(503);
-                    adapter.log(request, response, 0);
-                    error = true;
+                if (queueTime >= keepAliveTimeout) {
+                    // Queued for longer than timeout but there might be
+                    // data so use shortest possible timeout
+                    firstReadTimeout = 1;
                 } else {
-                    request.setStartTime(System.currentTimeMillis());
-                    keptAlive = true;
-                    if (disableUploadTimeout) {
-                        socket.getSocket().setSoTimeout(soTimeout);
-                    } else {
-                        socket.getSocket().setSoTimeout(connectionUploadTimeout);
-                    }
-                    inputBuffer.parseHeaders();
-                }
-            } catch (IOException e) {
-                error = true;
-                break;
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("http11processor.header.parse"), t);
-                }
-                // 400 - Bad Request
-                response.setStatus(400);
-                adapter.log(request, response, 0);
-                error = true;
-            }
-
-            if (!error) {
-                // Setting up filters, and parse some request headers
-                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
-                try {
-                    prepareRequest();
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    if (log.isDebugEnabled()) {
-                        log.debug(sm.getString("http11processor.request.prepare"), t);
-                    }
-                    // 400 - Internal Server Error
-                    response.setStatus(400);
-                    adapter.log(request, response, 0);
-                    error = true;
+                    // Cast is safe since queueTime must be less than
+                    // keepAliveTimeout which is an int
+                    firstReadTimeout = keepAliveTimeout - (int) queueTime;
                 }
             }
+            socket.getSocket().setSoTimeout(firstReadTimeout);
+            if (!inputBuffer.fill()) {
+                throw new EOFException(sm.getString("iib.eof.error"));
+            }
+            // Once the first byte has been read, the standard timeout should be
+            // used so restore it here.
+            socket.getSocket().setSoTimeout(endpoint.getSoTimeout());
+        }
+    }
 
-            if (maxKeepAliveRequests == 1) {
-                keepAlive = false;
-            } else if (maxKeepAliveRequests > 0 &&
-                    socketWrapper.decrementKeepAlive() <= 0) {
-                keepAlive = false;
-            }
-
-            // Process the request in the adapter
-            if (!error) {
-                try {
-                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
-                    adapter.service(request, response);
-                    // Handle when the response was committed before a serious
-                    // error occurred.  Throwing a ServletException should both
-                    // set the status to 500 and set the errorException.
-                    // If we fail here, then the response is likely already
-                    // committed, so we can't try and set headers.
-                    if(keepAlive && !error) { // Avoid checking twice.
-                        error = response.getErrorException() != null ||
-                                (!isAsync() &&
-                                statusDropsConnection(response.getStatus()));
-                    }
-
-                } catch (InterruptedIOException e) {
-                    error = true;
-                } catch (Throwable t) {
-                    ExceptionUtils.handleThrowable(t);
-                    log.error(sm.getString("http11processor.request.process"), t);
-                    // 500 - Internal Server Error
-                    response.setStatus(500);
-                    adapter.log(request, response, 0);
-                    error = true;
-                }
-            }
 
-            // Finish the handling of the request
-            try {
-                rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
-                // If we know we are closing the connection, don't drain input.
-                // This way uploading a 100GB file doesn't tie up the thread 
-                // if the servlet has rejected it.
-                
-                if(error && !isAsync())
-                    inputBuffer.setSwallowInput(false);
-                if (!isAsync())
-                    endRequest();
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                log.error(sm.getString("http11processor.request.finish"), t);
-                // 500 - Internal Server Error
-                response.setStatus(500);
-                adapter.log(request, response, 0);
-                error = true;
-            }
-            try {
-                rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
-            } catch (Throwable t) {
-                ExceptionUtils.handleThrowable(t);
-                log.error(sm.getString("http11processor.response.finish"), t);
-                error = true;
-            }
+    @Override
+    protected boolean handleIncompleteRequestLineRead() {
+        // Not used with BIO since it uses blocking reads
+        return false;
+    }
 
-            // If there was an error, make sure the request is counted as
-            // and error, and update the statistics counter
-            if (error) {
-                response.setStatus(500);
-            }
-            request.updateCounters();
-
-            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
-
-            // Don't reset the param - we'll see it as ended. Next request
-            // will reset it
-            // thrA.setParam(null);
-            // Next request
-            if (!isAsync() || error) {
-                inputBuffer.nextRequest();
-                outputBuffer.nextRequest();
-            }
-
-            // If we don't have a pipe-lined request allow this thread to be
-            // used by another connection
-            if (isAsync() || error || inputBuffer.lastValid == 0) {
-                break;
-            }
-        }
 
-        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
-        if (error || endpoint.isPaused()) {
-            return SocketState.CLOSED;
-        } else if (isAsync()) {
-            return SocketState.LONG;
-        } else {
-            if (!keepAlive) {
-                return SocketState.CLOSED;
-            } else {
-                return SocketState.OPEN;
-            }
-        } 
+    @Override
+    protected void setSocketTimeout(int timeout) throws IOException {
+        socket.getSocket().setSoTimeout(timeout);
     }
     
     
     @Override
-    protected boolean disableKeepAlive() {
-        int threadRatio = -1;   
-        // These may return zero or negative values     
-        // Only calculate a thread ratio when both are >0 to ensure we get a    
-        // sensible result      
-        if (endpoint.getCurrentThreadsBusy() >0 &&      
-                endpoint.getMaxThreads() >0) {      
-            threadRatio = (endpoint.getCurrentThreadsBusy() * 100)      
-                    / endpoint.getMaxThreads();     
-        }   
-        // Disable keep-alive if we are running low on threads      
-        if (threadRatio > getDisableKeepAlivePercentage()) {     
+    protected void setCometTimeouts(SocketWrapper<Socket> socketWrapper) {
+        // NO-OP for BIO
+    }
+
+
+    @Override
+    protected boolean breakKeepAliveLoop(SocketWrapper<Socket> socketWrapper) {
+        openSocket = keepAlive;
+        // If we don't have a pipe-lined request allow this thread to be
+        // used by another connection
+        if (inputBuffer.lastValid == 0) {
             return true;
         }
-        
         return false;
     }
 
-
+    
     @Override
     protected void resetTimeouts() {
         // NOOP for BIO
@@ -556,6 +397,11 @@ public class Http11Processor extends Abs
     }
 
     @Override
+    protected void setSocketWrapper(SocketWrapper<Socket> socketWrapper) {
+        this.socket = socketWrapper;
+    }
+
+    @Override
     protected AbstractInputBuffer<Socket> getInputBuffer() {
         return inputBuffer;
     }

Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AbstractEndpoint.java Thu Sep  8 09:07:34 2011
@@ -170,12 +170,18 @@ public abstract class AbstractEndpoint {
     private BindState bindState = BindState.UNBOUND;
 
     /**
-     * Keepalive timeout, if lesser or equal to 0 then soTimeout will be used.
+     * Keepalive timeout, if not set the soTimeout is used.
      */
-    private int keepAliveTimeout = -1;
-    public int getKeepAliveTimeout() { return keepAliveTimeout;}
+    private Integer keepAliveTimeout = null;
+    public int getKeepAliveTimeout() {
+        if (keepAliveTimeout == null) {
+            return getSoTimeout();
+        } else {
+            return keepAliveTimeout.intValue();
+        }
+    }
     public void setKeepAliveTimeout(int keepAliveTimeout) {
-        this.keepAliveTimeout = keepAliveTimeout;
+        this.keepAliveTimeout = Integer.valueOf(keepAliveTimeout);
     }
 
 
@@ -559,9 +565,12 @@ public abstract class AbstractEndpoint {
 
     protected abstract Log getLog();
     // Flags to indicate optional feature support
+    // Some of these are always hard-coded, some are hard-coded to false (i.e.
+    // the endpoint does not support them) and some are configurable.
     public abstract boolean getUseSendfile();
     public abstract boolean getUseComet();
     public abstract boolean getUseCometTimeout();
+    public abstract boolean getUsePolling();
     
     protected LimitLatch initializeConnectionLatch() {
         if (connectionLimitLatch==null) {

Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Thu Sep  8 09:07:34 2011
@@ -160,6 +160,8 @@ public class AprEndpoint extends Abstrac
     public boolean getUseComet() { return useComet; }
     @Override
     public boolean getUseCometTimeout() { return false; } // Not supported
+    @Override
+    public boolean getUsePolling() { return true; } // Always supported
 
 
     /**
@@ -750,8 +752,7 @@ public class AprEndpoint extends Abstrac
                 Socket.optSet(socket, Socket.APR_SO_LINGER, socketProperties.getSoLingerTime());
             if (socketProperties.getTcpNoDelay())
                 Socket.optSet(socket, Socket.APR_TCP_NODELAY, (socketProperties.getTcpNoDelay() ? 1 : 0));
-            if (socketProperties.getSoTimeout() > 0)
-                Socket.timeoutSet(socket, socketProperties.getSoTimeout() * 1000);
+            Socket.timeoutSet(socket, socketProperties.getSoTimeout() * 1000);
 
             // 2: SSL handshake
             step = 2;
@@ -1128,7 +1129,7 @@ public class AprEndpoint extends Abstrac
             int size = getMaxConnections() / pollerThreadCount;
             int keepAliveTimeout = getKeepAliveTimeout();
             int socketTimeout = socketProperties.getSoTimeout();
-            if (keepAliveTimeout > 0 && !comet) {
+            if (keepAliveTimeout != socketTimeout && !comet) {
                 separateKeepAlive = true;
             }
             connectionPollset = allocatePoller(size, pool, socketTimeout);

Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/JIoEndpoint.java Thu Sep  8 09:07:34 2011
@@ -108,6 +108,8 @@ public class JIoEndpoint extends Abstrac
     public boolean getUseCometTimeout() { return false; } // Not supported
     @Override
     public boolean getDeferAccept() { return false; } // Not supported
+    @Override
+    public boolean getUsePolling() { return false; } // Not supported
 
 
     // ------------------------------------------------ Handler Inner Interface

Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Thu Sep  8 09:07:34 2011
@@ -332,6 +332,8 @@ public class NioEndpoint extends Abstrac
     public boolean getUseComet() { return useComet; }
     @Override
     public boolean getUseCometTimeout() { return getUseComet(); }
+    @Override
+    public boolean getUsePolling() { return true; } // Always supported
 
 
     /**
@@ -1338,7 +1340,7 @@ public class NioEndpoint extends Abstrac
                               (ka.interestOps()&SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
                         //only timeout sockets that we are waiting for a read from
                         long delta = now - ka.getLastAccess();
-                        long timeout = (ka.getTimeout()==-1)?((long) socketProperties.getSoTimeout()):(ka.getTimeout());
+                        long timeout = ka.getTimeout();
                         boolean isTimedout = timeout > 0 && delta > timeout;
                         if ( close ) {
                             key.interestOps(0); 
@@ -1348,7 +1350,7 @@ public class NioEndpoint extends Abstrac
                             key.interestOps(0); 
                             ka.interestOps(0); //avoid duplicate timeout calls
                             cancelledKey(key, SocketStatus.TIMEOUT,true);
-                        } else {
+                        } else if (timeout > -1) {
                             long nextTime = now+(timeout-delta);
                             nextExpiration = (nextTime < nextExpiration)?nextTime:nextExpiration;
                         }

Modified: tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml?rev=1166576&r1=1166575&r2=1166576&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/config/http.xml Thu Sep  8 09:07:34 2011
@@ -317,7 +317,10 @@
     <attribute name="connectionTimeout" required="false">
       <p>The number of milliseconds this <strong>Connector</strong> will wait,
       after accepting a connection, for the request URI line to be
-      presented.  The default value is 60000 (i.e. 60 seconds).</p>
+      presented. Use a value of -1 to indicate no (i.e. infinite) timeout.
+      The default value is 60000 (i.e. 60 seconds) but note that the standard
+      server.xml that ships with Tomcat sets this to 20000 (i.e. 20 seconds).
+      </p>
     </attribute>
     
     <attribute name="connectionUploadTimeout" required="false">
@@ -347,7 +350,8 @@
       <p>The number of milliseconds this <strong>Connector</strong> will wait
       for another HTTP request before closing the connection. The default value
       is to use the value that has been set for the
-      <strong>connectionTimeout</strong> attribute.</p>
+      <strong>connectionTimeout</strong> attribute.
+      Use a value of -1 to indicate no (i.e. infinite) timeout.</p>
     </attribute>
 
     <attribute name="maxConnections" required="false">



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org