You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2019/10/15 20:40:27 UTC

[tomcat] branch 8.5.x updated (0495f66 -> 6e1b6a9)

This is an automated email from the ASF dual-hosted git repository.

markt pushed a change to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git.


    from 0495f66  Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=63816 async errors
     new 7c0a689  Expand test for https://bz.apache.org/bugzilla/show_bug.cgi?id=63816
     new eb9ca41  Refactor
     new 29bf1c5  Refactor
     new a6b3d5b  Remove an illegal state transition
     new 6e1b6a9  Hack to fix failing test

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 java/org/apache/coyote/AbstractProcessor.java      |   6 +-
 java/org/apache/coyote/AsyncStateMachine.java      |  31 +-
 .../apache/catalina/core/TestAsyncContextImpl.java |   7 +-
 .../core/TestAsyncContextStateChanges.java         | 327 +++++++++++++++++++++
 webapps/docs/changelog.xml                         |   6 +-
 5 files changed, 350 insertions(+), 27 deletions(-)
 create mode 100644 test/org/apache/catalina/core/TestAsyncContextStateChanges.java


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 03/05: Refactor

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 29bf1c53fa58fda3f76e94f2bea5e05c3a1eb0e2
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Oct 15 21:16:11 2019 +0100

    Refactor
---
 java/org/apache/coyote/AsyncStateMachine.java | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/java/org/apache/coyote/AsyncStateMachine.java b/java/org/apache/coyote/AsyncStateMachine.java
index b48bec9..3fffbcb 100644
--- a/java/org/apache/coyote/AsyncStateMachine.java
+++ b/java/org/apache/coyote/AsyncStateMachine.java
@@ -314,13 +314,8 @@ public class AsyncStateMachine {
         if (!ContainerThreadMarker.isContainerThread() && state == AsyncState.STARTING) {
             state = AsyncState.COMPLETE_PENDING;
             return false;
-        } else {
-            return doComplete();
         }
-    }
-
 
