use of org.eclipse.jetty.util.FuturePromise in project jetty.project by eclipse.
the class HttpClientExplicitConnectionTest method testExplicitConnection.
@Test
public void testExplicitConnection() throws Exception {
start(new EmptyServerHandler());
Destination destination = client.getDestination(scheme, "localhost", connector.getLocalPort());
FuturePromise<Connection> futureConnection = new FuturePromise<>();
destination.newConnection(futureConnection);
try (Connection connection = futureConnection.get(5, TimeUnit.SECONDS)) {
Request request = client.newRequest(destination.getHost(), destination.getPort()).scheme(scheme);
FutureResponseListener listener = new FutureResponseListener(request);
connection.send(request, listener);
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
Assert.assertNotNull(response);
Assert.assertEquals(200, response.getStatus());
HttpDestinationOverHTTP httpDestination = (HttpDestinationOverHTTP) destination;
DuplexConnectionPool connectionPool = (DuplexConnectionPool) httpDestination.getConnectionPool();
Assert.assertTrue(connectionPool.getActiveConnections().isEmpty());
Assert.assertTrue(connectionPool.getIdleConnections().isEmpty());
}
}
use of org.eclipse.jetty.util.FuturePromise in project jetty.project by eclipse.
the class HttpClientExplicitConnectionTest method testExplicitConnectionIsClosedOnRemoteClose.
@Test
public void testExplicitConnectionIsClosedOnRemoteClose() throws Exception {
start(new EmptyServerHandler());
Destination destination = client.getDestination(scheme, "localhost", connector.getLocalPort());
FuturePromise<Connection> futureConnection = new FuturePromise<>();
destination.newConnection(futureConnection);
Connection connection = futureConnection.get(5, TimeUnit.SECONDS);
Request request = client.newRequest(destination.getHost(), destination.getPort()).scheme(scheme);
FutureResponseListener listener = new FutureResponseListener(request);
connection.send(request, listener);
ContentResponse response = listener.get(5, TimeUnit.SECONDS);
Assert.assertEquals(200, response.getStatus());
// Wait some time to have the client is an idle state.
TimeUnit.SECONDS.sleep(1);
connector.stop();
// Give the connection some time to process the remote close.
TimeUnit.SECONDS.sleep(1);
HttpConnectionOverHTTP httpConnection = (HttpConnectionOverHTTP) connection;
Assert.assertFalse(httpConnection.getEndPoint().isOpen());
HttpDestinationOverHTTP httpDestination = (HttpDestinationOverHTTP) destination;
DuplexConnectionPool connectionPool = (DuplexConnectionPool) httpDestination.getConnectionPool();
Assert.assertTrue(connectionPool.getActiveConnections().isEmpty());
Assert.assertTrue(connectionPool.getIdleConnections().isEmpty());
}
use of org.eclipse.jetty.util.FuturePromise in project jetty.project by eclipse.
the class FlowControlStrategyTest method testFlowControlWhenServerResetsStream.
@Test
public void testFlowControlWhenServerResetsStream() throws Exception {
// On server, don't consume the data and immediately reset.
start(new ServerSessionListener.Adapter() {
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
MetaData.Request request = (MetaData.Request) frame.getMetaData();
if (HttpMethod.GET.is(request.getMethod()))
return new Stream.Listener.Adapter();
return new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
// Fail the callback to enlarge the session window.
// More data frames will be discarded because the
// stream is reset, and automatically consumed to
// keep the session window large for other streams.
callback.failed(new Throwable());
stream.reset(new ResetFrame(stream.getId(), ErrorCode.CANCEL_STREAM_ERROR.code), Callback.NOOP);
}
};
}
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("POST", new HttpFields());
HeadersFrame frame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise = new FuturePromise<>();
final CountDownLatch resetLatch = new CountDownLatch(1);
session.newStream(frame, streamPromise, new Stream.Listener.Adapter() {
@Override
public void onReset(Stream stream, ResetFrame frame) {
resetLatch.countDown();
}
});
Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
// Perform a big upload that will stall the flow control windows.
ByteBuffer data = ByteBuffer.allocate(5 * FlowControlStrategy.DEFAULT_WINDOW_SIZE);
final CountDownLatch dataLatch = new CountDownLatch(1);
stream.data(new DataFrame(stream.getId(), data, true), new Callback() {
@Override
public InvocationType getInvocationType() {
return InvocationType.NON_BLOCKING;
}
@Override
public void failed(Throwable x) {
dataLatch.countDown();
}
});
Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.util.FuturePromise in project jetty.project by eclipse.
the class FlowControlStrategyTest method testWindowSizeUpdates.
@Test
public void testWindowSizeUpdates() throws Exception {
final CountDownLatch prefaceLatch = new CountDownLatch(1);
final CountDownLatch stream1Latch = new CountDownLatch(1);
final CountDownLatch stream2Latch = new CountDownLatch(1);
final CountDownLatch settingsLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter() {
@Override
public Map<Integer, Integer> onPreface(Session session) {
HTTP2Session serverSession = (HTTP2Session) session;
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverSession.getSendWindow());
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverSession.getRecvWindow());
prefaceLatch.countDown();
return null;
}
@Override
public void onSettings(Session session, SettingsFrame frame) {
for (Stream stream : session.getStreams()) {
HTTP2Stream serverStream = (HTTP2Stream) stream;
Assert.assertEquals(0, serverStream.getSendWindow());
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverStream.getRecvWindow());
}
settingsLatch.countDown();
}
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
HTTP2Stream serverStream = (HTTP2Stream) stream;
MetaData.Request request = (MetaData.Request) frame.getMetaData();
if ("GET".equalsIgnoreCase(request.getMethod())) {
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverStream.getSendWindow());
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverStream.getRecvWindow());
stream1Latch.countDown();
} else {
Assert.assertEquals(0, serverStream.getSendWindow());
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, serverStream.getRecvWindow());
stream2Latch.countDown();
}
return null;
}
});
HTTP2Session clientSession = (HTTP2Session) newClient(new Session.Listener.Adapter());
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientSession.getSendWindow());
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientSession.getRecvWindow());
Assert.assertTrue(prefaceLatch.await(5, TimeUnit.SECONDS));
MetaData.Request request1 = newRequest("GET", new HttpFields());
FuturePromise<Stream> promise1 = new FuturePromise<>();
clientSession.newStream(new HeadersFrame(request1, null, true), promise1, new Stream.Listener.Adapter());
HTTP2Stream clientStream1 = (HTTP2Stream) promise1.get(5, TimeUnit.SECONDS);
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientStream1.getSendWindow());
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientStream1.getRecvWindow());
Assert.assertTrue(stream1Latch.await(5, TimeUnit.SECONDS));
// Send a SETTINGS frame that changes the window size.
// This tells the server that its stream send window must be updated,
// so on the client it's the receive window that must be updated.
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, 0);
SettingsFrame frame = new SettingsFrame(settings, false);
FutureCallback callback = new FutureCallback();
clientSession.settings(frame, callback);
callback.get(5, TimeUnit.SECONDS);
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientStream1.getSendWindow());
Assert.assertEquals(0, clientStream1.getRecvWindow());
settingsLatch.await(5, TimeUnit.SECONDS);
// Now create a new stream, it must pick up the new value.
MetaData.Request request2 = newRequest("POST", new HttpFields());
FuturePromise<Stream> promise2 = new FuturePromise<>();
clientSession.newStream(new HeadersFrame(request2, null, true), promise2, new Stream.Listener.Adapter());
HTTP2Stream clientStream2 = (HTTP2Stream) promise2.get(5, TimeUnit.SECONDS);
Assert.assertEquals(FlowControlStrategy.DEFAULT_WINDOW_SIZE, clientStream2.getSendWindow());
Assert.assertEquals(0, clientStream2.getRecvWindow());
Assert.assertTrue(stream2Latch.await(5, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.util.FuturePromise in project jetty.project by eclipse.
the class FlowControlStrategyTest method testClientFlowControlOneBigWrite.
@Test
public void testClientFlowControlOneBigWrite() throws Exception {
final int windowSize = 1536;
final Exchanger<Callback> exchanger = new Exchanger<>();
final CountDownLatch settingsLatch = new CountDownLatch(1);
final CountDownLatch dataLatch = new CountDownLatch(1);
start(new ServerSessionListener.Adapter() {
@Override
public Map<Integer, Integer> onPreface(Session session) {
Map<Integer, Integer> settings = new HashMap<>();
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize);
return settings;
}
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame requestFrame) {
MetaData.Response metaData = new MetaData.Response(HttpVersion.HTTP_2, 200, new HttpFields());
HeadersFrame responseFrame = new HeadersFrame(stream.getId(), metaData, null, true);
stream.headers(responseFrame, Callback.NOOP);
return new Stream.Listener.Adapter() {
private AtomicInteger dataFrames = new AtomicInteger();
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
try {
int dataFrames = this.dataFrames.incrementAndGet();
if (dataFrames == 1 || dataFrames == 2) {
// Do not consume the data frame.
// We should then be flow-control stalled.
exchanger.exchange(callback);
} else if (dataFrames == 3 || dataFrames == 4 || dataFrames == 5) {
// Consume totally.
callback.succeeded();
if (frame.isEndStream())
dataLatch.countDown();
} else {
Assert.fail();
}
} catch (InterruptedException x) {
callback.failed(x);
}
}
};
}
});
Session session = newClient(new Session.Listener.Adapter() {
@Override
public void onSettings(Session session, SettingsFrame frame) {
settingsLatch.countDown();
}
});
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
MetaData.Request metaData = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
FuturePromise<Stream> streamPromise = new FuturePromise<>();
session.newStream(requestFrame, streamPromise, null);
Stream stream = streamPromise.get(5, TimeUnit.SECONDS);
final int length = 5 * windowSize;
DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.allocate(length), true);
stream.data(dataFrame, Callback.NOOP);
Callback callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
checkThatWeAreFlowControlStalled(exchanger);
// Consume the first chunk.
callback.succeeded();
callback = exchanger.exchange(null, 5, TimeUnit.SECONDS);
checkThatWeAreFlowControlStalled(exchanger);
// Consume the second chunk.
callback.succeeded();
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
}
Aggregations