Issue #3758 - Avoid sending empty trailer frames for http/2 requests.
Added one more test case and comments about handling of `content.isConsumed()` in HTTP/2. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
8f53d14e15
commit
82f7647629
|
@ -740,7 +740,7 @@ public abstract class HttpSender implements AsyncContentProvider.Listener
|
|||
}
|
||||
else
|
||||
{
|
||||
// Was any content sent while committing ?
|
||||
// Was any content sent while committing?
|
||||
ByteBuffer contentBuffer = content.getContent();
|
||||
if (contentBuffer != null)
|
||||
{
|
||||
|
|
|
@ -94,8 +94,8 @@ public class HttpSenderOverHTTP extends HttpSender
|
|||
}
|
||||
case NEED_CHUNK_TRAILER:
|
||||
{
|
||||
callback.succeeded();
|
||||
return;
|
||||
chunk = bufferPool.acquire(httpClient.getRequestBufferSize(), false);
|
||||
break;
|
||||
}
|
||||
case FLUSH:
|
||||
{
|
||||
|
|
|
@ -133,6 +133,9 @@ public class HttpSenderOverHTTP2 extends HttpSender
|
|||
{
|
||||
if (content.isConsumed())
|
||||
{
|
||||
// The superclass calls sendContent() one more time after the last content.
|
||||
// This is necessary for HTTP/1.1 to generate the terminal chunk (with trailers),
|
||||
// but it's not necessary for HTTP/2 so we just succeed the callback.
|
||||
callback.succeeded();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -139,4 +139,52 @@ public class RequestTrailersTest extends AbstractTest
|
|||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyTrailersWithEmptyDeferredContent() throws Exception
|
||||
{
|
||||
start(new ServerSessionListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
return new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame dataFrame, Callback callback)
|
||||
{
|
||||
callback.succeeded();
|
||||
// We should not receive an empty HEADERS frame for the
|
||||
// trailers, but instead a DATA frame with endStream=true.
|
||||
if (dataFrame.isEndStream())
|
||||
{
|
||||
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
|
||||
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, true);
|
||||
stream.headers(responseFrame, Callback.NOOP);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
HttpRequest request = (HttpRequest)client.newRequest("localhost", connector.getLocalPort());
|
||||
HttpFields trailers = new HttpFields();
|
||||
request.trailers(() -> trailers);
|
||||
DeferredContentProvider content = new DeferredContentProvider();
|
||||
request.content(content);
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
request.send(result ->
|
||||
{
|
||||
assertTrue(result.isSucceeded());
|
||||
assertEquals(HttpStatus.OK_200, result.getResponse().getStatus());
|
||||
latch.countDown();
|
||||
});
|
||||
|
||||
// Send deferred content after a while.
|
||||
Thread.sleep(1000);
|
||||
content.close();
|
||||
|
||||
assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue