Author: markt Date: Sun May 15 10:00:22 2011 New Revision: 1103308 URL: http://svn.apache.org/viewvc?rev=1103308&view=rev Log: Make AJP-NIO actually use non-blocking reads. Only the first read of a request is is non-blocking. Any additional reads will block. The first read of the first request on a new connection will also block.
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java tomcat/trunk/java/org/apache/coyote/ajp/LocalStrings.properties Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java?rev=1103308&r1=1103307&r2=1103308&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java (original) +++ tomcat/trunk/java/org/apache/coyote/ajp/AjpNioProcessor.java Sun May 15 10:00:22 2011 @@ -216,6 +216,8 @@ public class AjpNioProcessor extends Abs // Error flag error = false; + boolean keptAlive = false; + while (!error && !endpoint.isPaused()) { // Parsing the request header @@ -225,8 +227,9 @@ public class AjpNioProcessor extends Abs ka.setTimeout(keepAliveTimeout); } // Get first message of the request - if (!readMessage(requestHeaderMessage)) { - // This means a connection timeout + int bytesRead = readMessage(requestHeaderMessage, !keptAlive); + if (!keptAlive && bytesRead == 0) { + // No bytes on a blocking read - connection timeout rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); break; } @@ -243,6 +246,8 @@ public class AjpNioProcessor extends Abs } catch (IOException e) { error = true; } + // Should be unnecessary but just in case... + keptAlive = true; recycle(); continue; } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) { @@ -250,6 +255,8 @@ public class AjpNioProcessor extends Abs if(log.isDebugEnabled()) { log.debug("Unexpected message: "+type); } + // Should be unnecessary but just in case... + keptAlive = true; recycle(); continue; } @@ -328,13 +335,18 @@ public class AjpNioProcessor extends Abs request.updateCounters(); rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); + keptAlive = true; recycle(); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - if (isAsync() && !error && !endpoint.isPaused()) { - return SocketState.LONG; + if (!error && !endpoint.isPaused()) { + if (isAsync()) { + return SocketState.LONG; + } else { + return SocketState.OPEN; + } } else { readBuffer = null; writeBuffer = null; @@ -494,13 +506,13 @@ public class AjpNioProcessor extends Abs * Read at least the specified amount of bytes, and place them * in the input buffer. */ - protected void read(byte[] buf, int pos, int n) + protected int read(byte[] buf, int pos, int n, boolean block) throws IOException { int read = readBufferEnd - pos; int res = 0; while (read < n) { - res = readSocket(buf, read + pos, true); + res = readSocket(buf, read + pos, block); if (res > 0) { read += res; } else { @@ -508,6 +520,7 @@ public class AjpNioProcessor extends Abs } } readBufferEnd += read; + return read; } private int readSocket(byte[] buf, int pos, boolean block) throws IOException { @@ -555,10 +568,9 @@ public class AjpNioProcessor extends Abs first = false; bodyMessage.reset(); - if (!readMessage(bodyMessage)) { - // Invalid message - return false; - } + + readMessage(bodyMessage, true); + // No data received. if (bodyMessage.getLen() == 0) { // just the header @@ -607,27 +619,26 @@ public class AjpNioProcessor extends Abs /** * Read an AJP message. * - * @return true if the message has been read, false if the short read - * didn't return anything + * @return The number of bytes read * @throws IOException any other failure, including incomplete reads */ - protected boolean readMessage(AjpMessage message) + protected int readMessage(AjpMessage message, boolean block) throws IOException { byte[] buf = message.getBuffer(); int headerLength = message.getHeaderLength(); - read(buf, 0, headerLength); + int bytesRead = read(buf, 0, headerLength, block); int messageLength = message.processHeader(); if (messageLength < 0) { // Invalid AJP header signature - // TODO: Throw some exception and close the connection to frontend. - return false; + throw new IOException(sm.getString("ajpmessage.invalidLength", + Integer.valueOf(messageLength))); } else if (messageLength == 0) { // Zero length message. - return true; + return bytesRead; } else { if (messageLength > buf.length) { @@ -638,8 +649,8 @@ public class AjpNioProcessor extends Abs Integer.valueOf(messageLength), Integer.valueOf(buf.length))); } - read(buf, headerLength, messageLength); - return true; + bytesRead += read(buf, headerLength, messageLength, true); + return bytesRead; } } Modified: tomcat/trunk/java/org/apache/coyote/ajp/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/LocalStrings.properties?rev=1103308&r1=1103307&r2=1103308&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/ajp/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/coyote/ajp/LocalStrings.properties Sun May 15 10:00:22 2011 @@ -44,4 +44,5 @@ ajpmessage.null=Cannot append null value ajpmessage.overflow=Overflow error for buffer adding {0} bytes at position {1} ajpmessage.read=Requested {0} bytes exceeds message available data ajpmessage.invalid=Invalid message received with signature {0} +ajpmessage.invalidLength=Invalid message received with length {0} --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org