Issue #2871 - Server reads -1 after client resets HTTP/2 stream.

Backported to jetty-9.3.x branch.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2018-08-31 19:07:57 +02:00
parent 05d4049d46
commit 831b684300
2 changed files with 61 additions and 10 deletions

View File

@ -689,4 +689,50 @@ public class StreamResetTest extends AbstractTest
Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS));
}
@Test
public void testResetBeforeBlockingRead() throws Exception
{
CountDownLatch requestLatch = new CountDownLatch(1);
CountDownLatch readLatch = new CountDownLatch(1);
CountDownLatch failureLatch = new CountDownLatch(1);
start(new HttpServlet()
{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException
{
try
{
requestLatch.countDown();
readLatch.await();
// Attempt to read after reset must throw.
request.getInputStream().read();
}
catch (InterruptedException x)
{
throw new InterruptedIOException();
}
catch (IOException expected)
{
failureLatch.countDown();
}
}
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
HeadersFrame frame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(frame, promise, new Stream.Listener.Adapter());
Stream stream = promise.get(5, TimeUnit.SECONDS);
ByteBuffer content = ByteBuffer.wrap(new byte[1024]);
stream.data(new DataFrame(stream.getId(), content, true), Callback.NOOP);
Assert.assertTrue(requestLatch.await(5, TimeUnit.SECONDS));
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
// Wait for the reset to arrive to the server and be processed.
Thread.sleep(1000);
// Try to read on server.
readLatch.countDown();
// Read on server should fail.
Assert.assertTrue(failureLatch.await(5, TimeUnit.SECONDS));
}
}

View File

@ -242,20 +242,25 @@ public class HttpInput extends ServletInputStream implements Runnable
if (LOG.isDebugEnabled())
LOG.debug("{} consumed {}", this, content);
if (content == EOF_CONTENT)
if (!isError())
{
if (_listener == null)
_state = EOF;
else
if (content == EOF_CONTENT)
{
_state = AEOF;
boolean woken = _channelState.onReadReady(); // force callback?
if (woken)
wake();
if (_listener == null)
_state = EOF;
else
{
_state = AEOF;
boolean woken = _channelState.onReadReady(); // force callback?
if (woken)
wake();
}
}
else if (content == EARLY_EOF_CONTENT)
{
_state = EARLY_EOF;
}
}
else if (content == EARLY_EOF_CONTENT)
_state = EARLY_EOF;
content = _inputQ.peek();
}