Fixes #755 - NPE in HttpChannelOverHTTP2.requestContent().

Fixed by recycling only channels that have completed normally by
having read the request content and responded.

Channels that don't read the request content won't be recycled, thus
avoiding the NPE.
This commit is contained in:
Simone Bordet 2016-07-21 16:36:28 +02:00
parent f8d81e9eeb
commit 78d27c9a28
3 changed files with 28 additions and 12 deletions

View File

@ -204,6 +204,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
@Override
public void recycle()
{
getStream().removeAttribute(IStream.CHANNEL_ATTRIBUTE);
super.recycle();
channels.offer(this);
}
@ -212,6 +213,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
public void onCompleted()
{
super.onCompleted();
if (!getStream().isReset())
recycle();
}
@ -219,11 +221,12 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
public void reject()
{
IStream stream = getStream();
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 Request #{}/{} rejected", stream.getId(), Integer.toHexString(stream.getSession().hashCode()));
stream.reset(new ResetFrame(stream.getId(), ErrorCode.ENHANCE_YOUR_CALM_ERROR.code), Callback.NOOP);
// Consume the existing queued data frames to
// avoid stalling the session flow control.
getHttpTransport().consumeInput();
recycle();
consumeInput();
}
}
}

View File

@ -191,6 +191,17 @@ public class HttpChannelOverHTTP2 extends HttpChannel
public Runnable requestContent(DataFrame frame, final Callback callback)
{
Stream stream = getStream();
if (stream.isReset())
{
// Consume previously queued content to
// enlarge the session flow control window.
consumeInput();
// Consume immediately this content.
callback.succeeded();
return null;
}
// We must copy the data since we do not know when the
// application will consume the bytes (we queue them by
// calling onContent()), and the parsing will continue
@ -233,7 +244,6 @@ public class HttpChannelOverHTTP2 extends HttpChannel
if (LOG.isDebugEnabled())
{
Stream stream = getStream();
LOG.debug("HTTP2 Request #{}/{}: {} bytes of {} content, handle: {}",
stream.getId(),
Integer.toHexString(stream.getSession().hashCode()),
@ -248,6 +258,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel
return handle || delayed ? this : null;
}
protected void consumeInput()
{
getRequest().getHttpInput().consumeAll();
}
/**
* If the associated response has the Expect header set to 100 Continue,
* then accessing the input stream indicates that the handler/servlet

View File

@ -31,7 +31,6 @@ import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Callback;
@ -193,17 +192,16 @@ public class HttpTransportOverHTTP2 implements HttpTransport
// If the stream is not closed, it is still reading the request content.
// Send a reset to the other end so that it stops sending data.
if (!stream.isClosed())
{
if (LOG.isDebugEnabled())
LOG.debug("HTTP2 Response #{}: unconsumed request content, resetting stream", stream.getId());
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
}
// Consume the existing queued data frames to
// avoid stalling the session flow control.
consumeInput();
}
protected void consumeInput()
{
HttpChannel channel = (HttpChannel)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
channel.getRequest().getHttpInput().consumeAll();
HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2)stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
channel.consumeInput();
}
@Override