--- java/org/apache/coyote/AbstractProtocol.java.orig 2017-06-08 16:23:31.981000734 -0400
+++ java/org/apache/coyote/AbstractProtocol.java 2017-06-08 16:23:32.002000817 -0400
@@ -693,10 +693,9 @@
release(wrapper, processor, false, true);
} else if (state == SocketState.SENDFILE) {
// Sendfile in progress. If it fails, the socket will be
- // closed. If it works, the socket will be re-added to the
- // poller
- connections.remove(socket);
- release(wrapper, processor, false, false);
+ // closed. If it works, the socket either be added to the
+ // poller (or equivalent) to await more data or processed
+ // if there are any pipe-lined requests remaining.
} else if (state == SocketState.UPGRADED) {
// Need to keep the connection associated with the processor
connections.put(socket, processor);
--- java/org/apache/coyote/http11/Http11AprProcessor.java.orig 2017-06-08 16:23:31.983000742 -0400
+++ java/org/apache/coyote/http11/Http11AprProcessor.java 2017-06-08 16:23:31.999000805 -0400
@@ -38,6 +38,7 @@
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.AprEndpoint;
import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.SendfileKeepAliveState;
import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;
@@ -211,7 +212,15 @@
// Do sendfile as needed: add socket to sendfile and end
if (sendfileData != null && !getErrorState().isError()) {
sendfileData.socket = socketWrapper.getSocket().longValue();
- sendfileData.keepAlive = keepAlive;
+ if (keepAlive) {
+ if (getInputBuffer().available() == 0) {
+ sendfileData.keepAliveState = SendfileKeepAliveState.OPEN;
+ } else {
+ sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED;
+ }
+ } else {
+ sendfileData.keepAliveState = SendfileKeepAliveState.NONE;
+ }
switch (((AprEndpoint)endpoint).getSendfile().add(sendfileData)) {
case DONE:
return false;
--- java/org/apache/coyote/http11/Http11NioProcessor.java.orig 2017-06-08 16:23:31.984000746 -0400
+++ java/org/apache/coyote/http11/Http11NioProcessor.java 2017-06-08 16:23:32.000000809 -0400
@@ -37,6 +37,7 @@
import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SecureNioChannel;
+import org.apache.tomcat.util.net.SendfileKeepAliveState;
import org.apache.tomcat.util.net.SocketStatus;
import org.apache.tomcat.util.net.SocketWrapper;
@@ -275,7 +276,15 @@
// Do sendfile as needed: add socket to sendfile and end
if (sendfileData != null && !getErrorState().isError()) {
((KeyAttachment) socketWrapper).setSendfileData(sendfileData);
- sendfileData.keepAlive = keepAlive;
+ if (keepAlive) {
+ if (getInputBuffer().available() == 0) {
+ sendfileData.keepAliveState = SendfileKeepAliveState.OPEN;
+ } else {
+ sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED;
+ }
+ } else {
+ sendfileData.keepAliveState = SendfileKeepAliveState.NONE;
+ }
SelectionKey key = socketWrapper.getSocket().getIOChannel().keyFor(
socketWrapper.getSocket().getPoller().getSelector());
//do the first write on this thread, might as well
--- java/org/apache/tomcat/util/net/AprEndpoint.java.orig 2017-06-08 16:23:31.985000750 -0400
+++ java/org/apache/tomcat/util/net/AprEndpoint.java 2017-06-08 16:23:32.001000813 -0400
@@ -2106,7 +2106,7 @@
// Position
public long pos;
// KeepAlive flag
- public boolean keepAlive;
+ public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE;
}
@@ -2349,20 +2349,33 @@
state.pos = state.pos + nw;
if (state.pos >= state.end) {
remove(state);
- if (state.keepAlive) {
+ switch (state.keepAliveState) {
+ case NONE: {
+ // Close the socket since this is
+ // the end of the not keep-alive request.
+ closeSocket(state.socket);
+ break;
+ }
+ case PIPELINED: {
+ // Destroy file descriptor pool, which should close the file
+ Pool.destroy(state.fdpool);
+ Socket.timeoutSet(state.socket, getSoTimeout() * 1000);
+ // Process the pipelined request data
+ if (!processSocket(state.socket, SocketStatus.OPEN_READ)) {
+ closeSocket(state.socket);
+ }
+ break;
+ }
+ case OPEN: {
// Destroy file descriptor pool, which should close the file
Pool.destroy(state.fdpool);
- Socket.timeoutSet(state.socket,
- getSoTimeout() * 1000);
- // If all done put the socket back in the
- // poller for processing of further requests
- getPoller().add(
- state.socket, getKeepAliveTimeout(),
+ Socket.timeoutSet(state.socket, getSoTimeout() * 1000);
+ // Put the socket back in the poller for
+ // processing of further requests
+ getPoller().add(state.socket, getKeepAliveTimeout(),
true, false);
- } else {
- // Close the socket since this is
- // the end of not keep-alive request.
- closeSocket(state.socket);
+ break;
+ }
}
}
}
--- java/org/apache/tomcat/util/net/NioEndpoint.java.orig 2017-06-08 16:23:31.987000757 -0400
+++ java/org/apache/tomcat/util/net/NioEndpoint.java 2017-06-08 16:23:32.002000817 -0400
@@ -1383,16 +1383,30 @@
// responsible for registering the socket for the
// appropriate event(s) if sendfile completes.
if (!calledByProcessor) {
- if ( sd.keepAlive ) {
- if (log.isDebugEnabled()) {
- log.debug("Connection is keep alive, registering back for OP_READ");
- }
- reg(sk,attachment,SelectionKey.OP_READ);
- } else {
+ switch (sd.keepAliveState) {
+ case NONE: {
if (log.isDebugEnabled()) {
log.debug("Send file connection is being closed");
}
cancelledKey(sk,SocketStatus.STOP,false);
+ break;
+ }
+ case PIPELINED: {
+ if (log.isDebugEnabled()) {
+ log.debug("Connection is keep alive, processing pipe-lined data");
+ }
+ if (!processSocket(sc, SocketStatus.OPEN_READ, true)) {
+ cancelledKey(sk, SocketStatus.DISCONNECT, false);
+ }
+ break;
+ }
+ case OPEN: {
+ if (log.isDebugEnabled()) {
+ log.debug("Connection is keep alive, registering back for OP_READ");
+ }
+ reg(sk, attachment, SelectionKey.OP_READ);
+ break;
+ }
}
}
return SendfileState.DONE;
@@ -1836,6 +1850,6 @@
public volatile long pos;
public volatile long length;
// KeepAlive flag
- public volatile boolean keepAlive;
+ public SendfileKeepAliveState keepAliveState = SendfileKeepAliveState.NONE;
}
}
--- webapps/docs/changelog.xml.orig 2017-06-08 16:23:31.989000765 -0400
+++ webapps/docs/changelog.xml 2017-06-08 16:25:23.618440723 -0400
@@ -73,6 +73,13 @@
</fix>
</changelog>
</subsection>
+ <subsection name="Coyote">
+ <changelog>
+ <fix>
+ Improve sendfile handling when requests are pipelined. (markt)
+ </fix>
+ </changelog>
+ </subsection>
</section>
<section name="Tomcat 7.0.76 (violetagg)">
<subsection name="Catalina">
--- java/org/apache/tomcat/util/net/SendfileKeepAliveState.java.orig 2017-06-08 16:23:31.992000777 -0400
+++ java/org/apache/tomcat/util/net/SendfileKeepAliveState.java 2017-06-08 16:23:32.000000809 -0400
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.net;
+
+public enum SendfileKeepAliveState {
+
+ /**
+ * Keep-alive is not in use. The socket can be closed when the response has
+ * been written.
+ */
+ NONE,
+
+ /**
+ * Keep-alive is in use and there is pipelined data in the input buffer to
+ * be read as soon as the current response has been written.
+ */
+ PIPELINED,
+
+ /**
+ * Keep-alive is in use. The socket should be added to the poller (or
+ * equivalent) to await more data as soon as the current response has been
+ * written.
+ */
+ OPEN
+}