Issue #6728 - QUIC and HTTP/3

- Made HttpChannelOverHTTP3.needContent() to look for content if none is immediately available.
- Improved javadocs.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2021-10-28 16:16:51 +02:00
parent 23111b744f
commit dc5ffe1a8e
3 changed files with 60 additions and 30 deletions

View File

@ -174,6 +174,14 @@ public class HttpChannelOverHTTP3 extends HttpChannel
public boolean onIdleTimeout(Throwable failure, Consumer<Runnable> consumer) public boolean onIdleTimeout(Throwable failure, Consumer<Runnable> consumer)
{ {
try (AutoLock l = lock.lock())
{
if (content == null)
content = new HttpInput.ErrorContent(failure);
else
return false;
}
boolean delayed = delayedUntilContent; boolean delayed = delayedUntilContent;
delayedUntilContent = false; delayedUntilContent = false;
@ -185,12 +193,6 @@ public class HttpChannelOverHTTP3 extends HttpChannel
failure.addSuppressed(new Throwable("idle timeout")); failure.addSuppressed(new Throwable("idle timeout"));
try (AutoLock l = lock.lock())
{
if (content == null)
content = new HttpInput.ErrorContent(failure);
}
boolean needed = getRequest().getHttpInput().onContentProducible(); boolean needed = getRequest().getHttpInput().onContentProducible();
if (needed || delayed) if (needed || delayed)
{ {
@ -225,8 +227,28 @@ public class HttpChannelOverHTTP3 extends HttpChannel
try (AutoLock l = lock.lock()) try (AutoLock l = lock.lock())
{ {
if (content != null) if (content != null)
{
if (LOG.isDebugEnabled())
LOG.debug("need content has immediate content {} on {}", content, this);
return true; return true;
}
} }
Stream.Data data = stream.readData();
if (data != null)
{
HttpInput.Content result = newContent(data);
try (AutoLock l = lock.lock())
{
if (LOG.isDebugEnabled())
LOG.debug("need content read content {} on {}", result, this);
content = result;
}
return true;
}
if (LOG.isDebugEnabled())
LOG.debug("need content demanding content on {}", this);
stream.demand(); stream.demand();
return false; return false;
} }
@ -254,26 +276,7 @@ public class HttpChannelOverHTTP3 extends HttpChannel
if (data == null) if (data == null)
return null; return null;
result = new HttpInput.Content(data.getByteBuffer()) result = newContent(data);
{
@Override
public boolean isEof()
{
return data.isLast();
}
@Override
public void succeeded()
{
data.complete();
}
@Override
public void failed(Throwable x)
{
data.complete();
}
};
try (AutoLock l = lock.lock()) try (AutoLock l = lock.lock())
{ {
content = result; content = result;
@ -303,6 +306,30 @@ public class HttpChannelOverHTTP3 extends HttpChannel
return result; return result;
} }
private HttpInput.Content newContent(Stream.Data data)
{
return new HttpInput.Content(data.getByteBuffer())
{
@Override
public boolean isEof()
{
return data.isLast();
}
@Override
public void succeeded()
{
data.complete();
}
@Override
public void failed(Throwable x)
{
data.complete();
}
};
}
@Override @Override
public boolean failAllContent(Throwable failure) public boolean failAllContent(Throwable failure)
{ {

View File

@ -171,6 +171,8 @@ class BlockingContentProducer implements ContentProducer
boolean unready = _asyncContentProducer.isUnready(); boolean unready = _asyncContentProducer.isUnready();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("onContentProducible releasing semaphore {} unready={}", _semaphore, unready); LOG.debug("onContentProducible releasing semaphore {} unready={}", _semaphore, unready);
// Do not release the semaphore if we are not unready, as certain protocols may call this method
// just after having received the request, not only when they have read all the available content.
if (unready) if (unready)
_semaphore.release(); _semaphore.release();
return false; return false;

View File

@ -140,10 +140,11 @@ public abstract class HttpChannel implements Runnable, HttpOutput.Interceptor
/** /**
* Notify the channel that content is needed. If some content is immediately available, true is returned and * Notify the channel that content is needed. If some content is immediately available, true is returned and
* {@link #produceContent()} has to be called and will return a non-null object. * {@link #produceContent()} has to be called and will return a non-null object.
* If no content is immediately available, {@link HttpInput#onContentProducible()} is called once some content arrives * If no content is immediately available, an attempt to produce content must be made; if new content has been
* and {@link #produceContent()} can be called without returning null. * produced, true is returned; otherwise {@link HttpInput#onContentProducible()} is called once some content
* If a failure happens, then {@link HttpInput#onContentProducible()} will be called and an error content will return the * arrives and {@link #produceContent()} can be called without returning {@code null}.
* error on the next call to {@link #produceContent()}. * If a failure happens, then {@link HttpInput#onContentProducible()} will be called and an error content will
* return the error on the next call to {@link #produceContent()}.
* @return true if content is immediately available. * @return true if content is immediately available.
*/ */
public abstract boolean needContent(); public abstract boolean needContent();