Author: markt Date: Fri Jun 13 20:21:32 2014 New Revision: 1602510 URL: http://svn.apache.org/r1602510 Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56518 Do not attempt an NIO write if a thread has been interrupted as it can lead to a connection limit leak
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProcessor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/Adapter.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/LocalStrings.properties tomcat/tc7.0.x/trunk/java/org/apache/coyote/Processor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpProcessor.java 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/upgrade/AbstractProcessor.java tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.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/NioChannel.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SocketStatus.java tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1602198 Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java Fri Jun 13 20:21:32 2014 @@ -469,6 +469,34 @@ public class CoyoteAdapter implements Ad @Override + public void errorDispatch(org.apache.coyote.Request req, + org.apache.coyote.Response res) { + Request request = (Request) req.getNote(ADAPTER_NOTES); + Response response = (Response) res.getNote(ADAPTER_NOTES); + + if (request != null && request.getMappingData().context != null) { + ((Context) request.getMappingData().context).logAccess( + request, response, + System.currentTimeMillis() - req.getStartTime(), + false); + } else { + log(req, res, System.currentTimeMillis() - req.getStartTime()); + } + + if (request != null) { + request.recycle(); + } + + if (response != null) { + response.recycle(); + } + + res.recycle(); + res.recycle(); + } + + + @Override public void log(org.apache.coyote.Request req, org.apache.coyote.Response res, long time) { Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProcessor.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/AbstractProcessor.java Fri Jun 13 20:21:32 2014 @@ -69,8 +69,20 @@ public abstract class AbstractProcessor< * Update the current error state to the new error state if the new error * state is more severe than the current error state. */ - protected void setErrorState(ErrorState errorState) { + protected void setErrorState(ErrorState errorState, Throwable t) { + boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed(); this.errorState = this.errorState.getMostSevere(errorState); + if (blockIo && !ContainerThreadMarker.isContainerThread()) { + // The error occurred on a non-container thread which means not all + // of the necessary clean-up will have been completed. Dispatch to + // a container thread to do the clean-up. Need to do it this way to + // ensure that all the necessary clean-up is performed. + if (response.getStatus() < 400) { + response.setStatus(500); + } + getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), t); + getEndpoint().processSocketAsync(socketWrapper, SocketStatus.CLOSE_NOW); + } } @@ -157,6 +169,11 @@ public abstract class AbstractProcessor< } @Override + public void errorDispatch() { + getAdapter().errorDispatch(request, response); + } + + @Override public abstract boolean isComet(); @Override Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/Adapter.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/Adapter.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/Adapter.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/Adapter.java Fri Jun 13 20:21:32 2014 @@ -51,6 +51,8 @@ public interface Adapter { public boolean asyncDispatch(Request req,Response res, SocketStatus status) throws Exception; + public void errorDispatch(Request request, Response response); + public void log(Request req, Response res, long time); /** Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/LocalStrings.properties?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/LocalStrings.properties (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/LocalStrings.properties Fri Jun 13 20:21:32 2014 @@ -16,6 +16,8 @@ abstractConnectionHandler.error=Error re abstractConnectionHandler.ioexception.debug=IOExceptions are normal, ignored abstractConnectionHandler.socketexception.debug=SocketExceptions are normal, ignored +abstractProcessor.nonContainerThreadError=An error occurred in processing while on a non-container thread. The connection will be closed immediately + abstractProtocolHandler.getAttribute=Get attribute [{0}] with value [{1}] abstractProtocolHandler.setAttribute=Set attribute [{0}] with value [{1}] abstractProtocolHandler.init=Initializing ProtocolHandler [{0}] Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/Processor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/Processor.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/Processor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/Processor.java Fri Jun 13 20:21:32 2014 @@ -54,6 +54,8 @@ public interface Processor<S> { HttpUpgradeHandler getHttpUpgradeHandler(); SocketState upgradeDispatch(SocketStatus status) throws IOException; + void errorDispatch(); + boolean isComet(); boolean isAsync(); boolean isUpgrade(); Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java Fri Jun 13 20:21:32 2014 @@ -319,13 +319,13 @@ public abstract class AbstractAjpProcess try { prepareResponse(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } try { flush(false); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } break; } @@ -335,7 +335,7 @@ public abstract class AbstractAjpProcess try { prepareResponse(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); return; } } @@ -343,7 +343,7 @@ public abstract class AbstractAjpProcess try { flush(true); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } break; } @@ -354,7 +354,7 @@ public abstract class AbstractAjpProcess case DISABLE_SWALLOW_INPUT: { // TODO: Do not swallow request input but // make sure we are closing the connection - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); break; } case CLOSE: { @@ -365,7 +365,7 @@ public abstract class AbstractAjpProcess try { finish(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } break; } @@ -494,7 +494,7 @@ public abstract class AbstractAjpProcess case CLOSE_NOW: { // Prevent further writes to the response swallowResponse = true; - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); break; } } @@ -508,14 +508,14 @@ public abstract class AbstractAjpProcess try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); if(!getAdapter().asyncDispatch(request, response, status)) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); } resetTimeouts(); } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); getLog().error(sm.getString("http11processor.request.process"), t); } finally { if (getErrorState().isError()) { @@ -761,7 +761,7 @@ public abstract class AbstractAjpProcess long cl = vMB.getLong(); if (contentLengthSet) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); } else { contentLengthSet = true; // Set the content-length header for the request @@ -879,7 +879,7 @@ public abstract class AbstractAjpProcess secret = true; if (!tmpMB.equals(requiredSecret)) { response.setStatus(403); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); } } break; @@ -895,7 +895,7 @@ public abstract class AbstractAjpProcess // Check if secret was submitted if required if ((requiredSecret != null) && !secret) { response.setStatus(403); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); } // Check for a full URI (including protocol://host:port/) @@ -946,7 +946,7 @@ public abstract class AbstractAjpProcess request.serverName().duplicate(request.localName()); } catch (IOException e) { response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, e); } return; } @@ -996,7 +996,7 @@ public abstract class AbstractAjpProcess // Invalid character // 400 - Bad request response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); break; } port = port + (charValue * mult); @@ -1112,7 +1112,7 @@ public abstract class AbstractAjpProcess try { prepareResponse(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); return; } } @@ -1196,7 +1196,7 @@ public abstract class AbstractAjpProcess try { prepareResponse(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } } Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpAprProcessor.java Fri Jun 13 20:21:32 2014 @@ -132,7 +132,7 @@ public class AjpAprProcessor extends Abs cping = true; if (Socket.send(socketRef, pongMessageArray, 0, pongMessageArray.length) < 0) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); } continue; } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) { @@ -141,20 +141,20 @@ public class AjpAprProcessor extends Abs if (log.isDebugEnabled()) { log.debug("Unexpected message: " + type); } - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); break; } keptAlive = true; request.setStartTime(System.currentTimeMillis()); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.header.error"), t); // 400 - Bad Request response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } @@ -168,7 +168,7 @@ public class AjpAprProcessor extends Abs log.debug(sm.getString("ajpprocessor.request.prepare"), t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } @@ -176,7 +176,7 @@ public class AjpAprProcessor extends Abs if (!getErrorState().isError() && !cping && endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); getAdapter().log(request, response, 0); } cping = false; @@ -187,13 +187,13 @@ public class AjpAprProcessor extends Abs rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("ajpprocessor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } @@ -208,7 +208,7 @@ public class AjpAprProcessor extends Abs finish(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); } } Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java Fri Jun 13 20:21:32 2014 @@ -118,7 +118,7 @@ public class AjpNioProcessor extends Abs try { output(pongMessageArray, 0, pongMessageArray.length); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); } recycle(false); continue; @@ -128,20 +128,20 @@ public class AjpNioProcessor extends Abs if (log.isDebugEnabled()) { log.debug("Unexpected message: " + type); } - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); recycle(true); break; } request.setStartTime(System.currentTimeMillis()); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.header.error"), t); // 400 - Bad Request response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } @@ -155,7 +155,7 @@ public class AjpNioProcessor extends Abs log.debug(sm.getString("ajpprocessor.request.prepare"), t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } @@ -163,7 +163,7 @@ public class AjpNioProcessor extends Abs if (!getErrorState().isError() && !cping && endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); getAdapter().log(request, response, 0); } cping = false; @@ -174,13 +174,13 @@ public class AjpNioProcessor extends Abs rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("ajpprocessor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } @@ -195,7 +195,7 @@ public class AjpNioProcessor extends Abs finish(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); } } Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpProcessor.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/ajp/AjpProcessor.java Fri Jun 13 20:21:32 2014 @@ -135,7 +135,7 @@ public class AjpProcessor extends Abstra try { output.write(pongMessageArray); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } continue; } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) { @@ -144,19 +144,19 @@ public class AjpProcessor extends Abstra if (log.isDebugEnabled()) { log.debug("Unexpected message: " + type); } - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); break; } request.setStartTime(System.currentTimeMillis()); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.debug(sm.getString("ajpprocessor.header.error"), t); // 400 - Bad Request response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } @@ -170,7 +170,7 @@ public class AjpProcessor extends Abstra log.debug(sm.getString("ajpprocessor.request.prepare"), t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } @@ -178,7 +178,7 @@ public class AjpProcessor extends Abstra if (!getErrorState().isError() && !cping && endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); getAdapter().log(request, response, 0); } cping = false; @@ -189,13 +189,13 @@ public class AjpProcessor extends Abstra rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); adapter.service(request, response); } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("ajpprocessor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } @@ -210,7 +210,7 @@ public class AjpProcessor extends Abstra finish(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); } } 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=1602510&r1=1602509&r2=1602510&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 Fri Jun 13 20:21:32 2014 @@ -734,7 +734,7 @@ public abstract class AbstractHttp11Proc // Unsupported transfer encoding // 501 - Unimplemented response.setStatus(501); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); if (getLog().isDebugEnabled()) { getLog().debug(sm.getString("http11processor.request.prepare") + " Unsupported transfer encoding [" + encodingName + "]"); @@ -759,7 +759,7 @@ public abstract class AbstractHttp11Proc try { getOutputBuffer().endRequest(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } break; } @@ -774,7 +774,7 @@ public abstract class AbstractHttp11Proc prepareResponse(); getOutputBuffer().commit(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } break; } @@ -790,7 +790,7 @@ public abstract class AbstractHttp11Proc try { getOutputBuffer().sendAck(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } break; } @@ -798,7 +798,7 @@ public abstract class AbstractHttp11Proc try { getOutputBuffer().flush(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); response.setErrorException(e); } break; @@ -810,7 +810,7 @@ public abstract class AbstractHttp11Proc case DISABLE_SWALLOW_INPUT: { // Do not swallow request input and make sure we are closing the // connection - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); getInputBuffer().setSwallowInput(false); break; } @@ -894,7 +894,7 @@ public abstract class AbstractHttp11Proc case CLOSE_NOW: { // Block further output getOutputBuffer().finished = true; - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); break; } default: { @@ -989,7 +989,7 @@ public abstract class AbstractHttp11Proc if (endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); } else { // Make sure that connectors that are non-blocking during // header processing (NIO) only set the start time the first @@ -1017,7 +1017,7 @@ public abstract class AbstractHttp11Proc getLog().debug( sm.getString("http11processor.header.parse"), e); } - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); @@ -1039,7 +1039,7 @@ public abstract class AbstractHttp11Proc } // 400 - Bad Request response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } @@ -1056,7 +1056,7 @@ public abstract class AbstractHttp11Proc } // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } @@ -1082,20 +1082,20 @@ public abstract class AbstractHttp11Proc response.getErrorException() != null || (!isAsync() && statusDropsConnection(response.getStatus())))) { - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); } setCometTimeouts(socketWrapper); } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (HeadersTooLargeException e) { // The response should not have been committed but check it // anyway to be safe if (response.isCommitted()) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } else { response.reset(); response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, e); response.setHeader("Connection", "close"); // TODO: Remove } } catch (Throwable t) { @@ -1104,7 +1104,7 @@ public abstract class AbstractHttp11Proc "http11processor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } @@ -1224,7 +1224,7 @@ public abstract class AbstractHttp11Proc http11 = false; // Send 505; Unsupported HTTP version response.setStatus(505); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); if (getLog().isDebugEnabled()) { getLog().debug(sm.getString("http11processor.request.prepare")+ " Unsupported HTTP version \""+protocolMB+"\""); @@ -1262,7 +1262,7 @@ public abstract class AbstractHttp11Proc expectation = true; } else { response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); } } @@ -1356,7 +1356,7 @@ public abstract class AbstractHttp11Proc if (http11 && (valueMB == null)) { // 400 - Bad request response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); if (getLog().isDebugEnabled()) { getLog().debug(sm.getString("http11processor.request.prepare")+ " host header missing"); @@ -1636,7 +1636,7 @@ public abstract class AbstractHttp11Proc // Invalid character // 400 - Bad request response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); break; } port = port + (charValue * mult); @@ -1655,14 +1655,14 @@ public abstract class AbstractHttp11Proc try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); if (!getAdapter().asyncDispatch(request, response, status)) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); } resetTimeouts(); } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); getLog().error(sm.getString("http11processor.request.process"), t); } finally { if (getErrorState().isError()) { @@ -1756,14 +1756,14 @@ public abstract class AbstractHttp11Proc try { getInputBuffer().endRequest(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // 500 - Internal Server Error // Can't add a 500 to the access log since that has already been // written in the Adapter.service method. response.setStatus(500); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); getLog().error(sm.getString("http11processor.request.finish"), t); } } @@ -1771,10 +1771,10 @@ public abstract class AbstractHttp11Proc try { getOutputBuffer().endRequest(); } catch (IOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); getLog().error(sm.getString("http11processor.response.finish"), t); } } 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=1602510&r1=1602509&r2=1602510&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 Fri Jun 13 20:21:32 2014 @@ -126,15 +126,15 @@ public class Http11AprProcessor extends try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); if (!getAdapter().event(request, response, status)) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); } } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); getAdapter().log(request, response, 0); log.error(sm.getString("http11processor.request.process"), t); } @@ -191,7 +191,7 @@ public class Http11AprProcessor extends if (endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); getAdapter().log(request, response, 0); } else { return true; @@ -228,7 +228,7 @@ public class Http11AprProcessor extends log.debug(sm.getString( "http11processor.sendfile.error")); } - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); } else { // The sendfile Poller will add the socket to the main // Poller once sendfile processing is complete 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=1602510&r1=1602509&r2=1602510&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 Fri Jun 13 20:21:32 2014 @@ -116,7 +116,7 @@ public class Http11NioProcessor extends try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); if (!getAdapter().event(request, response, status)) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); } if (!getErrorState().isError()) { if (attach != null) { @@ -139,12 +139,12 @@ public class Http11NioProcessor extends } } } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, e); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); // 500 - Internal Server Error response.setStatus(500); - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, t); log.error(sm.getString("http11processor.request.process"), t); getAdapter().log(request, response, 0); } @@ -233,7 +233,7 @@ public class Http11NioProcessor extends if (endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); - setErrorState(ErrorState.CLOSE_CLEAN); + setErrorState(ErrorState.CLOSE_CLEAN, null); getAdapter().log(request, response, 0); } else { return true; @@ -287,7 +287,7 @@ public class Http11NioProcessor extends if (log.isDebugEnabled()) { log.debug(sm.getString("http11processor.sendfile.error")); } - setErrorState(ErrorState.CLOSE_NOW); + setErrorState(ErrorState.CLOSE_NOW, null); } return true; } Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java Fri Jun 13 20:21:32 2014 @@ -161,6 +161,11 @@ public abstract class AbstractProcessor< } @Override + public void errorDispatch() { + // NO-OP + } + + @Override public final SocketState asyncPostProcess() { return null; } Modified: tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/upgrade/UpgradeProcessor.java Fri Jun 13 20:21:32 2014 @@ -135,6 +135,11 @@ public abstract class UpgradeProcessor<S } @Override + public void errorDispatch() { + // NO-OP + } + + @Override public final SocketState asyncPostProcess() { return null; } 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=1602510&r1=1602509&r2=1602510&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 Fri Jun 13 20:21:32 2014 @@ -623,7 +623,7 @@ public abstract class AbstractEndpoint<S // ---------------------------------------------- Request processing methods - protected abstract void processSocketAsync(SocketWrapper<S> socketWrapper, + public abstract void processSocketAsync(SocketWrapper<S> socketWrapper, SocketStatus socketStatus); Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/NioChannel.java Fri Jun 13 20:21:32 2014 @@ -27,6 +27,7 @@ import java.nio.channels.SocketChannel; import org.apache.tomcat.util.net.NioEndpoint.Poller; import org.apache.tomcat.util.net.SecureNioChannel.ApplicationBufferHandler; +import org.apache.tomcat.util.res.StringManager; /** * @@ -39,6 +40,9 @@ import org.apache.tomcat.util.net.Secure */ public class NioChannel implements ByteChannel{ + protected static final StringManager sm = + StringManager.getManager("org.apache.tomcat.util.net.res"); + protected static ByteBuffer emptyBuf = ByteBuffer.allocate(0); protected SocketChannel sc = null; @@ -120,6 +124,7 @@ public class NioChannel implements ByteC */ @Override public int write(ByteBuffer src) throws IOException { + checkInterruptStatus(); return sc.write(src); } @@ -224,4 +229,19 @@ public class NioChannel implements ByteC } + /** + * This method should be used to check the interrupt status before + * attempting a write. + * + * If a thread has been interrupted and the interrupt has not been cleared + * then an attempt to write to the socket will fail. When this happens the + * socket is removed from the poller without the socket being selected. This + * results in a connection limit leak for NIO as the endpoint expects the + * socket to be selected even in error conditions. + */ + protected void checkInterruptStatus() throws IOException { + if (Thread.interrupted()) { + throw new IOException(sm.getString("channel.nio.interrupted")); + } + } } 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=1602510&r1=1602509&r2=1602510&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 Fri Jun 13 20:21:32 2014 @@ -723,7 +723,7 @@ public class NioEndpoint extends Abstrac @Override - protected void processSocketAsync(SocketWrapper<NioChannel> socketWrapper, + public void processSocketAsync(SocketWrapper<NioChannel> socketWrapper, SocketStatus socketStatus) { dispatchForEvent(socketWrapper.getSocket(), socketStatus, true); } Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Fri Jun 13 20:21:32 2014 @@ -471,6 +471,7 @@ public class SecureNioChannel extends Ni */ @Override public int write(ByteBuffer src) throws IOException { + checkInterruptStatus(); if ( src == this.netOutBuffer ) { //we can get here through a recursive call //by using the NioBlockingSelector Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SocketStatus.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SocketStatus.java?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SocketStatus.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/SocketStatus.java Fri Jun 13 20:21:32 2014 @@ -23,5 +23,5 @@ package org.apache.tomcat.util.net; * @author remm */ public enum SocketStatus { - OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT, ERROR + OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT, ERROR, CLOSE_NOW } Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties Fri Jun 13 20:21:32 2014 @@ -57,3 +57,5 @@ endpoint.apr.pollUnknownEvent=A socket w endpoint.apr.remoteport=APR socket [{0}] opened with remote port [{1}] endpoint.nio.selectorCloseFail=Failed to close selector when closing the poller endpoint.warn.noExector=Failed to process socket [{0}] in state [{1}] because the executor had already been shutdown + +channel.nio.interrupted=The current thread was interrupted Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1602510&r1=1602509&r2=1602510&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Fri Jun 13 20:21:32 2014 @@ -106,6 +106,12 @@ <subsection name="Coyote"> <changelog> <fix> + <bug>56518</bug>: When using NIO, do not attempt to write to the socket + if the thread is marked interrupted as this will lead to a connection + limit leak. This fix was based on analysis of the issue by hanyong. + (markt) + </fix> + <fix> <bug>56521</bug>: Re-use the asynchronous write buffer between writes to reduce allocation and GC overhead. Based on a patch by leonzhx. Also make the buffer size configurable and remove copying of data within --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org