-    private synchronized boolean doComplete() {
         clearNonBlockingListeners();
         boolean triggerDispatch = false;
         if (state == AsyncState.STARTING || state == AsyncState.MUST_ERROR) {
@@ -380,13 +375,8 @@ public class AsyncStateMachine {
         if (!ContainerThreadMarker.isContainerThread() && state == AsyncState.STARTING) {
             state = AsyncState.DISPATCH_PENDING;
             return false;
-        } else {
-            return doDispatch();
         }
-    }
-
 
-    private synchronized boolean doDispatch() {
         clearNonBlockingListeners();
         boolean triggerDispatch = false;
         if (state == AsyncState.STARTING || state == AsyncState.MUST_ERROR) {


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 04/05: Remove an illegal state transition

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit a6b3d5b56fb0f1dff9e481596048f255773ae86a
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Oct 15 21:27:10 2019 +0100

    Remove an illegal state transition
---
 java/org/apache/coyote/AsyncStateMachine.java | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/coyote/AsyncStateMachine.java b/java/org/apache/coyote/AsyncStateMachine.java
index 3fffbcb..1657840 100644
--- a/java/org/apache/coyote/AsyncStateMachine.java
+++ b/java/org/apache/coyote/AsyncStateMachine.java
@@ -322,7 +322,7 @@ public class AsyncStateMachine {
             // Processing is on a container thread so no need to transfer
             // processing to a new container thread
             state = AsyncState.MUST_COMPLETE;
-        } else if (state == AsyncState.STARTED || state == AsyncState.COMPLETE_PENDING) {
+        } else if (state == AsyncState.STARTED) {
             state = AsyncState.COMPLETING;
             // A dispatch to a container thread is always required.
             // If on a non-container thread, need to get back onto a container
@@ -383,7 +383,7 @@ public class AsyncStateMachine {
             // Processing is on a container thread so no need to transfer
             // processing to a new container thread
             state = AsyncState.MUST_DISPATCH;
-        } else if (state == AsyncState.STARTED || state == AsyncState.DISPATCH_PENDING) {
+        } else if (state == AsyncState.STARTED) {
             state = AsyncState.DISPATCHING;
             // A dispatch to a container thread is always required.
             // If on a non-container thread, need to get back onto a container


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 05/05: Hack to fix failing test

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 6e1b6a9a4f358132b57e795170906108b8365311
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Oct 15 21:36:52 2019 +0100

    Hack to fix failing test
---
 .../org/apache/catalina/core/TestAsyncContextStateChanges.java | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/test/org/apache/catalina/core/TestAsyncContextStateChanges.java b/test/org/apache/catalina/core/TestAsyncContextStateChanges.java
index 5df1740..dc1cde9 100644
--- a/test/org/apache/catalina/core/TestAsyncContextStateChanges.java
+++ b/test/org/apache/catalina/core/TestAsyncContextStateChanges.java
@@ -196,6 +196,16 @@ public class TestAsyncContextStateChanges extends TomcatBaseTest {
             if (endTiming == EndTiming.THREAD_AFTER_EXIT) {
                 try {
                     threadLatch.await();
+                    /*
+                     * As much as I dislike it, I don't see any easy way around
+                     * this hack. The latch above is released as the Servlet
+                     * exits but we need to wait for the post processing to
+                     * complete for the test to work as intended. In real-world
+                     * applications this does mean that there is a real chance
+                     * of an ISE. We may need to increase this delay for some CI
+                     * systems.
+                     */
+                    Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     // Ignore
                 }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 01/05: Expand test for https://bz.apache.org/bugzilla/show_bug.cgi?id=63816

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 7c0a689e78512686978a8ce71ca7d4cd2216fa8e
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Oct 15 14:18:26 2019 +0100

    Expand test for https://bz.apache.org/bugzilla/show_bug.cgi?id=63816
    
    Expanded to cover https://bz.apache.org/bugzilla/show_bug.cgi?id=63817
    and additional, similar scenarios. Correct bugs in existing tests.
---
 java/org/apache/coyote/AbstractProcessor.java      |   6 +-
 java/org/apache/coyote/AsyncStateMachine.java      |  11 +-
 .../apache/catalina/core/TestAsyncContextImpl.java |   7 +-
 .../core/TestAsyncContextStateChanges.java         | 317 +++++++++++++++++++++
 webapps/docs/changelog.xml                         |   6 +-
 5 files changed, 334 insertions(+), 13 deletions(-)

diff --git a/java/org/apache/coyote/AbstractProcessor.java b/java/org/apache/coyote/AbstractProcessor.java
index 55a350d..98c79ce 100644
--- a/java/org/apache/coyote/AbstractProcessor.java
+++ b/java/org/apache/coyote/AbstractProcessor.java
@@ -101,7 +101,9 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement
      * @param t The error which occurred
      */
     protected void setErrorState(ErrorState errorState, Throwable t) {
-        response.setError();
+        // Use the return value to avoid processing more than one async error
+        // in a single async cycle.
+        boolean setError = response.setError();
         boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed();
         this.errorState = this.errorState.getMostSevere(errorState);
         // Don't change the status code for IOException since that is almost
@@ -113,7 +115,7 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement
         if (t != null) {
             request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
         }
-        if (blockIo && isAsync()) {
+        if (blockIo && isAsync() && setError) {
             if (asyncStateMachine.asyncError()) {
                 processSocketEvent(SocketEvent.ERROR, true);
             }
diff --git a/java/org/apache/coyote/AsyncStateMachine.java b/java/org/apache/coyote/AsyncStateMachine.java
index 81a883b..5d0e4e5 100644
--- a/java/org/apache/coyote/AsyncStateMachine.java
+++ b/java/org/apache/coyote/AsyncStateMachine.java
@@ -154,6 +154,7 @@ public class AsyncStateMachine {
         DISPATCH_PENDING(true,  true,  false, false),
         DISPATCHING     (true,  false, false, true),
         READ_WRITE_OP   (true,  true,  false, false),
+        MUST_ERROR      (true,  true,  false, false),
         ERROR           (true,  true,  false, false);
 
         private final boolean isAsync;
@@ -320,7 +321,7 @@ public class AsyncStateMachine {
     private synchronized boolean doComplete() {
         clearNonBlockingListeners();
         boolean triggerDispatch = false;
-        if (state == AsyncState.STARTING) {
+        if (state == AsyncState.STARTING || state == AsyncState.MUST_ERROR) {
             // Processing is on a container thread so no need to transfer
             // processing to a new container thread
             state = AsyncState.MUST_COMPLETE;
@@ -386,7 +387,7 @@ public class AsyncStateMachine {
     private synchronized boolean doDispatch() {
         clearNonBlockingListeners();
         boolean triggerDispatch = false;
-        if (state == AsyncState.STARTING) {
+        if (state == AsyncState.STARTING || state == AsyncState.MUST_ERROR) {
             // Processing is on a container thread so no need to transfer
             // processing to a new container thread
             state = AsyncState.MUST_DISPATCH;
@@ -435,7 +436,11 @@ public class AsyncStateMachine {
 
     public synchronized boolean asyncError() {
         clearNonBlockingListeners();
-        state = AsyncState.ERROR;
+        if (state == AsyncState.STARTING) {
+            state = AsyncState.MUST_ERROR;
+        } else {
+            state = AsyncState.ERROR;
+        }
         return !ContainerThreadMarker.isContainerThread();
     }
 
diff --git a/test/org/apache/catalina/core/TestAsyncContextImpl.java b/test/org/apache/catalina/core/TestAsyncContextImpl.java
index d7afe2d..ccf3228 100644
--- a/test/org/apache/catalina/core/TestAsyncContextImpl.java
+++ b/test/org/apache/catalina/core/TestAsyncContextImpl.java
@@ -851,6 +851,8 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         private final boolean completeOnError;
         private final boolean completeOnTimeout;
         private final String dispatchUrl;
+        // Assumes listener is fired after container thread that initiated async
+        // has exited.
         private boolean asyncStartedCorrect = true;
 
         public TrackingListener(boolean completeOnError,
@@ -1901,7 +1903,6 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
         }
 
         Assert.assertEquals(expectedTrack, getTrack());
-        Assert.assertTrue(bug59219Servlet.isAsyncStartedCorrect());
     }
 
 
@@ -1936,10 +1937,6 @@ public class TestAsyncContextImpl extends TomcatBaseTest {
             } else
                 throw new ServletException();
         }
-
-        public boolean isAsyncStartedCorrect() {
-            return trackingListener.isAsyncStartedCorrect();
-        }
     }
 
     @Test
diff --git a/test/org/apache/catalina/core/TestAsyncContextStateChanges.java b/test/org/apache/catalina/core/TestAsyncContextStateChanges.java
new file mode 100644
index 0000000..5df1740
--- /dev/null
+++ b/test/org/apache/catalina/core/TestAsyncContextStateChanges.java
@@ -0,0 +1,317 @@
+/*
+ *  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.catalina.core;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.TestCoyoteAdapter;
+import org.apache.catalina.startup.SimpleHttpClient;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+
+/*
+ * Derived from a test for https://bz.apache.org/bugzilla/show_bug.cgi?id=63816
+ * Expanded to cover https://bz.apache.org/bugzilla/show_bug.cgi?id=63817 and
+ * additional scenarios.
+ */
+@RunWith(Parameterized.class)
+public class TestAsyncContextStateChanges extends TomcatBaseTest {
+
+    @Parameterized.Parameters(name = "{index}: end [{0}], timing [{1}]")
+    public static Collection<Object[]> parameters() {
+        List<Object[]> parameterSets = new ArrayList<>();
+        for (AsyncEnd asyncEnd : AsyncEnd.values()) {
+            for (EndTiming endTiming : EndTiming.values()) {
+                parameterSets.add(new Object[] { asyncEnd, endTiming });
+            }
+        }
+        return parameterSets;
+    }
+
+    @Parameter(0)
+    public AsyncEnd asyncEnd;
+
+    @Parameter(1)
+    public EndTiming endTiming;
+
+    private ServletRequest servletRequest = null;
+    private AsyncContext asyncContext = null;
+    private AtomicBoolean failed = new AtomicBoolean();
+    private CountDownLatch threadLatch;
+    private CountDownLatch closeLatch;
+    private CountDownLatch endLatch;
+    private boolean dispatch;
+
+    @Test
+    public void testAsync() throws Exception {
+        dispatch = false;
+        servletRequest = null;
+        asyncContext = null;
+
+        // Initialise tracking fields
+        failed.set(true);
+        threadLatch = new CountDownLatch(1);
+        closeLatch = new CountDownLatch(1);
+        endLatch = new CountDownLatch(1);
+
+        // Setup Tomcat instance
+        Tomcat tomcat = getTomcatInstance();
+
+        // No file system docBase required
+        Context ctx = tomcat.addContext("", null);
+
+        AsyncServlet bug63816Servlet = new AsyncServlet();
+        Wrapper wrapper = Tomcat.addServlet(ctx, "bug63816Servlet", bug63816Servlet);
+        wrapper.setAsyncSupported(true);
+        ctx.addServletMappingDecoded("/*", "bug63816Servlet");
+
+        tomcat.start();
+
+        Client client = new Client();
+        client.setPort(getPort());
+        client.setRequest(new String[] { "GET / HTTP/1.1" + SimpleHttpClient.CRLF +
+                                         "Host: localhost:" + SimpleHttpClient.CRLF +
+                                         SimpleHttpClient.CRLF});
+        client.connect();
+        client.sendRequest();
+
+        if (asyncEnd.isError()) {
+            client.disconnect();
+            closeLatch.countDown();
+            try {
+                endLatch.await();
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+        } else {
+            client.setUseContentLength(true);
+            client.readResponse(true);
+        }
+
+        Assert.assertFalse(failed.get());
+    }
+
+
+    private static final class Client extends SimpleHttpClient {
+
+        @Override
+        public boolean isResponseBodyOK() {
+            return true;
+        }
+    }
+
+
+    private final class AsyncServlet extends HttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+                throws ServletException, IOException {
+            if (dispatch) {
+                return;
+            }
+
+            if (!asyncEnd.isError()) {
+                resp.setContentType("text/plain");
+                resp.setCharacterEncoding("UTF-8");
+                resp.setContentLength(2);
+                resp.getWriter().print("OK");
+            }
+
+            servletRequest = req;
+            asyncContext = req.startAsync();
+            asyncContext.addListener(new Listener());
+            asyncContext.setTimeout(1000);
+            Thread t = new NonContainerThread();
+
+            switch (endTiming) {
+                case INLINE: {
+                    t.run();
+                    break;
+                }
+                case THREAD_AFTER_EXIT: {
+                    t.start();
+                    threadLatch.countDown();
+                    break;
+                }
+                case THREAD_BEFORE_EXIT: {
+                    t.start();
+                    try {
+                        threadLatch.await();
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                    endLatch.countDown();
+                    break;
+                }
+            }
+        }
+    }
+
+
+    private final class NonContainerThread extends Thread {
+
+        @Override
+        public void run() {
+            if (endTiming == EndTiming.THREAD_AFTER_EXIT) {
+                try {
+                    threadLatch.await();
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+            }
+
+            // Trigger the error if necessary
+            if (asyncEnd.isError()) {
+                try {
+                    closeLatch.await();
+                } catch (InterruptedException e) {
+                    // Ignore
+                }
+                try {
+                    ServletResponse resp = asyncContext.getResponse();
+                    resp.setContentType("text/plain");
+                    resp.setCharacterEncoding("UTF-8");
+                    OutputStream os = resp.getOutputStream();
+                    resp.setContentType("text/plain");
+                    for (int i = 0; i < 16; i++) {
+                        os.write(TestCoyoteAdapter.TEXT_8K.getBytes(StandardCharsets.UTF_8));
+                    }
+                } catch (IOException e) {
+                    // Expected
+                }
+            }
+
+            try {
+                switch (asyncEnd) {
+                    case COMPLETE:
+                    case ERROR_COMPLETE: {
+                        asyncContext.complete();
+                        break;
+                    }
+                    case DISPATCH:
+                    case ERROR_DISPATCH: {
+                        dispatch = true;
+                        asyncContext.dispatch();
+                        break;
+                    }
+                    case NONE:
+                    case ERROR_NONE: {
+                        break;
+                    }
+                }
+
+                // The request must stay in async mode until doGet() exists
+                if (servletRequest.isAsyncStarted() != (endTiming == EndTiming.THREAD_AFTER_EXIT && !asyncEnd.isNone())) {
+                    failed.set(false);
+                }
+            } finally {
+                if (endTiming == EndTiming.THREAD_BEFORE_EXIT) {
+                    threadLatch.countDown();
+                } else if (endTiming == EndTiming.THREAD_AFTER_EXIT) {
+                    endLatch.countDown();
+                }
+            }
+        }
+    }
+
+
+    private class Listener implements AsyncListener {
+
+        @Override
+        public void onComplete(AsyncEvent event) throws IOException {
+            if (endTiming == EndTiming.INLINE) {
+                endLatch.countDown();
+            }
+        }
+
+        @Override
+        public void onTimeout(AsyncEvent event) throws IOException {
+            // NO-OP
+        }
+
+        @Override
+        public void onError(AsyncEvent event) throws IOException {
+            // NO-OP
+        }
+
+        @Override
+        public void onStartAsync(AsyncEvent event) throws IOException {
+            // NO-OP
+        }
+    }
+
+
+    public enum AsyncEnd {
+
+        NONE          ( true, false),
+        COMPLETE      (false, false),
+        DISPATCH      (false, false),
+        ERROR_NONE    ( true,  true),
+        ERROR_COMPLETE(false,  true),
+        ERROR_DISPATCH(false,  true);
+
+        final boolean none;
+        final boolean error;
+
+        private AsyncEnd(boolean none, boolean error) {
+            this.none = none;
+            this.error = error;
+        }
+
+        public boolean isNone() {
+            return none;
+        }
+
+        public boolean isError() {
+            return error;
+        }
+    }
+
+
+    public enum EndTiming {
+        INLINE,
+        THREAD_BEFORE_EXIT,
+        THREAD_AFTER_EXIT
+    }
+}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index dbcaef7..f3b6a80 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -63,9 +63,9 @@
         <code>AsyncListener.onError()</code>. (markt)
       </fix>
       <fix>
-        <bug>63816</bug>: Correctly handle I/O errors on a non-container thread
-        after asynchronous processing has been started but before the container
-        thread that started asynchronous processing has completed processing the
+        <bug>63816</bug> and <bug>63817</bug>: Correctly handle I/O errors after
+        asynchronous processing has been started but before the container thread
+        that started asynchronous processing has completed processing the
         current request/response. (markt)
       </fix>
     </changelog>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 02/05: Refactor

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit eb9ca417184edc90bcbb51a817e83e7dc8781674
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Tue Oct 15 21:14:25 2019 +0100

    Refactor
---
 java/org/apache/coyote/AsyncStateMachine.java | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/coyote/AsyncStateMachine.java b/java/org/apache/coyote/AsyncStateMachine.java
index 5d0e4e5..b48bec9 100644
--- a/java/org/apache/coyote/AsyncStateMachine.java
+++ b/java/org/apache/coyote/AsyncStateMachine.java
@@ -278,10 +278,12 @@ public class AsyncStateMachine {
      */
     public synchronized SocketState asyncPostProcess() {
         if (state == AsyncState.COMPLETE_PENDING) {
-            doComplete();
+            clearNonBlockingListeners();
+            state = AsyncState.COMPLETING;
             return SocketState.ASYNC_END;
         } else if (state == AsyncState.DISPATCH_PENDING) {
-            doDispatch();
+            clearNonBlockingListeners();
+            state = AsyncState.DISPATCHING;
             return SocketState.ASYNC_END;
         } else  if (state == AsyncState.STARTING || state == AsyncState.READ_WRITE_OP) {
             state = AsyncState.STARTED;


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org