diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index e93873aef2b..da16fa53026 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -500,7 +500,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener * @see #onIdleTimeout() */ @Override - public void close(int error, String reason, Callback callback) + public boolean close(int error, String reason, Callback callback) { while (true) { @@ -516,7 +516,7 @@ public abstract class HTTP2Session implements ISession, Parser.Listener if (LOG.isDebugEnabled()) LOG.debug("Sending {}", frame); control(null, callback, frame); - return; + return true; } break; } @@ -524,7 +524,8 @@ public abstract class HTTP2Session implements ISession, Parser.Listener { if (LOG.isDebugEnabled()) LOG.debug("Ignoring close {}/{}, already closed", error, reason); - return; + callback.succeeded(); + return false; } } } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 75f9dd8e0e6..9c91d604e46 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -96,9 +96,9 @@ public class HTTP2Stream extends IdleTimeout implements IStream @Override public void reset(ResetFrame frame, Callback callback) { - notIdle(); if (isReset()) return; + notIdle(); localReset = true; session.control(this, callback, frame, Frame.EMPTY_ARRAY); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java index 01b8c89ceb5..056cc128c5a 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Session.java @@ -21,6 +21,7 @@ package org.eclipse.jetty.http2.api; import java.util.Collection; import java.util.Map; +import org.eclipse.jetty.http2.frames.DataFrame; import org.eclipse.jetty.http2.frames.GoAwayFrame; import org.eclipse.jetty.http2.frames.HeadersFrame; import org.eclipse.jetty.http2.frames.PingFrame; @@ -29,39 +30,161 @@ import org.eclipse.jetty.http2.frames.SettingsFrame; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; +/** + *
A {@link Session} represents the client-side endpoint of a HTTP/2 connection to a single origin server.
+ *Once a {@link Session} has been obtained, it can be used to open HTTP/2 streams:
+ *+ * Session session = ...; + * HeadersFrame frame = ...; + * Promise+ *promise = ... + * session.newStream(frame, promise, new Stream.Listener.Adapter() + * { + * public void onHeaders(Stream stream, HeadersFrame frame) + * { + * // Reply received + * } + * }); + *
A {@link Session} is the active part of the endpoint, and by calling its API applications can generate + * events on the connection; conversely {@link Session.Listener} is the passive part of the endpoint, and + * has callbacks that are invoked when events happen on the connection.
+ * + * @see Session.Listener + */ public interface Session { + /** + *Sends the given HEADERS {@code frame} to create a new {@link Stream}.
+ * + * @param frame the HEADERS frame containing the HTTP headers + * @param promise the promise that gets notified of the stream creation + * @param listener the listener that gets notified of stream events + */ public void newStream(HeadersFrame frame, PromiseSends the given SETTINGS {@code frame} to configure the session.
+ * + * @param frame the SETTINGS frame to send + * @param callback the callback that gets notified when the frame has been sent + */ public void settings(SettingsFrame frame, Callback callback); + /** + *Sends the given PING {@code frame}.
+ *PING frames may be used to test the connection integrity and to measure + * round-trip time.
+ * + * @param frame the PING frame to send + * @param callback the callback that gets notified when the frame has been sent + */ public void ping(PingFrame frame, Callback callback); - public void close(int error, String payload, Callback callback); + /** + *Closes the session by sending a GOAWAY frame with the given error code + * and payload.
+ *The GOAWAY frame is sent only once; subsequent or concurrent attempts to + * close the session will have no effect.
+ * + * @param error the error code + * @param payload an optional payload (may be null) + * @param callback the callback that gets notified when the frame has been sent + * @return true if the frame is being sent, false if the session was already closed + */ + public boolean close(int error, String payload, Callback callback); + /** + * @return whether the session is not open + */ public boolean isClosed(); + /** + * @return a snapshot of all the streams currently belonging to this session + */ public CollectionRetrieves the stream with the given {@code streamId}.
+ * + * @param streamId the stream id of the stream looked for + * @return the stream with the given id, or null if no such stream exist + */ public Stream getStream(int streamId); + /** + *A {@link Listener} is the passive counterpart of a {@link Session} and + * receives events happening on a HTTP/2 connection.
+ * + * @see Session + */ public interface Listener { - public MapCallback method invoked when the preface has been received.
+ * + * @param session the session + * @return a (possibly empty or null) map containing SETTINGS configuration + * options that are sent after the preface. + */ + public MapCallback method invoked when a new stream is being created upon + * receiving a HEADERS frame representing a HTTP request.
+ *Applications should implement this method to process HTTP requests, + * typically providing a HTTP response via + * {@link Stream#headers(HeadersFrame, Callback)}.
+ *Applications can detect whether request DATA frames will be arriving + * by testing {@link HeadersFrame#isEndStream()}. If the application is + * interested in processing the DATA frames, it must return a + * {@link Stream.Listener} implementation that overrides + * {@link Stream.Listener#onData(Stream, DataFrame, Callback)}.
+ * + * @param stream the newly created stream + * @param frame the HEADERS frame received + * @return a {@link Stream.Listener} that will be notified of stream events + */ public Stream.Listener onNewStream(Stream stream, HeadersFrame frame); + /** + *Callback method invoked when a SETTINGS frame has been received.
+ * + * @param session the session + * @param frame the SETTINGS frame received + */ public void onSettings(Session session, SettingsFrame frame); + /** + *Callback method invoked when a PING frame has been received.
+ * + * @param session the session + * @param frame the PING frame received + */ public void onPing(Session session, PingFrame frame); + /** + *Callback method invoked when a RST_STREAM frame has been received for an unknown stream.
+ * + * @param session the session + * @param frame the RST_STREAM frame received + * @see {@link Stream.Listener#onReset(Stream, ResetFrame)} + */ public void onReset(Session session, ResetFrame frame); + /** + *Callback method invoked when a GOAWAY frame has been received.
+ * + * @param session the session + * @param frame the GOAWAY frame received + */ public void onClose(Session session, GoAwayFrame frame); // TODO: how come this is not called ??? public void onFailure(Session session, Throwable failure); + /** + *Empty implementation of {@link Stream.Listener}.
+ */ public static class Adapter implements Session.Listener { @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java index a30216b3310..5c6a6337a73 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/Stream.java @@ -25,46 +25,164 @@ import org.eclipse.jetty.http2.frames.ResetFrame; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Promise; +/** + *A {@link Stream} represents a bidirectional exchange of data on top of a {@link Session}.
+ *Differently from socket streams, where the input and output streams are permanently associated + * with the socket (and hence with the connection that the socket represents), there can be multiple + * HTTP/2 streams present concurrent for a HTTP/2 session.
+ *A {@link Stream} maps to a HTTP request/response cycle, and after the request/response cycle is + * completed, the stream is closed and removed from the session.
+ *Like {@link Session}, {@link Stream} is the active part and by calling its API applications + * can generate events on the stream; conversely, {@link Stream.Listener} is the passive part, and + * its callbacks are invoked when events happen on the stream.
+ * + * @see Stream.Listener + */ public interface Stream { + /** + * @return the stream unique id + */ public int getId(); + /** + * @return the session this stream is associated to + */ public Session getSession(); + /** + *Sends the given HEADERS {@code frame} representing a HTTP response.
+ * + * @param frame the HEADERS frame to send + * @param callback the callback that gets notified when the frame has been sent + */ public void headers(HeadersFrame frame, Callback callback); + /** + *Sends the given PUSH_PROMISE {@code frame}.
+ * + * @param frame the PUSH_PROMISE frame to send + * @param promise the promise that gets notified of the pushed stream creation + */ public void push(PushPromiseFrame frame, PromiseSends the given DATA {@code frame}.
+ * + * @param frame the DATA frame to send + * @param callback the callback that gets notified when the frame has been sent + */ public void data(DataFrame frame, Callback callback); + /** + *Sends the given RST_STREAM {@code frame}.
+ * + * @param frame the RST_FRAME to send + * @param callback the callback that gets notified when the frame has been sent + */ public void reset(ResetFrame frame, Callback callback); + /** + * @param key the attribute key + * @return an arbitrary object associated with the given key to this stream + * or null if no object can be found for the given key. + * @see #setAttribute(String, Object) + */ public Object getAttribute(String key); + /** + * @param key the attribute key + * @param value an arbitrary object to associate with the given key to this stream + * @see #getAttribute(String) + * @see #removeAttribute(String) + */ public void setAttribute(String key, Object value); + /** + * @param key the attribute key + * @return the arbitrary object associated with the given key to this stream + * @see #setAttribute(String, Object) + */ public Object removeAttribute(String key); + /** + * @return whether this stream has been reset + */ public boolean isReset(); + /** + * @return whether this stream is closed, both locally and remotely. + */ public boolean isClosed(); + /** + * @return the stream idle timeout + * @see #setIdleTimeout(long) + */ public long getIdleTimeout(); + /** + * @param idleTimeout the stream idle timeout + * @see #getIdleTimeout() + * @see Stream.Listener#onTimeout(Stream, Throwable) + */ public void setIdleTimeout(long idleTimeout); + /** + *A {@link Stream.Listener} is the passive counterpart of a {@link Stream} and receives + * events happening on a HTTP/2 stream.
+ * + * @see Stream + */ public interface Listener { + /** + *Callback method invoked when a HEADERS frame representing the HTTP response has been received.
+ * + * @param stream the stream + * @param frame the HEADERS frame received + */ public void onHeaders(Stream stream, HeadersFrame frame); + /** + *Callback method invoked when a PUSH_PROMISE frame has been received.
+ * + * @param stream the stream + * @param frame the PUSH_PROMISE frame received + * @return a {@link Stream.Listener} that will be notified of pushed stream events + */ public Listener onPush(Stream stream, PushPromiseFrame frame); + /** + *Callback method invoked when a DATA frame has been received.
+ * + * @param stream the stream + * @param frame the DATA frame received + * @param callback the callback to complete when the bytes of the DATA frame have been consumed + */ public void onData(Stream stream, DataFrame frame, Callback callback); + /** + *Callback method invoked when a RST_STREAM frame has been received for this stream.
+ * + * @param stream the stream + * @param frame the RST_FRAME received + * @see Session.Listener#onReset(Session, ResetFrame) + */ public void onReset(Stream stream, ResetFrame frame); + /** + *Callback method invoked when the stream exceeds its idle timeout.
+ * + * @param stream the stream + * @param x the timeout failure + * @see #getIdleTimeout() + */ public void onTimeout(Stream stream, Throwable x); + /** + *Empty implementation of {@link Listener}
+ */ public static class Adapter implements Listener { @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java index d7ac5dbdd23..e1228742fe1 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/api/server/ServerSessionListener.java @@ -20,10 +20,20 @@ package org.eclipse.jetty.http2.api.server; import org.eclipse.jetty.http2.api.Session; +/** + *Server-side extension of {@link Session.Listener} that exposes additional events.
+ */ public interface ServerSessionListener extends Session.Listener { + /** + *Callback method invoked when a connection has been accepted by the server.
+ * @param session the session + */ public void onAccept(Session session); + /** + *Empty implementation of {@link ServerSessionListener}
+ */ public static class Adapter extends Session.Listener.Adapter implements ServerSessionListener { @Override