use of org.eclipse.jetty.http2.api.Session in project jetty.project by eclipse.
the class StreamResetTest method testStreamResetDoesNotCloseConnection.
@Test
public void testStreamResetDoesNotCloseConnection() throws Exception {
final CountDownLatch serverResetLatch = new CountDownLatch(1);
final CountDownLatch serverDataLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter() {
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) {
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), response, null, false);
Callback.Completable completable = new Callback.Completable();
stream.headers(responseFrame, completable);
return new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
callback.succeeded();
completable.thenRun(() -> stream.data(new DataFrame(stream.getId(), ByteBuffer.allocate(16), true), new Callback() {
@Override
public void succeeded() {
serverDataLatch.countDown();
}
}));
}
@Override
public void onReset(Stream s, ResetFrame frame) {
// Simulate that there is pending data to send.
IStream stream = (IStream) s;
stream.getSession().frames(stream, new Callback() {
@Override
public void failed(Throwable x) {
serverResetLatch.countDown();
}
}, new DataFrame(s.getId(), ByteBuffer.allocate(16), true));
}
};
}
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request1 = newRequest("GET", new HttpFields());
HeadersFrame requestFrame1 = new HeadersFrame(request1, null, false);
FuturePromise<Stream> promise1 = new FuturePromise<>();
final CountDownLatch stream1HeadersLatch = new CountDownLatch(1);
final CountDownLatch stream1DataLatch = new CountDownLatch(1);
client.newStream(requestFrame1, promise1, new Stream.Listener.Adapter() {
@Override
public void onHeaders(Stream stream, HeadersFrame frame) {
stream1HeadersLatch.countDown();
}
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
callback.succeeded();
stream1DataLatch.countDown();
}
});
Stream stream1 = promise1.get(5, TimeUnit.SECONDS);
Assert.assertTrue(stream1HeadersLatch.await(5, TimeUnit.SECONDS));
MetaData.Request request2 = newRequest("GET", new HttpFields());
HeadersFrame requestFrame2 = new HeadersFrame(request2, null, false);
FuturePromise<Stream> promise2 = new FuturePromise<>();
final CountDownLatch stream2DataLatch = new CountDownLatch(1);
client.newStream(requestFrame2, promise2, new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
callback.succeeded();
stream2DataLatch.countDown();
}
});
Stream stream2 = promise2.get(5, TimeUnit.SECONDS);
ResetFrame resetFrame = new ResetFrame(stream1.getId(), ErrorCode.CANCEL_STREAM_ERROR.code);
stream1.reset(resetFrame, Callback.NOOP);
Assert.assertTrue(serverResetLatch.await(5, TimeUnit.SECONDS));
// Stream MUST NOT receive data sent by server after reset.
Assert.assertFalse(stream1DataLatch.await(1, TimeUnit.SECONDS));
// The other stream should still be working.
stream2.data(new DataFrame(stream2.getId(), ByteBuffer.allocate(16), true), Callback.NOOP);
Assert.assertTrue(serverDataLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(stream2DataLatch.await(5, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.http2.api.Session in project jetty.project by eclipse.
the class StreamResetTest method testServerExceptionConsumesQueuedData.
@Test
public void testServerExceptionConsumesQueuedData() throws Exception {
try (StacklessLogging suppressor = new StacklessLogging(HttpChannel.class)) {
start(new HttpServlet() {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// Wait to let the data sent by the client to be queued.
Thread.sleep(1000);
throw new IllegalStateException("explictly_thrown_by_test");
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}
});
Session client = newClient(new Session.Listener.Adapter());
Log.getLogger(HttpChannel.class).info("Expecting java.lang.IllegalStateException: explictly_thrown_by_test");
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 data = ByteBuffer.allocate(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
CountDownLatch dataLatch = new CountDownLatch(1);
stream.data(new DataFrame(stream.getId(), data, false), new Callback() {
@Override
public void succeeded() {
dataLatch.countDown();
}
});
// The server does not read the data, so the flow control window should be zero.
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
Assert.assertEquals(0, ((ISession) client).updateSendWindow(0));
// Wait for the server process the exception, and
// for the client to process the window updates.
Thread.sleep(2000);
Assert.assertThat(((ISession) client).updateSendWindow(0), Matchers.greaterThan(0));
}
}
use of org.eclipse.jetty.http2.api.Session in project jetty.project by eclipse.
the class StreamResetTest method testBlockingWriteAfterStreamReceivingReset.
@Test
public void testBlockingWriteAfterStreamReceivingReset() throws Exception {
final CountDownLatch resetLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
start(new HttpServlet() {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Charset charset = StandardCharsets.UTF_8;
byte[] data = "AFTER RESET".getBytes(charset);
response.setStatus(200);
response.setContentType("text/plain;charset=" + charset.name());
response.setContentLength(data.length * 10);
response.flushBuffer();
try {
// Wait for the reset to happen.
Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
} catch (InterruptedException x) {
throw new InterruptedIOException();
}
try {
// been reset, it should throw an exception.
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
response.getOutputStream().write(data);
response.flushBuffer();
}
} catch (InterruptedException x) {
} catch (IOException x) {
dataLatch.countDown();
}
}
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
HeadersFrame frame = new HeadersFrame(request, null, true);
client.newStream(frame, new FuturePromise<>(), new Stream.Listener.Adapter() {
@Override
public void onHeaders(Stream stream, HeadersFrame frame) {
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
resetLatch.countDown();
}
});
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.http2.api.Session in project jetty.project by eclipse.
the class StreamResetTest method testStreamReceivingResetIsRemoved.
@Test
public void testStreamReceivingResetIsRemoved() throws Exception {
final AtomicReference<Stream> streamRef = new AtomicReference<>();
final CountDownLatch resetLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter() {
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
return new Stream.Listener.Adapter() {
@Override
public void onReset(Stream stream, ResetFrame frame) {
Assert.assertNotNull(stream);
Assert.assertTrue(stream.isReset());
streamRef.set(stream);
resetLatch.countDown();
}
};
}
});
Session client = newClient(new Session.Listener.Adapter());
MetaData.Request request = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(request, null, false);
FuturePromise<Stream> promise = new FuturePromise<>();
client.newStream(requestFrame, promise, new Stream.Listener.Adapter());
Stream stream = promise.get(5, TimeUnit.SECONDS);
ResetFrame resetFrame = new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code);
stream.reset(resetFrame, Callback.NOOP);
Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
// Wait a while to let the server remove the
// stream after returning from onReset().
Thread.sleep(1000);
Stream serverStream = streamRef.get();
Assert.assertEquals(0, serverStream.getSession().getStreams().size());
}
use of org.eclipse.jetty.http2.api.Session in project jetty.project by eclipse.
the class HTTP2ClientConnectionFactory method newConnection.
@Override
public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException {
HTTP2Client client = (HTTP2Client) context.get(CLIENT_CONTEXT_KEY);
ByteBufferPool byteBufferPool = (ByteBufferPool) context.get(BYTE_BUFFER_POOL_CONTEXT_KEY);
Executor executor = (Executor) context.get(EXECUTOR_CONTEXT_KEY);
Scheduler scheduler = (Scheduler) context.get(SCHEDULER_CONTEXT_KEY);
Session.Listener listener = (Session.Listener) context.get(SESSION_LISTENER_CONTEXT_KEY);
@SuppressWarnings("unchecked") Promise<Session> promise = (Promise<Session>) context.get(SESSION_PROMISE_CONTEXT_KEY);
Generator generator = new Generator(byteBufferPool);
FlowControlStrategy flowControl = client.getFlowControlStrategyFactory().newFlowControlStrategy();
HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, client.getInputBufferSize(), promise, listener);
connection.addListener(connectionListener);
return customize(connection, context);
}
Aggregations