use of org.eclipse.jetty.http2.ISession in project jetty.project by eclipse.
the class HTTP2ServerConnection method onSessionTimeout.
public boolean onSessionTimeout(Throwable failure) {
ISession session = getSession();
boolean result = true;
for (Stream stream : session.getStreams()) {
HttpChannelOverHTTP2 channel = (HttpChannelOverHTTP2) stream.getAttribute(IStream.CHANNEL_ATTRIBUTE);
if (channel != null)
result &= !channel.isRequestHandled();
}
if (LOG.isDebugEnabled())
LOG.debug("{} idle timeout on {}: {}", result ? "Processed" : "Ignored", session, failure);
return result;
}
use of org.eclipse.jetty.http2.ISession in project jetty.project by eclipse.
the class AbstractFlowControlStrategy method updateInitialStreamWindow.
@Override
public void updateInitialStreamWindow(ISession session, int initialStreamWindow, boolean local) {
int previousInitialStreamWindow;
if (local) {
previousInitialStreamWindow = getInitialStreamRecvWindow();
this.initialStreamRecvWindow = initialStreamWindow;
} else {
previousInitialStreamWindow = getInitialStreamSendWindow();
this.initialStreamSendWindow = initialStreamWindow;
}
int delta = initialStreamWindow - previousInitialStreamWindow;
// SPEC: updates of the initial window size only affect stream windows, not session's.
for (Stream stream : session.getStreams()) {
if (local) {
((IStream) stream).updateRecvWindow(delta);
if (LOG.isDebugEnabled())
LOG.debug("Updated initial stream recv window {} -> {} for {}", previousInitialStreamWindow, initialStreamWindow, stream);
} else {
session.onWindowUpdate((IStream) stream, new WindowUpdateFrame(stream.getId(), delta));
}
}
}
use of org.eclipse.jetty.http2.ISession in project jetty.project by eclipse.
the class BufferingFlowControlStrategy method onDataConsumed.
@Override
public void onDataConsumed(ISession session, IStream stream, int length) {
if (length <= 0)
return;
float ratio = bufferRatio;
WindowUpdateFrame windowFrame = null;
int level = sessionLevel.addAndGet(length);
int maxLevel = (int) (maxSessionRecvWindow.get() * ratio);
if (level > maxLevel) {
if (sessionLevel.compareAndSet(level, 0)) {
session.updateRecvWindow(level);
if (LOG.isDebugEnabled())
LOG.debug("Data consumed, {} bytes, updated session recv window by {}/{} for {}", length, level, maxLevel, session);
windowFrame = new WindowUpdateFrame(0, level);
} else {
if (LOG.isDebugEnabled())
LOG.debug("Data consumed, {} bytes, concurrent session recv window level {}/{} for {}", length, sessionLevel, maxLevel, session);
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Data consumed, {} bytes, session recv window level {}/{} for {}", length, level, maxLevel, session);
}
Frame[] windowFrames = Frame.EMPTY_ARRAY;
if (stream != null) {
if (stream.isClosed()) {
if (LOG.isDebugEnabled())
LOG.debug("Data consumed, {} bytes, ignoring update stream recv window for closed {}", length, stream);
} else {
AtomicInteger streamLevel = streamLevels.get(stream);
if (streamLevel != null) {
level = streamLevel.addAndGet(length);
maxLevel = (int) (getInitialStreamRecvWindow() * ratio);
if (level > maxLevel) {
level = streamLevel.getAndSet(0);
stream.updateRecvWindow(level);
if (LOG.isDebugEnabled())
LOG.debug("Data consumed, {} bytes, updated stream recv window by {}/{} for {}", length, level, maxLevel, stream);
WindowUpdateFrame frame = new WindowUpdateFrame(stream.getId(), level);
if (windowFrame == null)
windowFrame = frame;
else
windowFrames = new Frame[] { frame };
} else {
if (LOG.isDebugEnabled())
LOG.debug("Data consumed, {} bytes, stream recv window level {}/{} for {}", length, level, maxLevel, stream);
}
}
}
}
if (windowFrame != null)
session.frames(stream, Callback.NOOP, windowFrame, windowFrames);
}
use of org.eclipse.jetty.http2.ISession in project jetty.project by eclipse.
the class FlowControlStalledTest method testSessionStalledIsInvokedOnlyOnce.
@Test
public void testSessionStalledIsInvokedOnlyOnce() throws Exception {
AtomicReference<CountDownLatch> stallLatch = new AtomicReference<>(new CountDownLatch(1));
CountDownLatch unstallLatch = new CountDownLatch(1);
start(() -> new BufferingFlowControlStrategy(0.5f) {
@Override
public void onSessionStalled(ISession session) {
super.onSessionStalled(session);
stallLatch.get().countDown();
}
@Override
protected void onSessionUnstalled(ISession session) {
super.onSessionUnstalled(session);
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 session 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 stream window so that only the session gets stalled.
client.setInitialStreamRecvWindow(5 * FlowControlStrategy.DEFAULT_WINDOW_SIZE);
Session session = newClient(new Session.Listener.Adapter() {
@Override
public Map<Integer, Integer> onPreface(Session session) {
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, client.getInitialStreamRecvWindow());
return settings;
}
});
CountDownLatch latch = new CountDownLatch(1);
Queue<Callback> callbacks = new ArrayDeque<>();
MetaData.Request request = newRequest("GET", "/stall", new HttpFields());
session.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));
// The session is now stalled, check that writing a second stream
// does not result in the session be notified again of being stalled.
stallLatch.set(new CountDownLatch(1));
request = newRequest("GET", "/", new HttpFields());
session.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));
}
Aggregations