use of org.eclipse.jetty.http2.IStream in project jetty.project by eclipse.
the class HTTP2Session method push.
@Override
public void push(IStream stream, Promise<Stream> promise, PushPromiseFrame frame, Stream.Listener listener) {
// Synchronization is necessary to atomically create
// the stream id and enqueue the frame to be sent.
boolean queued;
synchronized (this) {
int streamId = streamIds.getAndAdd(2);
frame = new PushPromiseFrame(frame.getStreamId(), streamId, frame.getMetaData());
final IStream pushStream = createLocalStream(streamId, promise);
if (pushStream == null)
return;
pushStream.setListener(listener);
ControlEntry entry = new ControlEntry(frame, pushStream, new PromiseCallback<>(promise, pushStream));
queued = flusher.append(entry);
}
// Iterate outside the synchronized block.
if (queued)
flusher.iterate();
}
use of org.eclipse.jetty.http2.IStream in project jetty.project by eclipse.
the class FlowControlStalledTest method testStreamStalledIsInvokedOnlyOnce.
@Test
public void testStreamStalledIsInvokedOnlyOnce() throws Exception {
AtomicReference<CountDownLatch> stallLatch = new AtomicReference<>(new CountDownLatch(1));
CountDownLatch unstallLatch = new CountDownLatch(1);
start(() -> new BufferingFlowControlStrategy(0.5f) {
@Override
public void onStreamStalled(IStream stream) {
super.onStreamStalled(stream);
stallLatch.get().countDown();
}
@Override
protected void onStreamUnstalled(IStream stream) {
super.onStreamUnstalled(stream);
unstallLatch.countDown();
}
}, new ServerSessionListener.Adapter() {
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
MetaData.Request request = (MetaData.Request) frame.getMetaData();
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
if (request.getURIString().endsWith("/stall")) {
stream.headers(new HeadersFrame(stream.getId(), response, null, false), new Callback() {
@Override
public void succeeded() {
// Send a large chunk of data so the stream gets stalled.
ByteBuffer data = ByteBuffer.allocate(FlowControlStrategy.DEFAULT_WINDOW_SIZE + 1);
stream.data(new DataFrame(stream.getId(), data, true), NOOP);
}
});
} else {
stream.headers(new HeadersFrame(stream.getId(), response, null, true), Callback.NOOP);
}
return null;
}
});
// Use a large session window so that only the stream gets stalled.
client.setInitialSessionRecvWindow(5 * FlowControlStrategy.DEFAULT_WINDOW_SIZE);
Session client = newClient(new Session.Listener.Adapter());
CountDownLatch latch = new CountDownLatch(1);
Queue<Callback> callbacks = new ArrayDeque<>();
MetaData.Request request = newRequest("GET", "/stall", new HttpFields());
client.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
callbacks.offer(callback);
if (frame.isEndStream())
latch.countDown();
}
});
Assert.assertTrue(stallLatch.get().await(5, TimeUnit.SECONDS));
// First stream is now stalled, check that writing a second stream
// does not result in the first be notified again of being stalled.
stallLatch.set(new CountDownLatch(1));
request = newRequest("GET", "/", new HttpFields());
client.newStream(new HeadersFrame(request, null, true), new Promise.Adapter<>(), new Stream.Listener.Adapter());
Assert.assertFalse(stallLatch.get().await(1, TimeUnit.SECONDS));
// Consume all data.
while (!latch.await(10, TimeUnit.MILLISECONDS)) {
Callback callback = callbacks.poll();
if (callback != null)
callback.succeeded();
}
// Make sure the unstall callback is invoked.
Assert.assertTrue(unstallLatch.await(5, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.http2.IStream in project jetty.project by eclipse.
the class HTTP2ClientSession method onHeaders.
@Override
public void onHeaders(HeadersFrame frame) {
if (LOG.isDebugEnabled())
LOG.debug("Received {}", frame);
int streamId = frame.getStreamId();
IStream stream = getStream(streamId);
if (stream != null) {
MetaData metaData = frame.getMetaData();
if (metaData.isRequest()) {
onConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "invalid_response");
} else {
stream.process(frame, Callback.NOOP);
notifyHeaders(stream, frame);
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Ignoring {}, stream #{} not found", frame, streamId);
}
}
Aggregations