|
|
037463 |
--- java/org/apache/tomcat/util/net/NioEndpoint.java.orig 2017-03-28 14:39:31.522852483 -0400
|
|
|
037463 |
+++ java/org/apache/tomcat/util/net/NioEndpoint.java 2017-03-28 14:39:31.528852515 -0400
|
|
|
037463 |
@@ -1406,11 +1406,15 @@
|
|
|
037463 |
}
|
|
|
037463 |
}catch ( IOException x ) {
|
|
|
037463 |
if ( log.isDebugEnabled() ) log.debug("Unable to complete sendfile request:", x);
|
|
|
037463 |
- cancelledKey(sk,SocketStatus.ERROR,false);
|
|
|
037463 |
+ if (!calledByProcessor) {
|
|
|
037463 |
+ cancelledKey(sk,SocketStatus.ERROR,false);
|
|
|
037463 |
+ }
|
|
|
037463 |
return SendfileState.ERROR;
|
|
|
037463 |
}catch ( Throwable t ) {
|
|
|
037463 |
log.error("",t);
|
|
|
037463 |
- cancelledKey(sk, SocketStatus.ERROR, false);
|
|
|
037463 |
+ if (!calledByProcessor) {
|
|
|
037463 |
+ cancelledKey(sk, SocketStatus.ERROR, false);
|
|
|
037463 |
+ }
|
|
|
037463 |
return SendfileState.ERROR;
|
|
|
037463 |
}
|
|
|
037463 |
}
|
|
|
037463 |
--- webapps/docs/changelog.xml.orig 2017-03-28 14:39:31.523852488 -0400
|
|
|
037463 |
+++ webapps/docs/changelog.xml 2017-03-28 14:41:38.105546243 -0400
|
|
|
037463 |
@@ -57,6 +57,16 @@
|
|
|
037463 |
They eventually become mixed with the numbered issues. (I.e., numbered
|
|
|
037463 |
issues do not "pop up" wrt. others).
|
|
|
037463 |
-->
|
|
|
037463 |
+<section name="Tomcat 7.0.69-11 (csutherl)">
|
|
|
037463 |
+ <subsection name="Coyote">
|
|
|
037463 |
+ <changelog>
|
|
|
037463 |
+ <fix>
|
|
|
037463 |
+ <bug>60409</bug>: When unable to complete sendfile request, ensure the
|
|
|
037463 |
+ Processor will be added to the cache only once. (markt/violetagg)
|
|
|
037463 |
+ </fix>
|
|
|
037463 |
+ </changelog>
|
|
|
037463 |
+ </subsection>
|
|
|
037463 |
+</section>
|
|
|
037463 |
<section name="Tomcat 7.0.69-9 (csutherl)">
|
|
|
037463 |
<subsection name="Catalina">
|
|
|
037463 |
<changelog>
|
|
|
037463 |
--- test/org/apache/catalina/connector/TestSendFile.java.orig 2017-03-28 14:39:31.524852493 -0400
|
|
|
037463 |
+++ test/org/apache/catalina/connector/TestSendFile.java 2017-03-28 14:39:31.527852510 -0400
|
|
|
037463 |
@@ -22,10 +22,14 @@
|
|
|
037463 |
import java.io.FileInputStream;
|
|
|
037463 |
import java.io.FileWriter;
|
|
|
037463 |
import java.io.IOException;
|
|
|
037463 |
+import java.util.ArrayList;
|
|
|
037463 |
import java.util.Arrays;
|
|
|
037463 |
import java.util.HashMap;
|
|
|
037463 |
import java.util.List;
|
|
|
037463 |
import java.util.Map;
|
|
|
037463 |
+import java.util.Random;
|
|
|
037463 |
+import java.util.concurrent.CountDownLatch;
|
|
|
037463 |
+import java.util.concurrent.TimeUnit;
|
|
|
037463 |
|
|
|
037463 |
import javax.servlet.ServletException;
|
|
|
037463 |
import javax.servlet.http.HttpServlet;
|
|
|
037463 |
@@ -33,6 +37,8 @@
|
|
|
037463 |
import javax.servlet.http.HttpServletResponse;
|
|
|
037463 |
|
|
|
037463 |
import static org.junit.Assert.assertEquals;
|
|
|
037463 |
+
|
|
|
037463 |
+import org.junit.Assert;
|
|
|
037463 |
import org.junit.Test;
|
|
|
037463 |
|
|
|
037463 |
import org.apache.catalina.Context;
|
|
|
037463 |
@@ -163,4 +169,97 @@
|
|
|
037463 |
}
|
|
|
037463 |
}
|
|
|
037463 |
|
|
|
037463 |
+
|
|
|
037463 |
+ @Test
|
|
|
037463 |
+ public void testBug60409() throws Exception {
|
|
|
037463 |
+ Tomcat tomcat = getTomcatInstance();
|
|
|
037463 |
+
|
|
|
037463 |
+ Context ctx = tomcat.addContext("", TEMP_DIR);
|
|
|
037463 |
+ File file = generateFile(TEMP_DIR, "", EXPECTED_CONTENT_LENGTH);
|
|
|
037463 |
+ Tomcat.addServlet(ctx, "test", new Bug60409Servlet(file));
|
|
|
037463 |
+ ctx.addServletMapping("/", "test");
|
|
|
037463 |
+
|
|
|
037463 |
+ tomcat.start();
|
|
|
037463 |
+
|
|
|
037463 |
+ ByteChunk bc = new ByteChunk();
|
|
|
037463 |
+ getUrl("http://localhost:" + getPort() + "/test/?" + Globals.SENDFILE_SUPPORTED_ATTR
|
|
|
037463 |
+ + "=true", bc, null);
|
|
|
037463 |
+
|
|
|
037463 |
+ CountDownLatch latch = new CountDownLatch(2);
|
|
|
037463 |
+ List<Throwable> exceptions = new ArrayList<Throwable>();
|
|
|
037463 |
+ new Thread(
|
|
|
037463 |
+ new RequestExecutor("http://localhost:" + getPort() + "/test/", latch, exceptions))
|
|
|
037463 |
+ .start();
|
|
|
037463 |
+ new Thread(
|
|
|
037463 |
+ new RequestExecutor("http://localhost:" + getPort() + "/test/", latch, exceptions))
|
|
|
037463 |
+ .start();
|
|
|
037463 |
+
|
|
|
037463 |
+ latch.await(3000, TimeUnit.MILLISECONDS);
|
|
|
037463 |
+
|
|
|
037463 |
+ if (exceptions.size() > 0) {
|
|
|
037463 |
+ Assert.fail();
|
|
|
037463 |
+ }
|
|
|
037463 |
+ }
|
|
|
037463 |
+
|
|
|
037463 |
+ private static final class Bug60409Servlet extends HttpServlet {
|
|
|
037463 |
+ private static final long serialVersionUID = 1L;
|
|
|
037463 |
+ private final File file;
|
|
|
037463 |
+
|
|
|
037463 |
+ Bug60409Servlet(File file) {
|
|
|
037463 |
+ this.file = file;
|
|
|
037463 |
+ }
|
|
|
037463 |
+
|
|
|
037463 |
+ @Override
|
|
|
037463 |
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
|
|
037463 |
+ throws ServletException, IOException {
|
|
|
037463 |
+ if (Boolean.valueOf(req.getParameter(Globals.SENDFILE_SUPPORTED_ATTR)).booleanValue()) {
|
|
|
037463 |
+ resp.setContentType("'application/octet-stream");
|
|
|
037463 |
+ resp.setCharacterEncoding("ISO-8859-1");
|
|
|
037463 |
+ resp.setContentLength((int) file.length());
|
|
|
037463 |
+ req.setAttribute(Globals.SENDFILE_FILENAME_ATTR, file.getAbsolutePath());
|
|
|
037463 |
+ req.setAttribute(Globals.SENDFILE_FILE_START_ATTR, new Long(0));
|
|
|
037463 |
+ req.setAttribute(Globals.SENDFILE_FILE_END_ATTR, new Long(file.length()));
|
|
|
037463 |
+ file.delete();
|
|
|
037463 |
+ } else {
|
|
|
037463 |
+ byte[] c = new byte[1024];
|
|
|
037463 |
+ Random rd = new Random();
|
|
|
037463 |
+ rd.nextBytes(c);
|
|
|
037463 |
+ try {
|
|
|
037463 |
+ Thread.sleep(1000);
|
|
|
037463 |
+ } catch (InterruptedException e) {
|
|
|
037463 |
+ e.printStackTrace();
|
|
|
037463 |
+ }
|
|
|
037463 |
+ resp.getOutputStream().write(c);
|
|
|
037463 |
+ }
|
|
|
037463 |
+ }
|
|
|
037463 |
+
|
|
|
037463 |
+ }
|
|
|
037463 |
+
|
|
|
037463 |
+ private static final class RequestExecutor implements Runnable {
|
|
|
037463 |
+ private final String url;
|
|
|
037463 |
+ private final CountDownLatch latch;
|
|
|
037463 |
+ private final List<Throwable> exceptions;
|
|
|
037463 |
+
|
|
|
037463 |
+ RequestExecutor(String url, CountDownLatch latch, List<Throwable> exceptions) {
|
|
|
037463 |
+ this.url = url;
|
|
|
037463 |
+ this.latch = latch;
|
|
|
037463 |
+ this.exceptions = exceptions;
|
|
|
037463 |
+ }
|
|
|
037463 |
+
|
|
|
037463 |
+ @Override
|
|
|
037463 |
+ public void run() {
|
|
|
037463 |
+ try {
|
|
|
037463 |
+ ByteChunk result = new ByteChunk();
|
|
|
037463 |
+ int rc = getUrl(url, result, null);
|
|
|
037463 |
+ Assert.assertEquals(HttpServletResponse.SC_OK, rc);
|
|
|
037463 |
+ Assert.assertEquals(1024, result.getLength());
|
|
|
037463 |
+ } catch (Throwable e) {
|
|
|
037463 |
+ e.printStackTrace();
|
|
|
037463 |
+ exceptions.add(e);
|
|
|
037463 |
+ } finally {
|
|
|
037463 |
+ latch.countDown();
|
|
|
037463 |
+ }
|
|
|
037463 |
+ }
|
|
|
037463 |
+
|
|
|
037463 |
+ }
|
|
|
037463 |
}
|