Issue #6728 - QUIC and HTTP/3
- Made BlockingContentProducer.onContentProducible() idempotent by checking if the input is unready before releasing the semaphore. This is necessary because HTTP/3 will call onContentProducible() just after receiving the request, while other protocols assume that content is producible and only call onContentProducible() when they read all the available content. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
baab1a15b9
commit
23111b744f
|
@ -312,6 +312,11 @@ class AsyncContentProducer implements ContentProducer
|
|||
return false;
|
||||
}
|
||||
|
||||
boolean isUnready()
|
||||
{
|
||||
return _httpChannel.getState().isInputUnready();
|
||||
}
|
||||
|
||||
private HttpInput.Content nextTransformedContent()
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
|
|
|
@ -160,17 +160,19 @@ class BlockingContentProducer implements ContentProducer
|
|||
{
|
||||
_semaphore.assertLocked();
|
||||
// In blocking mode, the dispatched thread normally does not have to be rescheduled as it is normally in state
|
||||
// DISPATCHED blocked on the semaphore that just needs to be released for the dispatched thread to resume. This is why
|
||||
// this method always returns false.
|
||||
// DISPATCHED blocked on the semaphore that just needs to be released for the dispatched thread to resume.
|
||||
// This is why this method always returns false.
|
||||
// But async errors can occur while the dispatched thread is NOT blocked reading (i.e.: in state WAITING),
|
||||
// so the WAITING to WOKEN transition must be done by the error-notifying thread which then has to reschedule the
|
||||
// dispatched thread after HttpChannelState.asyncError() is called.
|
||||
// Calling _asyncContentProducer.wakeup() changes the channel state from WAITING to WOKEN which would prevent the
|
||||
// subsequent call to HttpChannelState.asyncError() from rescheduling the thread.
|
||||
// so the WAITING to WOKEN transition must be done by the error-notifying thread which then has to reschedule
|
||||
// the dispatched thread after HttpChannelState.asyncError() is called.
|
||||
// Calling _asyncContentProducer.onContentProducible() changes the channel state from WAITING to WOKEN which
|
||||
// would prevent the subsequent call to HttpChannelState.asyncError() from rescheduling the thread.
|
||||
// AsyncServletTest.testStartAsyncThenClientStreamIdleTimeout() tests this.
|
||||
boolean unready = _asyncContentProducer.isUnready();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onContentProducible releasing semaphore {}", _semaphore);
|
||||
_semaphore.release();
|
||||
LOG.debug("onContentProducible releasing semaphore {} unready={}", _semaphore, unready);
|
||||
if (unready)
|
||||
_semaphore.release();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1361,6 +1361,14 @@ public class HttpChannelState
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isInputUnready()
|
||||
{
|
||||
try (AutoLock l = lock())
|
||||
{
|
||||
return _inputState == InputState.UNREADY;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onWritePossible()
|
||||
{
|
||||
boolean wake = false;
|
||||
|
|
Loading…
Reference in New Issue