use of org.eclipse.jetty.util.Callback in project jetty.project by eclipse.
the class FlowControlStrategyTest method testServerSendsBigContent.
@Test
public void testServerSendsBigContent() throws Exception {
final byte[] data = new byte[1024 * 1024];
new Random().nextBytes(data);
start(new ServerSessionListener.Adapter() {
@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, false);
Callback.Completable completable = new Callback.Completable();
stream.headers(responseFrame, completable);
completable.thenRun(() -> {
DataFrame dataFrame = new DataFrame(stream.getId(), ByteBuffer.wrap(data), true);
stream.data(dataFrame, Callback.NOOP);
});
return null;
}
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
final byte[] bytes = new byte[data.length];
final CountDownLatch latch = new CountDownLatch(1);
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter() {
private int received;
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
int remaining = frame.remaining();
frame.getData().get(bytes, received, remaining);
this.received += remaining;
callback.succeeded();
if (frame.isEndStream())
latch.countDown();
}
});
Assert.assertTrue(latch.await(15, TimeUnit.SECONDS));
Assert.assertArrayEquals(data, bytes);
}
use of org.eclipse.jetty.util.Callback in project jetty.project by eclipse.
the class FlowControlStrategyTest method testClientExceedingSessionWindow.
@Test
public void testClientExceedingSessionWindow() throws Exception {
// On server, we don't consume the data.
start(new ServerSessionListener.Adapter());
final CountDownLatch closeLatch = new CountDownLatch(1);
Session session = newClient(new Session.Listener.Adapter() {
@Override
public void onClose(Session session, GoAwayFrame frame) {
if (frame.getError() == ErrorCode.FLOW_CONTROL_ERROR.code)
closeLatch.countDown();
}
});
// Consume the whole session and stream window.
MetaData.Request metaData = newRequest("POST", new HttpFields());
HeadersFrame requestFrame = new HeadersFrame(metaData, null, false);
CompletableFuture<Stream> completable = new CompletableFuture<>();
session.newStream(requestFrame, Promise.from(completable), new Stream.Listener.Adapter());
Stream stream = completable.get(5, TimeUnit.SECONDS);
ByteBuffer data = ByteBuffer.allocate(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
final CountDownLatch dataLatch = new CountDownLatch(1);
stream.data(new DataFrame(stream.getId(), data, false), new Callback() {
@Override
public InvocationType getInvocationType() {
return InvocationType.NON_BLOCKING;
}
@Override
public void succeeded() {
dataLatch.countDown();
}
});
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
// The following "sneaky" write may clash with the write
// of the reply SETTINGS frame sent by the client in
// response to the server SETTINGS frame.
// It is not enough to use a latch on the server to
// wait for the reply frame, since the client may have
// sent the bytes, but not yet be ready to write again.
Thread.sleep(1000);
// Now the client is supposed to not send more frames.
// If it does, the connection must be closed.
HTTP2Session http2Session = (HTTP2Session) session;
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(connector.getByteBufferPool());
ByteBuffer extraData = ByteBuffer.allocate(1024);
http2Session.getGenerator().data(lease, new DataFrame(stream.getId(), extraData, true), extraData.remaining());
List<ByteBuffer> buffers = lease.getByteBuffers();
http2Session.getEndPoint().write(Callback.NOOP, buffers.toArray(new ByteBuffer[buffers.size()]));
// Expect the connection to be closed.
Assert.assertTrue(closeLatch.await(5, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.util.Callback in project jetty.project by eclipse.
the class HTTP2Test method testRequestNoContentResponseContent.
@Test
public void testRequestNoContentResponseContent() throws Exception {
final byte[] content = "Hello World!".getBytes(StandardCharsets.UTF_8);
start(new HttpServlet() {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getOutputStream().write(content);
}
});
Session session = newClient(new Session.Listener.Adapter());
HttpFields fields = new HttpFields();
MetaData.Request metaData = newRequest("GET", fields);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
final CountDownLatch latch = new CountDownLatch(2);
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter() {
@Override
public void onHeaders(Stream stream, HeadersFrame frame) {
Assert.assertTrue(stream.getId() > 0);
Assert.assertFalse(frame.isEndStream());
Assert.assertEquals(stream.getId(), frame.getStreamId());
Assert.assertTrue(frame.getMetaData().isResponse());
MetaData.Response response = (MetaData.Response) frame.getMetaData();
Assert.assertEquals(200, response.getStatus());
latch.countDown();
}
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
Assert.assertTrue(frame.isEndStream());
Assert.assertEquals(ByteBuffer.wrap(content), frame.getData());
callback.succeeded();
latch.countDown();
}
});
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.util.Callback in project jetty.project by eclipse.
the class HTTP2Test method testMultipleRequests.
@Test
public void testMultipleRequests() throws Exception {
final String downloadBytes = "X-Download";
start(new HttpServlet() {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int download = request.getIntHeader(downloadBytes);
byte[] content = new byte[download];
new Random().nextBytes(content);
response.getOutputStream().write(content);
}
});
int requests = 20;
Session session = newClient(new Session.Listener.Adapter());
Random random = new Random();
HttpFields fields = new HttpFields();
fields.putLongField(downloadBytes, random.nextInt(128 * 1024));
fields.put("User-Agent", "HTTP2Client/" + Jetty.VERSION);
MetaData.Request metaData = newRequest("GET", fields);
HeadersFrame frame = new HeadersFrame(metaData, null, true);
final CountDownLatch latch = new CountDownLatch(requests);
for (int i = 0; i < requests; ++i) {
session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
callback.succeeded();
if (frame.isEndStream())
latch.countDown();
}
});
}
Assert.assertTrue(latch.await(requests, TimeUnit.SECONDS));
}
use of org.eclipse.jetty.util.Callback in project jetty.project by eclipse.
the class HTTP2Test method testInvalidAPIUsageOnClient.
@Test
public void testInvalidAPIUsageOnClient() throws Exception {
start(new ServerSessionListener.Adapter() {
@Override
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
Callback.Completable completable = new Callback.Completable();
MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
stream.headers(new HeadersFrame(stream.getId(), response, null, false), completable);
return new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
callback.succeeded();
if (frame.isEndStream()) {
completable.thenRun(() -> {
DataFrame endFrame = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true);
stream.data(endFrame, Callback.NOOP);
});
}
}
};
}
});
Session session = newClient(new Session.Listener.Adapter());
MetaData.Request metaData = newRequest("GET", new HttpFields());
HeadersFrame frame = new HeadersFrame(metaData, null, false);
Promise.Completable<Stream> completable = new Promise.Completable<>();
CountDownLatch completeLatch = new CountDownLatch(2);
session.newStream(frame, completable, new Stream.Listener.Adapter() {
@Override
public void onData(Stream stream, DataFrame frame, Callback callback) {
callback.succeeded();
if (frame.isEndStream())
completeLatch.countDown();
}
});
Stream stream = completable.get(5, TimeUnit.SECONDS);
long sleep = 1000;
DataFrame data1 = new DataFrame(stream.getId(), ByteBuffer.allocate(1024), false) {
@Override
public ByteBuffer getData() {
sleep(2 * sleep);
return super.getData();
}
};
DataFrame data2 = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true);
new Thread(() -> {
// The first data() call is legal, but slow.
stream.data(data1, new Callback() {
@Override
public void succeeded() {
stream.data(data2, NOOP);
}
});
}).start();
// Wait for the first data() call to happen.
sleep(sleep);
// This data call is illegal because it does not
// wait for the previous callback to complete.
stream.data(data2, new Callback() {
@Override
public void failed(Throwable x) {
if (x instanceof WritePendingException) {
// Expected.
completeLatch.countDown();
}
}
});
Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
}
Aggregations