Blame SOURCES/tomcat-7.0.69-CVE-2016-8745.patch

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
 }