Additional fix for https://bz.apache.org/bugzilla/show_bug.cgi?id=63825
Local performance testing shows no negative impact and possibly a small
gain.
diff --git a/java/org/apache/coyote/http11/Constants.java b/java/org/apache/coyote/http11/Constants.java
index 6ed0923..2ca4dc4 100644
--- a/java/org/apache/coyote/http11/Constants.java
+++ b/java/org/apache/coyote/http11/Constants.java
@@ -103,8 +103,16 @@
/* Various constant "strings" */
public static final String CONNECTION = "Connection";
public static final String CLOSE = "close";
+ /**
+ * @deprecated Unused. Will be removed in Tomcat 10.
+ */
+ @Deprecated
public static final byte[] CLOSE_BYTES = ByteChunk.convertToBytes(CLOSE);
public static final String KEEPALIVE = "keep-alive";
+ /**
+ * @deprecated Unused. Will be removed in Tomcat 10.
+ */
+ @Deprecated
public static final byte[] KEEPALIVE_BYTES = ByteChunk.convertToBytes(KEEPALIVE);
public static final String CHUNKED = "chunked";
public static final byte[] ACK_BYTES = ByteChunk.convertToBytes("HTTP/1.1 100 " + CRLF + CRLF);
diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java
index 24fd9e9..6df04cc 100644
--- a/java/org/apache/coyote/http11/Http11Processor.java
+++ b/java/org/apache/coyote/http11/Http11Processor.java
@@ -20,6 +20,7 @@
import java.io.InterruptedIOException;
import java.io.StringReader;
import java.nio.ByteBuffer;
+import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Locale;
@@ -49,7 +50,6 @@
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
-import org.apache.tomcat.util.buf.Ascii;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.FastHttpDateFormat;
@@ -189,39 +189,6 @@
/**
- * Specialized utility method: find a sequence of lower case bytes inside
- * a ByteChunk.
- */
- private static int findBytes(ByteChunk bc, byte[] b) {
-
- byte first = b[0];
- byte[] buff = bc.getBuffer();
- int start = bc.getStart();
- int end = bc.getEnd();
-
- // Look for first char
- int srcEnd = b.length;
-
- for (int i = start; i <= (end - srcEnd); i++) {
- if (Ascii.toLower(buff[i]) != first) {
- continue;
- }
- // found first char, now look for a match
- int myPos = i+1;
- for (int srcPos = 1; srcPos < srcEnd;) {
- if (Ascii.toLower(buff[myPos++]) != b[srcPos++]) {
- break;
- }
- if (srcPos == srcEnd) {
- return i - start; // found it
- }
- }
- }
- return -1;
- }
-
-
- /**
* Determine if we must drop the connection because of the HTTP status
* code. Use the same list of codes as Apache/httpd.
*/
@@ -560,7 +527,7 @@
/**
* After reading the request headers, we have to setup the request filters.
*/
- private void prepareRequest() {
+ private void prepareRequest() throws IOException {
http11 = true;
http09 = false;
@@ -598,11 +565,11 @@
// Check connection header
MessageBytes connectionValueMB = headers.getValue(Constants.CONNECTION);
if (connectionValueMB != null && !connectionValueMB.isNull()) {
- ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
- if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
+ Set<String> tokens = new HashSet<>();
+ parseConnectionTokens(headers, tokens);
+ if (tokens.contains(Constants.CLOSE)) {
keepAlive = false;
- } else if (findBytes(connectionValueBC,
- Constants.KEEPALIVE_BYTES) != -1) {
+ } else if (tokens.contains(Constants.KEEPALIVE)) {
keepAlive = true;
}
}
@@ -992,18 +959,23 @@
return false;
}
+ Set<String> tokens = new HashSet<>();
+ parseConnectionTokens(headers, tokens);
+ return tokens.contains(token);
+ }
+
+
+ private static void parseConnectionTokens(MimeHeaders headers, Collection<String> tokens) throws IOException {
Enumeration<String> values = headers.values(Constants.CONNECTION);
- Set<String> result = new HashSet<>();
while (values.hasMoreElements()) {
String nextHeaderValue = values.nextElement();
if (nextHeaderValue != null) {
- TokenList.parseTokenList(new StringReader(nextHeaderValue), result);
+ TokenList.parseTokenList(new StringReader(nextHeaderValue), tokens);
}
}
-
- return result.contains(token);
}
+
private void prepareSendfile(OutputFilter[] outputFilters) {
String fileName = (String) request.getAttribute(
org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR);