Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java')
-rw-r--r--jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java184
1 files changed, 182 insertions, 2 deletions
diff --git a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java
index 1f68283fcf..405e6d8d56 100644
--- a/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java
+++ b/jetty-http2/http2-client/src/test/java/org/eclipse/jetty/http2/client/HTTP2Test.java
@@ -20,6 +20,7 @@ package org.eclipse.jetty.http2.client;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.channels.WritePendingException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@@ -263,7 +264,7 @@ public class HTTP2Test extends AbstractTest
}
});
- Thread.sleep(1000);
+ sleep(1000);
server.stop();
@@ -285,7 +286,7 @@ public class HTTP2Test extends AbstractTest
newClient(new Session.Listener.Adapter());
- Thread.sleep(1000);
+ sleep(1000);
client.stop();
@@ -416,4 +417,183 @@ public class HTTP2Test extends AbstractTest
Assert.assertTrue(exchangeLatch2.await(5, TimeUnit.SECONDS));
Assert.assertEquals(0, session.getStreams().size());
}
+
+ @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));
+ }
+
+ @Test
+ public void testInvalidAPIUsageOnServer() throws Exception
+ {
+ long sleep = 1000;
+ CountDownLatch completeLatch = new CountDownLatch(2);
+ start(new ServerSessionListener.Adapter()
+ {
+ @Override
+ public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
+ {
+ MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
+ DataFrame dataFrame = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true);
+ // The call to headers() is legal, but slow.
+ new Thread(() ->
+ {
+ stream.headers(new HeadersFrame(stream.getId(), response, null, false)
+ {
+ @Override
+ public MetaData getMetaData()
+ {
+ sleep(2 * sleep);
+ return super.getMetaData();
+ }
+ }, new Callback()
+ {
+ @Override
+ public void succeeded()
+ {
+ stream.data(dataFrame, NOOP);
+ }
+ });
+ }).start();
+
+ // Wait for the headers() call to happen.
+ sleep(sleep);
+
+ // This data call is illegal because it does not
+ // wait for the previous callback to complete.
+ stream.data(dataFrame, new Callback()
+ {
+ @Override
+ public void failed(Throwable x)
+ {
+ if (x instanceof WritePendingException)
+ {
+ // Expected.
+ completeLatch.countDown();
+ }
+ }
+ });
+
+ return null;
+ }
+ });
+
+ Session session = newClient(new Session.Listener.Adapter());
+
+ MetaData.Request metaData = newRequest("GET", new HttpFields());
+ HeadersFrame frame = new HeadersFrame(metaData, null, true);
+ 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())
+ completeLatch.countDown();
+ }
+ });
+
+ Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
+ }
+
+ private static void sleep(long time)
+ {
+ try
+ {
+ Thread.sleep(time);
+ }
+ catch (InterruptedException x)
+ {
+ throw new RuntimeException();
+ }
+ }
}

Back to the top