Merged branch 'jetty-9.4.x' into 'master'.
This commit is contained in:
commit
a116fd05a2
|
@ -46,6 +46,8 @@ import org.eclipse.jetty.http.HttpVersion;
|
||||||
import org.eclipse.jetty.http.MetaData;
|
import org.eclipse.jetty.http.MetaData;
|
||||||
import org.eclipse.jetty.http2.ErrorCode;
|
import org.eclipse.jetty.http2.ErrorCode;
|
||||||
import org.eclipse.jetty.http2.FlowControlStrategy;
|
import org.eclipse.jetty.http2.FlowControlStrategy;
|
||||||
|
import org.eclipse.jetty.http2.HTTP2Flusher;
|
||||||
|
import org.eclipse.jetty.http2.HTTP2Session;
|
||||||
import org.eclipse.jetty.http2.ISession;
|
import org.eclipse.jetty.http2.ISession;
|
||||||
import org.eclipse.jetty.http2.IStream;
|
import org.eclipse.jetty.http2.IStream;
|
||||||
import org.eclipse.jetty.http2.api.Session;
|
import org.eclipse.jetty.http2.api.Session;
|
||||||
|
@ -54,6 +56,7 @@ import org.eclipse.jetty.http2.api.server.ServerSessionListener;
|
||||||
import org.eclipse.jetty.http2.frames.DataFrame;
|
import org.eclipse.jetty.http2.frames.DataFrame;
|
||||||
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
import org.eclipse.jetty.http2.frames.HeadersFrame;
|
||||||
import org.eclipse.jetty.http2.frames.ResetFrame;
|
import org.eclipse.jetty.http2.frames.ResetFrame;
|
||||||
|
import org.eclipse.jetty.http2.server.AbstractHTTP2ServerConnectionFactory;
|
||||||
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
||||||
import org.eclipse.jetty.server.HttpChannel;
|
import org.eclipse.jetty.server.HttpChannel;
|
||||||
import org.eclipse.jetty.server.HttpConfiguration;
|
import org.eclipse.jetty.server.HttpConfiguration;
|
||||||
|
@ -631,6 +634,55 @@ public class StreamResetTest extends AbstractTest
|
||||||
Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS));
|
Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResetAfterBlockingWrite() throws Exception
|
||||||
|
{
|
||||||
|
int windowSize = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
|
||||||
|
CountDownLatch writeLatch = new CountDownLatch(1);
|
||||||
|
start(new HttpServlet()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ServletOutputStream output = response.getOutputStream();
|
||||||
|
output.write(new byte[10 * windowSize]);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
writeLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
AtomicLong received = new AtomicLong();
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
Session client = newClient(new Session.Listener.Adapter());
|
||||||
|
MetaData.Request request = newRequest("GET", new HttpFields());
|
||||||
|
HeadersFrame frame = new HeadersFrame(request, null, true);
|
||||||
|
FuturePromise<Stream> promise = new FuturePromise<>();
|
||||||
|
client.newStream(frame, promise, new Stream.Listener.Adapter()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||||
|
{
|
||||||
|
if (received.addAndGet(frame.getData().remaining()) == windowSize)
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Stream stream = promise.get(5, TimeUnit.SECONDS);
|
||||||
|
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
// Reset.
|
||||||
|
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
|
||||||
|
Assert.assertTrue(writeLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
HTTP2Session session = connector.getConnectionFactory(AbstractHTTP2ServerConnectionFactory.class).getBean(HTTP2Session.class);
|
||||||
|
HTTP2Flusher flusher = session.getBean(HTTP2Flusher.class);
|
||||||
|
Assert.assertEquals(0, flusher.getFrameQueueSize());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResetAfterAsyncRequestAsyncWriteStalledByFlowControl() throws Exception
|
public void testResetAfterAsyncRequestAsyncWriteStalledByFlowControl() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,6 +74,7 @@ public abstract class AbstractFlowControlStrategy implements FlowControlStrategy
|
||||||
@Override
|
@Override
|
||||||
public void onStreamDestroyed(IStream stream)
|
public void onStreamDestroyed(IStream stream)
|
||||||
{
|
{
|
||||||
|
streamsStalls.remove(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.http2;
|
package org.eclipse.jetty.http2;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -31,10 +32,12 @@ import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.EofException;
|
import org.eclipse.jetty.io.EofException;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.IteratingCallback;
|
import org.eclipse.jetty.util.IteratingCallback;
|
||||||
|
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
|
import org.eclipse.jetty.util.component.Dumpable;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
public class HTTP2Flusher extends IteratingCallback
|
public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(HTTP2Flusher.class);
|
private static final Logger LOG = Log.getLogger(HTTP2Flusher.class);
|
||||||
|
|
||||||
|
@ -105,7 +108,15 @@ public class HTTP2Flusher extends IteratingCallback
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getQueueSize()
|
private int getWindowQueueSize()
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
return windows.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFrameQueueSize()
|
||||||
{
|
{
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
|
@ -130,15 +141,12 @@ public class HTTP2Flusher extends IteratingCallback
|
||||||
entry.perform();
|
entry.perform();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!frames.isEmpty())
|
for (Entry entry : frames)
|
||||||
{
|
{
|
||||||
for (Entry entry : frames)
|
entries.offer(entry);
|
||||||
{
|
actives.add(entry);
|
||||||
entries.offer(entry);
|
|
||||||
actives.add(entry);
|
|
||||||
}
|
|
||||||
frames.clear();
|
|
||||||
}
|
}
|
||||||
|
frames.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,11 +163,11 @@ public class HTTP2Flusher extends IteratingCallback
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Processing {}", entry);
|
LOG.debug("Processing {}", entry);
|
||||||
|
|
||||||
// If the stream has been reset, don't send the frame.
|
// If the stream has been reset or removed, don't send the frame.
|
||||||
if (entry.reset())
|
if (entry.isStale())
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Resetting {}", entry);
|
LOG.debug("Stale {}", entry);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,11 +299,32 @@ public class HTTP2Flusher extends IteratingCallback
|
||||||
entry.failed(failure);
|
entry.failed(failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String dump()
|
||||||
|
{
|
||||||
|
return ContainerLifeCycle.dump(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dump(Appendable out, String indent) throws IOException
|
||||||
|
{
|
||||||
|
out.append(toString()).append(System.lineSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("%s[window_queue=%d,frame_queue=%d,actives=%d]",
|
||||||
|
super.toString(),
|
||||||
|
getWindowQueueSize(),
|
||||||
|
getFrameQueueSize(),
|
||||||
|
actives.size());
|
||||||
|
}
|
||||||
|
|
||||||
public static abstract class Entry extends Callback.Nested
|
public static abstract class Entry extends Callback.Nested
|
||||||
{
|
{
|
||||||
protected final Frame frame;
|
protected final Frame frame;
|
||||||
protected final IStream stream;
|
protected final IStream stream;
|
||||||
private boolean reset;
|
|
||||||
|
|
||||||
protected Entry(Frame frame, IStream stream, Callback callback)
|
protected Entry(Frame frame, IStream stream, Callback callback)
|
||||||
{
|
{
|
||||||
|
@ -313,7 +342,7 @@ public class HTTP2Flusher extends IteratingCallback
|
||||||
|
|
||||||
private void complete()
|
private void complete()
|
||||||
{
|
{
|
||||||
if (reset)
|
if (isStale())
|
||||||
failed(new EofException("reset"));
|
failed(new EofException("reset"));
|
||||||
else
|
else
|
||||||
succeeded();
|
succeeded();
|
||||||
|
@ -330,23 +359,31 @@ public class HTTP2Flusher extends IteratingCallback
|
||||||
super.failed(x);
|
super.failed(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean reset()
|
private boolean isStale()
|
||||||
{
|
{
|
||||||
return this.reset = stream != null && stream.isReset() && !isProtocol();
|
return !isProtocol() && stream != null && stream.isReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isProtocol()
|
private boolean isProtocol()
|
||||||
{
|
{
|
||||||
switch (frame.getType())
|
switch (frame.getType())
|
||||||
{
|
{
|
||||||
|
case DATA:
|
||||||
|
case HEADERS:
|
||||||
|
case PUSH_PROMISE:
|
||||||
|
case CONTINUATION:
|
||||||
|
return false;
|
||||||
case PRIORITY:
|
case PRIORITY:
|
||||||
case RST_STREAM:
|
case RST_STREAM:
|
||||||
|
case SETTINGS:
|
||||||
|
case PING:
|
||||||
case GO_AWAY:
|
case GO_AWAY:
|
||||||
case WINDOW_UPDATE:
|
case WINDOW_UPDATE:
|
||||||
|
case PREFACE:
|
||||||
case DISCONNECT:
|
case DISCONNECT:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ import org.eclipse.jetty.util.Promise;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
|
import org.eclipse.jetty.util.component.DumpableCollection;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
|
@ -106,13 +107,8 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
this.recvWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
|
this.recvWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
|
||||||
this.pushEnabled = true; // SPEC: by default, push is enabled.
|
this.pushEnabled = true; // SPEC: by default, push is enabled.
|
||||||
this.idleTime = System.nanoTime();
|
this.idleTime = System.nanoTime();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doStart() throws Exception
|
|
||||||
{
|
|
||||||
addBean(flowControl);
|
addBean(flowControl);
|
||||||
super.doStart();
|
addBean(flusher);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -286,7 +282,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
|
|
||||||
IStream stream = getStream(frame.getStreamId());
|
IStream stream = getStream(frame.getStreamId());
|
||||||
if (stream != null)
|
if (stream != null)
|
||||||
stream.process(frame, Callback.NOOP);
|
stream.process(frame, new ResetCallback());
|
||||||
else
|
else
|
||||||
notifyReset(this, frame);
|
notifyReset(this, frame);
|
||||||
}
|
}
|
||||||
|
@ -547,7 +543,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
flusher.iterate();
|
flusher.iterate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void settings(SettingsFrame frame, Callback callback)
|
public void settings(SettingsFrame frame, Callback callback)
|
||||||
{
|
{
|
||||||
|
@ -758,8 +753,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
IStream removed = streams.remove(stream.getId());
|
IStream removed = streams.remove(stream.getId());
|
||||||
if (removed != null)
|
if (removed != null)
|
||||||
{
|
{
|
||||||
assert removed == stream;
|
|
||||||
|
|
||||||
boolean local = stream.isLocal();
|
boolean local = stream.isLocal();
|
||||||
if (local)
|
if (local)
|
||||||
localStreamCount.decrementAndGet();
|
localStreamCount.decrementAndGet();
|
||||||
|
@ -1115,15 +1108,21 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dump(Appendable out, String indent) throws IOException
|
||||||
|
{
|
||||||
|
super.dump(out, indent);
|
||||||
|
dump(out, indent, Collections.singleton(new DumpableCollection("streams", streams.values())));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return String.format("%s@%x{l:%s <-> r:%s,queueSize=%d,sendWindow=%s,recvWindow=%s,streams=%d,%s}",
|
return String.format("%s@%x{l:%s <-> r:%s,sendWindow=%s,recvWindow=%s,streams=%d,%s}",
|
||||||
getClass().getSimpleName(),
|
getClass().getSimpleName(),
|
||||||
hashCode(),
|
hashCode(),
|
||||||
getEndPoint().getLocalAddress(),
|
getEndPoint().getLocalAddress(),
|
||||||
getEndPoint().getRemoteAddress(),
|
getEndPoint().getRemoteAddress(),
|
||||||
flusher.getQueueSize(),
|
|
||||||
sendWindow,
|
sendWindow,
|
||||||
recvWindow,
|
recvWindow,
|
||||||
streams.size(),
|
streams.size(),
|
||||||
|
@ -1328,6 +1327,32 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ResetCallback implements Callback
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void succeeded()
|
||||||
|
{
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failed(Throwable x)
|
||||||
|
{
|
||||||
|
complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InvocationType getInvocationType()
|
||||||
|
{
|
||||||
|
return InvocationType.NON_BLOCKING;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void complete()
|
||||||
|
{
|
||||||
|
flusher.iterate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class CloseCallback implements Callback
|
private class CloseCallback implements Callback
|
||||||
{
|
{
|
||||||
private final int error;
|
private final int error;
|
||||||
|
|
|
@ -37,11 +37,13 @@ import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
|
||||||
import org.eclipse.jetty.io.IdleTimeout;
|
import org.eclipse.jetty.io.IdleTimeout;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.Promise;
|
import org.eclipse.jetty.util.Promise;
|
||||||
|
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
|
import org.eclipse.jetty.util.component.Dumpable;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
|
|
||||||
public class HTTP2Stream extends IdleTimeout implements IStream, Callback
|
public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpable
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(HTTP2Stream.class);
|
private static final Logger LOG = Log.getLogger(HTTP2Stream.class);
|
||||||
|
|
||||||
|
@ -86,9 +88,8 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback
|
||||||
@Override
|
@Override
|
||||||
public void headers(HeadersFrame frame, Callback callback)
|
public void headers(HeadersFrame frame, Callback callback)
|
||||||
{
|
{
|
||||||
if (!startWrite(callback))
|
if (startWrite(callback))
|
||||||
return;
|
session.frames(this, this, frame, Frame.EMPTY_ARRAY);
|
||||||
session.frames(this, this, frame, Frame.EMPTY_ARRAY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -100,9 +101,8 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback
|
||||||
@Override
|
@Override
|
||||||
public void data(DataFrame frame, Callback callback)
|
public void data(DataFrame frame, Callback callback)
|
||||||
{
|
{
|
||||||
if (!startWrite(callback))
|
if (startWrite(callback))
|
||||||
return;
|
session.data(this, this, frame);
|
||||||
session.data(this, this, frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -290,8 +290,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback
|
||||||
remoteReset = true;
|
remoteReset = true;
|
||||||
close();
|
close();
|
||||||
session.removeStream(this);
|
session.removeStream(this);
|
||||||
callback.succeeded();
|
notifyReset(this, frame, callback);
|
||||||
notifyReset(this, frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPush(PushPromiseFrame frame, Callback callback)
|
private void onPush(PushPromiseFrame frame, Callback callback)
|
||||||
|
@ -375,8 +374,8 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback
|
||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
closeState.set(CloseState.CLOSED);
|
if (closeState.getAndSet(CloseState.CLOSED) != CloseState.CLOSED)
|
||||||
onClose();
|
onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -415,14 +414,14 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyReset(Stream stream, ResetFrame frame)
|
private void notifyReset(Stream stream, ResetFrame frame, Callback callback)
|
||||||
{
|
{
|
||||||
final Listener listener = this.listener;
|
final Listener listener = this.listener;
|
||||||
if (listener == null)
|
if (listener == null)
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
listener.onReset(stream, frame);
|
listener.onReset(stream, frame, callback);
|
||||||
}
|
}
|
||||||
catch (Throwable x)
|
catch (Throwable x)
|
||||||
{
|
{
|
||||||
|
@ -446,6 +445,18 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String dump()
|
||||||
|
{
|
||||||
|
return ContainerLifeCycle.dump(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dump(Appendable out, String indent) throws IOException
|
||||||
|
{
|
||||||
|
out.append(toString()).append(System.lineSeparator());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -163,6 +163,19 @@ public interface Stream
|
||||||
*/
|
*/
|
||||||
public void onData(Stream stream, DataFrame frame, Callback callback);
|
public void onData(Stream stream, DataFrame frame, Callback callback);
|
||||||
|
|
||||||
|
public default void onReset(Stream stream, ResetFrame frame, Callback callback)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
onReset(stream, frame);
|
||||||
|
callback.succeeded();
|
||||||
|
}
|
||||||
|
catch (Throwable x)
|
||||||
|
{
|
||||||
|
callback.failed(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Callback method invoked when a RST_STREAM frame has been received for this stream.</p>
|
* <p>Callback method invoked when a RST_STREAM frame has been received for this stream.</p>
|
||||||
*
|
*
|
||||||
|
@ -170,7 +183,9 @@ public interface Stream
|
||||||
* @param frame the RST_FRAME received
|
* @param frame the RST_FRAME received
|
||||||
* @see Session.Listener#onReset(Session, ResetFrame)
|
* @see Session.Listener#onReset(Session, ResetFrame)
|
||||||
*/
|
*/
|
||||||
public void onReset(Stream stream, ResetFrame frame);
|
public default void onReset(Stream stream, ResetFrame frame)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Callback method invoked when the stream exceeds its idle timeout.</p>
|
* <p>Callback method invoked when the stream exceeds its idle timeout.</p>
|
||||||
|
|
|
@ -163,12 +163,12 @@ public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionF
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReset(Stream stream, ResetFrame frame)
|
public void onReset(Stream stream, ResetFrame frame, Callback callback)
|
||||||
{
|
{
|
||||||
ErrorCode error = ErrorCode.from(frame.getError());
|
ErrorCode error = ErrorCode.from(frame.getError());
|
||||||
if (error == null)
|
if (error == null)
|
||||||
error = ErrorCode.CANCEL_STREAM_ERROR;
|
error = ErrorCode.CANCEL_STREAM_ERROR;
|
||||||
getConnection().onStreamFailure((IStream)stream, new EofException("HTTP/2 " + error), Callback.NOOP);
|
getConnection().onStreamFailure((IStream)stream, new EofException("HTTP/2 " + error), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue