Fix #6227 Async timeout dispatch race (#6228)

Fix #6227 Async timeout dispatch race
Only allow the thread calling onTimeout to call dispatch and complete once timeout has expired.
Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2021-05-04 14:18:48 +10:00 committed by GitHub
parent 2f19c67b41
commit ad6d23fc68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 41 additions and 20 deletions

View File

@ -155,6 +155,7 @@ public class HttpChannelState
private boolean _asyncWritePossible;
private long _timeoutMs = DEFAULT_TIMEOUT;
private AsyncContextEvent _event;
private Thread _onTimeoutThread;
protected HttpChannelState(HttpChannel channel)
{
@ -582,7 +583,10 @@ public class HttpChannelState
switch (_requestState)
{
case ASYNC:
break;
case EXPIRING:
if (Thread.currentThread() != _onTimeoutThread)
throw new IllegalStateException(this.getStatusStringLocked());
break;
default:
throw new IllegalStateException(this.getStatusStringLocked());
@ -646,36 +650,47 @@ public class HttpChannelState
throw new IllegalStateException(toStringLocked());
event = _event;
listeners = _asyncListeners;
_onTimeoutThread = Thread.currentThread();
}
if (listeners != null)
try
{
Runnable task = new Runnable()
if (listeners != null)
{
@Override
public void run()
Runnable task = new Runnable()
{
for (AsyncListener listener : listeners)
@Override
public void run()
{
try
for (AsyncListener listener : listeners)
{
listener.onTimeout(event);
}
catch (Throwable x)
{
LOG.warn("{} while invoking onTimeout listener {}", x, listener, x);
try
{
listener.onTimeout(event);
}
catch (Throwable x)
{
LOG.warn("{} while invoking onTimeout listener {}", x, listener, x);
}
}
}
}
@Override
public String toString()
{
return "onTimeout";
}
};
@Override
public String toString()
{
return "onTimeout";
}
};
runInContext(event, task);
runInContext(event, task);
}
}
finally
{
synchronized (this)
{
_onTimeoutThread = null;
}
}
}
@ -692,6 +707,11 @@ public class HttpChannelState
switch (_requestState)
{
case EXPIRING:
if (Thread.currentThread() != _onTimeoutThread)
throw new IllegalStateException(this.getStatusStringLocked());
_requestState = _sendError ? RequestState.BLOCKING : RequestState.COMPLETE;
break;
case ASYNC:
_requestState = _sendError ? RequestState.BLOCKING : RequestState.COMPLETE;
break;

View File

@ -235,7 +235,8 @@ public class QoSFilter implements Filter
}
catch (IllegalStateException x)
{
LOG.warn(x);
if (LOG.isDebugEnabled())
LOG.debug(x);
continue;
}
}