Author: markt
Date: Tue Jan 13 15:47:50 2015
New Revision: 1651386
URL: http://svn.apache.org/r1651386
Log:
Switch APR to using non-blocking reads for HTTP request line and headers
Modified:
tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java
tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java
Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java?rev=1651386&r1=1651385&r2=1651386&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/InternalAprInputBuffer.java Tue
Jan 13 15:47:50 2015
@@ -16,11 +16,9 @@
*/
package org.apache.coyote.http11;
-import java.io.EOFException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
@@ -31,7 +29,6 @@ import org.apache.juli.logging.LogFactor
import org.apache.tomcat.jni.Socket;
import org.apache.tomcat.jni.Status;
import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.SocketWrapperBase;
@@ -41,7 +38,7 @@ import org.apache.tomcat.util.net.Socket
*
* @author <a href="mailto:[email protected]">Remy Maucherat</a>
*/
-public class InternalAprInputBuffer extends AbstractInputBuffer<Long> {
+public class InternalAprInputBuffer extends AbstractNioInputBuffer<Long> {
private static final Log log =
LogFactory.getLog(InternalAprInputBuffer.class);
@@ -53,11 +50,8 @@ public class InternalAprInputBuffer exte
* Alternate constructor.
*/
public InternalAprInputBuffer(Request request, int headerBufferSize) {
+ super(request, headerBufferSize);
- this.request = request;
- headers = request.getMimeHeaders();
-
- buf = new byte[headerBufferSize];
if (headerBufferSize < (8 * 1024)) {
bbuf = ByteBuffer.allocateDirect(6 * 1500);
} else {
@@ -65,14 +59,6 @@ public class InternalAprInputBuffer exte
}
inputStreamInputBuffer = new SocketInputBuffer();
-
- filterLibrary = new InputFilter[0];
- activeFilters = new InputFilter[0];
- lastActiveFilter = -1;
-
- parsingHeader = true;
- swallowInput = true;
-
}
@@ -108,432 +94,26 @@ public class InternalAprInputBuffer exte
}
- /**
- * Read the request line. This function is meant to be used during the
- * HTTP request header parsing. Do NOT attempt to read the request body
- * using it.
- *
- * @throws IOException If an exception occurs during the underlying socket
- * read operations, or if the given buffer is not big enough to accommodate
- * the whole line.
- * @return true if data is properly fed; false if no data is available
- * immediately and thread should be freed
- */
- @Override
- public boolean parseRequestLine(boolean useAvailableData)
- throws IOException {
-
- int start = 0;
-
- //
- // Skipping blank lines
- //
-
- byte chr = 0;
- do {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (useAvailableData) {
- return false;
- }
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
- // Set the start time once we start reading data (even if it is
- // just skipping blank lines)
- if (request.getStartTime() < 0) {
- request.setStartTime(System.currentTimeMillis());
- }
- chr = buf[pos++];
- } while ((chr == Constants.CR) || (chr == Constants.LF));
-
- pos--;
-
- // Mark the current buffer position
- start = pos;
-
- if (pos >= lastValid) {
- if (useAvailableData) {
- return false;
- }
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- //
- // Reading the method name
- // Method name is always US-ASCII
- //
-
- boolean space = false;
-
- while (!space) {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- // Spec says no CR or LF in method name
- if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) {
- throw new IllegalArgumentException(
- sm.getString("iib.invalidmethod"));
- }
- // Spec says single SP but it also says be tolerant of HT
- if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
- space = true;
- request.method().setBytes(buf, start, pos - start);
- }
-
- pos++;
-
- }
-
- // Spec says single SP but also says be tolerant of multiple and/or HT
- while (space) {
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
- if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
- pos++;
- } else {
- space = false;
- }
- }
-
- // Mark the current buffer position
- start = pos;
- int end = 0;
- int questionPos = -1;
-
- //
- // Reading the URI
- //
-
- boolean eol = false;
-
- while (!space) {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- // Spec says single SP but it also says be tolerant of HT
- if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
- space = true;
- end = pos;
- } else if ((buf[pos] == Constants.CR)
- || (buf[pos] == Constants.LF)) {
- // HTTP/0.9 style request
- eol = true;
- space = true;
- end = pos;
- } else if ((buf[pos] == Constants.QUESTION)
- && (questionPos == -1)) {
- questionPos = pos;
- }
-
- pos++;
-
- }
-
- if (questionPos >= 0) {
- request.queryString().setBytes(buf, questionPos + 1,
- end - questionPos - 1);
- request.requestURI().setBytes(buf, start, questionPos - start);
- } else {
- request.requestURI().setBytes(buf, start, end - start);
- }
-
- // Spec says single SP but also says be tolerant of multiple and/or HT
- while (space) {
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
- if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) {
- pos++;
- } else {
- space = false;
- }
- }
-
-
- // Mark the current buffer position
- start = pos;
- end = 0;
-
- //
- // Reading the protocol
- // Protocol is always US-ASCII
- //
-
- while (!eol) {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- if (buf[pos] == Constants.CR) {
- end = pos;
- } else if (buf[pos] == Constants.LF) {
- if (end == 0)
- end = pos;
- eol = true;
- }
-
- pos++;
-
- }
-
- if ((end - start) > 0) {
- request.protocol().setBytes(buf, start, end - start);
- } else {
- request.protocol().setString("");
- }
-
- return true;
-
- }
-
+ // ------------------------------------------------------ Protected Methods
- /**
- * Parse the HTTP headers.
- */
@Override
- public boolean parseHeaders()
- throws IOException {
- if (!parsingHeader) {
- throw new IllegalStateException(
- sm.getString("iib.parseheaders.ise.error"));
- }
-
- while (parseHeader()) {
- // Loop until there are no more headers
- }
-
- parsingHeader = false;
- end = pos;
- return true;
- }
-
-
- /**
- * Parse an HTTP header.
- *
- * @return false after reading a blank line (which indicates that the
- * HTTP header parsing is done
- */
- @SuppressWarnings("null") // headerValue cannot be null
- private boolean parseHeader()
- throws IOException {
-
- //
- // Check for blank line
- //
-
- byte chr = 0;
- while (true) {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- chr = buf[pos];
-
- if (chr == Constants.CR) {
- // Skip
- } else if (chr == Constants.LF) {
- pos++;
- return false;
- } else {
- break;
- }
-
- pos++;
-
- }
-
- // Mark the current buffer position
- int start = pos;
-
- //
- // Reading the header name
- // Header name is always US-ASCII
- //
-
- boolean colon = false;
- MessageBytes headerValue = null;
-
- while (!colon) {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- if (buf[pos] == Constants.COLON) {
- colon = true;
- headerValue = headers.addValue(buf, start, pos - start);
- } else if (!HTTP_TOKEN_CHAR[buf[pos]]) {
- // If a non-token header is detected, skip the line and
- // ignore the header
- skipLine(start);
- return true;
- }
- chr = buf[pos];
- if ((chr >= Constants.A) && (chr <= Constants.Z)) {
- buf[pos] = (byte) (chr - Constants.LC_OFFSET);
- }
-
- pos++;
-
- }
-
- // Mark the current buffer position
- start = pos;
- int realPos = pos;
-
- //
- // Reading the header value (which can be spanned over multiple lines)
- //
-
- boolean eol = false;
- boolean validLine = true;
-
- while (validLine) {
-
- boolean space = true;
-
- // Skipping spaces
- while (space) {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) {
- pos++;
- } else {
- space = false;
- }
-
- }
-
- int lastSignificantChar = realPos;
-
- // Reading bytes until the end of the line
- while (!eol) {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- if (buf[pos] == Constants.CR) {
- // Skip
- } else if (buf[pos] == Constants.LF) {
- eol = true;
- } else if (buf[pos] == Constants.SP) {
- buf[realPos] = buf[pos];
- realPos++;
- } else {
- buf[realPos] = buf[pos];
- realPos++;
- lastSignificantChar = realPos;
- }
-
- pos++;
-
- }
-
- realPos = lastSignificantChar;
-
- // Checking the first character of the new line. If the character
- // is a LWS, then it's a multiline header
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- chr = buf[pos];
- if ((chr != Constants.SP) && (chr != Constants.HT)) {
- validLine = false;
- } else {
- eol = false;
- // Copying one extra space in the buffer (since there must
- // be at least one space inserted between the lines)
- buf[realPos] = chr;
- realPos++;
- }
-
- }
-
- // Set the header value
- headerValue.setBytes(buf, start, realPos - start);
-
- return true;
-
- }
-
-
- private void skipLine(int start) throws IOException {
- boolean eol = false;
- int lastRealByte = start;
- if (pos - 1 > start) {
- lastRealByte = pos - 1;
- }
-
- while (!eol) {
-
- // Read new bytes if needed
- if (pos >= lastValid) {
- if (!fill(true))
- throw new EOFException(sm.getString("iib.eof.error"));
- }
-
- if (buf[pos] == Constants.CR) {
- // Skip
- } else if (buf[pos] == Constants.LF) {
- eol = true;
- } else {
- lastRealByte = pos;
- }
- pos++;
- }
-
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("iib.invalidheader", new String(buf, start,
- lastRealByte - start + 1, StandardCharsets.ISO_8859_1)));
- }
+ protected final Log getLog() {
+ return log;
}
- // ------------------------------------------------------ Protected Methods
-
@Override
protected void init(SocketWrapperBase<Long> socketWrapper,
AbstractEndpoint<Long> endpoint) throws IOException {
socket = socketWrapper.getSocket().longValue();
wrapper = socketWrapper;
+
+ int bufLength = headerBufferSize + bbuf.capacity();
+ if (buf == null || buf.length < bufLength) {
+ buf = new byte[bufLength];
+ }
+
Socket.setrbb(this.socket, bbuf);
}
@@ -594,12 +174,6 @@ public class InternalAprInputBuffer exte
}
- @Override
- protected final Log getLog() {
- return log;
- }
-
-
private int doReadSocket(boolean block) {
Lock readLock = wrapper.getBlockingStatusReadLock();
Modified: tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java?rev=1651386&r1=1651385&r2=1651386&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/InternalNioInputBuffer.java Tue
Jan 13 15:47:50 2015
@@ -65,12 +65,6 @@ public class InternalNioInputBuffer exte
// --------------------------------------------------------- Public Methods
- @Override
- protected final Log getLog() {
- return log;
- }
-
-
/**
* Recycle the input buffer. This should be called when closing the
* connection.
@@ -84,6 +78,12 @@ public class InternalNioInputBuffer exte
// ------------------------------------------------------ Protected Methods
@Override
+ protected final Log getLog() {
+ return log;
+ }
+
+
+ @Override
protected void init(SocketWrapperBase<NioChannel> socketWrapper,
AbstractEndpoint<NioChannel> endpoint) throws IOException {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]