From 231c282685d1fa9945f577e845a18d18bcabe5b1 Mon Sep 17 00:00:00 2001 From: Mark Thomas Date: Fri, 4 Aug 2023 19:11:04 +0100 Subject: [PATCH] Fix regression in fix for BZ 66841 --- java/org/apache/coyote/AsyncStateMachine.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/java/org/apache/coyote/AsyncStateMachine.java b/java/org/apache/coyote/AsyncStateMachine.java index 81fa1fed12bb..04270925a36c 100644 --- a/java/org/apache/coyote/AsyncStateMachine.java +++ b/java/org/apache/coyote/AsyncStateMachine.java @@ -183,13 +183,14 @@ boolean isCompleting() { */ private final AtomicLong generation = new AtomicLong(0); /* - * Error processing should only be triggered once per async generation. This field tracks the last generation of - * async processing for which error processing was triggered and is used to ensure that the second and subsequent + * Error processing should only be triggered once per async generation. These fields track the last generation of + * async processing for which error processing was triggered and are used to ensure that the second and subsequent * attempts to trigger async error processing for a given generation are NO-OPs. * * Guarded by this */ private long lastErrorGeneration = -1; + private long lastErrorGenerationMust = -1; // Need this to fire listener on complete private AsyncContextCallback asyncCtxt = null; @@ -421,14 +422,25 @@ synchronized void asyncDispatched() { synchronized boolean asyncError() { - // Ensure this is only processed once per generation. + Request request = processor.getRequest(); + boolean containerThread = (request != null && request.isRequestThread()); + + // Ensure the error processing is only started once per generation if (lastErrorGeneration == getCurrentGeneration()) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("asyncStateMachine.asyncError.skip")); + if (state == AsyncState.MUST_ERROR && containerThread && lastErrorGenerationMust != getCurrentGeneration()) { + // This is the first container thread call after state was set to MUST_ERROR so don't skip + lastErrorGenerationMust = getCurrentGeneration(); + } else { + // Duplicate call. Skip. + if (log.isDebugEnabled()) { + log.debug(sm.getString("asyncStateMachine.asyncError.skip")); + } + return false; } - return false; + } else { + // First call for this generation, don't skip. + lastErrorGeneration = getCurrentGeneration(); } - lastErrorGeneration = getCurrentGeneration(); if (log.isDebugEnabled()) { log.debug(sm.getString("asyncStateMachine.asyncError.start")); @@ -447,8 +459,8 @@ synchronized boolean asyncError() { updateState(AsyncState.ERROR); } - Request request = processor.getRequest(); - return request == null || !request.isRequestThread(); + // Return true for non-container threads to trigger a dispatch + return !containerThread; }