Author: markt
Date: Thu Jun 12 15:10:46 2014
New Revision: 1602198
URL: http://svn.apache.org/r1602198
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/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java
tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java
tomcat/trunk/java/org/apache/coyote/Adapter.java
tomcat/trunk/java/org/apache/coyote/LocalStrings.properties
tomcat/trunk/java/org/apache/coyote/Processor.java
tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java
tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java
tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java
tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
tomcat/trunk/java/org/apache/tomcat/util/net/SocketStatus.java
tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties
tomcat/trunk/webapps/docs/changelog.xml
Modified: tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java
(original)
+++ tomcat/trunk/java/org/apache/catalina/connector/CoyoteAdapter.java Thu Jun
12 15:10:46 2014
@@ -599,6 +599,35 @@ 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) {
+ 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/trunk/java/org/apache/coyote/AbstractProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/AbstractProcessor.java Thu Jun 12
15:10:46 2014
@@ -74,8 +74,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().processSocket(socketWrapper, SocketStatus.CLOSE_NOW,
true);
+ }
}
@@ -162,6 +174,11 @@ public abstract class AbstractProcessor<
}
@Override
+ public void errorDispatch() {
+ getAdapter().errorDispatch(request, response);
+ }
+
+ @Override
public abstract boolean isComet();
@Override
Modified: tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java (original)
+++ tomcat/trunk/java/org/apache/coyote/AbstractProtocol.java Thu Jun 12
15:10:46 2014
@@ -624,7 +624,10 @@ public abstract class AbstractProtocol<S
SocketState state = SocketState.CLOSED;
Iterator<DispatchType> dispatches = null;
do {
- if (dispatches != null) {
+ if (status == SocketStatus.CLOSE_NOW) {
+ processor.errorDispatch();
+ state = SocketState.CLOSED;
+ } else if (dispatches != null) {
// Associate the processor with the connection as
// these calls may result in a nested call to process()
connections.put(socket, processor);
Modified: tomcat/trunk/java/org/apache/coyote/Adapter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/Adapter.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/Adapter.java (original)
+++ tomcat/trunk/java/org/apache/coyote/Adapter.java Thu Jun 12 15:10:46 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/trunk/java/org/apache/coyote/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/LocalStrings.properties?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/coyote/LocalStrings.properties Thu Jun 12
15:10:46 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
+
abstractProtocol.mbeanDeregistrationFailed=Failed to deregister MBean named
[{0}] from MBean server [{1}]
abstractProtocolHandler.getAttribute=Get attribute [{0}] with value [{1}]
Modified: tomcat/trunk/java/org/apache/coyote/Processor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/Processor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/Processor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/Processor.java Thu Jun 12 15:10:46 2014
@@ -43,6 +43,8 @@ public interface Processor<S> {
HttpUpgradeHandler getHttpUpgradeHandler();
SocketState upgradeDispatch(SocketStatus status) throws IOException;
+ void errorDispatch();
+
boolean isComet();
boolean isAsync();
boolean isUpgrade();
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java Thu Jun
12 15:10:46 2014
@@ -359,7 +359,7 @@ public abstract class AbstractAjpProcess
try {
finish();
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
}
break;
}
@@ -371,13 +371,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;
}
@@ -391,7 +391,7 @@ public abstract class AbstractAjpProcess
try {
prepareResponse();
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
return;
}
}
@@ -399,7 +399,7 @@ public abstract class AbstractAjpProcess
try {
flush(true);
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
}
break;
}
@@ -410,7 +410,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 RESET: {
@@ -642,7 +642,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;
}
}
@@ -690,14 +690,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);
}
@@ -766,7 +766,7 @@ public abstract class AbstractAjpProcess
try {
output(pongMessageArray, 0, pongMessageArray.length,
true);
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
}
recycle(false);
continue;
@@ -776,20 +776,20 @@ public abstract class AbstractAjpProcess
if (getLog().isDebugEnabled()) {
getLog().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);
getLog().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);
}
@@ -803,7 +803,7 @@ public abstract class AbstractAjpProcess
getLog().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);
}
}
@@ -811,7 +811,7 @@ public abstract class AbstractAjpProcess
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;
@@ -822,13 +822,13 @@ public abstract class AbstractAjpProcess
rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
getAdapter().service(request, response);
} catch (InterruptedIOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
getLog().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);
}
}
@@ -843,7 +843,7 @@ public abstract class AbstractAjpProcess
finish();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, t);
}
}
@@ -1191,7 +1191,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
@@ -1306,7 +1306,7 @@ public abstract class AbstractAjpProcess
secret = true;
if (!tmpMB.equals(requiredSecret)) {
response.setStatus(403);
- setErrorState(ErrorState.CLOSE_CLEAN);
+ setErrorState(ErrorState.CLOSE_CLEAN, null);
}
}
break;
@@ -1322,7 +1322,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/)
@@ -1373,7 +1373,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;
}
@@ -1423,7 +1423,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);
@@ -1542,7 +1542,7 @@ public abstract class AbstractAjpProcess
try {
prepareResponse();
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
return;
}
}
@@ -1748,7 +1748,7 @@ public abstract class AbstractAjpProcess
try {
prepareResponse();
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
}
}
Modified:
tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java Thu
Jun 12 15:10:46 2014
@@ -698,7 +698,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 +
"]");
@@ -722,7 +722,7 @@ public abstract class AbstractHttp11Proc
try {
getOutputBuffer().endRequest();
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
}
break;
}
@@ -737,7 +737,7 @@ public abstract class AbstractHttp11Proc
prepareResponse();
getOutputBuffer().commit();
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
}
break;
}
@@ -753,7 +753,7 @@ public abstract class AbstractHttp11Proc
try {
getOutputBuffer().sendAck();
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
}
break;
}
@@ -761,7 +761,7 @@ public abstract class AbstractHttp11Proc
try {
getOutputBuffer().flush();
} catch (IOException e) {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
response.setErrorException(e);
}
break;
@@ -773,7 +773,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;
}
@@ -875,7 +875,7 @@ public abstract class AbstractHttp11Proc
isReady.set(getOutputBuffer().isReady());
} catch (IOException e) {
getLog().debug("isReady() failed", e);
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, e);
}
break;
}
@@ -903,7 +903,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: {
@@ -997,7 +997,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
@@ -1025,7 +1025,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);
@@ -1047,7 +1047,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);
}
@@ -1064,7 +1064,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);
}
}
@@ -1090,20 +1090,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) {
@@ -1112,7 +1112,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);
}
}
@@ -1230,7 +1230,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+"\"");
@@ -1268,7 +1268,7 @@ public abstract class AbstractHttp11Proc
expectation = true;
} else {
response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
- setErrorState(ErrorState.CLOSE_CLEAN);
+ setErrorState(ErrorState.CLOSE_CLEAN, null);
}
}
@@ -1362,7 +1362,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");
@@ -1623,7 +1623,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);
@@ -1675,14 +1675,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);
}
@@ -1752,14 +1752,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);
}
}
@@ -1767,10 +1767,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/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java Thu Jun
12 15:10:46 2014
@@ -113,15 +113,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);
}
@@ -178,7 +178,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;
@@ -215,7 +215,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/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Nio2Processor.java Thu Jun
12 15:10:46 2014
@@ -94,7 +94,7 @@ public class Http11Nio2Processor 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 (socketWrapper != null) {
@@ -117,12 +117,12 @@ public class Http11Nio2Processor 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);
getAdapter().log(request, response, 0);
log.error(sm.getString("http11processor.request.process"), t);
}
@@ -239,7 +239,7 @@ public class Http11Nio2Processor 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;
@@ -285,7 +285,7 @@ public class Http11Nio2Processor extends
if (log.isDebugEnabled()) {
log.debug(sm.getString("http11processor.sendfile.error"));
}
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, null);
}
return true;
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Thu Jun
12 15:10:46 2014
@@ -103,7 +103,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) {
@@ -126,12 +126,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);
}
@@ -236,7 +236,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;
@@ -290,7 +290,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/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/upgrade/AbstractProcessor.java
Thu Jun 12 15:10:46 2014
@@ -150,6 +150,11 @@ public abstract class AbstractProcessor<
}
@Override
+ public void errorDispatch() {
+ // NO-OP
+ }
+
+ @Override
public final SocketState asyncPostProcess() {
return null;
}
Modified: tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/spdy/SpdyProcessor.java Thu Jun 12
15:10:46 2014
@@ -160,7 +160,7 @@ public class SpdyProcessor<S> extends Ab
rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
getAdapter().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);
@@ -169,7 +169,7 @@ public class SpdyProcessor<S> extends Ab
t.printStackTrace();
response.setStatus(500);
getAdapter().log(request, response, 0);
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, t);
}
// TODO: async, etc ( detached mode - use a special light protocol)
@@ -180,7 +180,7 @@ public class SpdyProcessor<S> extends Ab
finish();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, t);
}
}
@@ -251,7 +251,7 @@ public class SpdyProcessor<S> extends Ab
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: {
@@ -414,7 +414,7 @@ public class SpdyProcessor<S> extends Ab
break;
}
case CLOSE_NOW: {
- setErrorState(ErrorState.CLOSE_NOW);
+ setErrorState(ErrorState.CLOSE_NOW, null);
break;
}
default: {
Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/NioChannel.java Thu Jun 12
15:10:46 2014
@@ -25,6 +25,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;
/**
*
@@ -36,6 +37,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;
@@ -119,6 +123,7 @@ public class NioChannel implements ByteC
*/
@Override
public int write(ByteBuffer src) throws IOException {
+ checkInterruptStatus();
return sc.write(src);
}
@@ -211,4 +216,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/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Thu Jun
12 15:10:46 2014
@@ -29,8 +29,6 @@ import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
-import org.apache.tomcat.util.res.StringManager;
-
/**
*
* Implementation of a secure socket channel
@@ -39,8 +37,6 @@ import org.apache.tomcat.util.res.String
public class SecureNioChannel extends NioChannel {
- protected static final StringManager sm =
StringManager.getManager("org.apache.tomcat.util.net.res");
-
protected ByteBuffer netInBuffer;
protected ByteBuffer netOutBuffer;
@@ -475,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/trunk/java/org/apache/tomcat/util/net/SocketStatus.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SocketStatus.java?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SocketStatus.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SocketStatus.java Thu Jun 12
15:10:46 2014
@@ -23,5 +23,5 @@ package org.apache.tomcat.util.net;
* @author remm
*/
public enum SocketStatus {
- OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT, ERROR,
ASYNC_WRITE_ERROR, ASYNC_READ_ERROR
+ OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT, ERROR,
ASYNC_WRITE_ERROR, ASYNC_READ_ERROR, CLOSE_NOW
}
Modified:
tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/res/LocalStrings.properties
Thu Jun 12 15:10:46 2014
@@ -61,6 +61,7 @@ endpoint.apr.remoteport=APR socket [{0}]
endpoint.nio.selectorCloseFail=Failed to close selector when closing the poller
endpoint.nio2.exclusiveExecutor=The NIO2 connector requires an exclusive
executor to operate properly on shutdown
+channel.nio.interrupted=The current thread was interrupted
channel.nio.ssl.notHandshaking=NOT_HANDSHAKING during handshake
channel.nio.ssl.handhakeError=Handshake error
channel.nio.ssl.unexpectedStatusDuringWrap=Unexpected status [{0}] during
handshake WRAP.
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1602198&r1=1602197&r2=1602198&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Thu Jun 12 15:10:46 2014
@@ -147,6 +147,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: [email protected]
For additional commands, e-mail: [email protected]