1 module hunt.http.codec.http.stream.Session; 2 3 import hunt.collection.Collection; 4 import hunt.collection.Map; 5 6 import hunt.http.codec.http.frame.DataFrame; 7 import hunt.http.codec.http.frame.GoAwayFrame; 8 import hunt.http.codec.http.frame.HeadersFrame; 9 import hunt.http.codec.http.frame.PingFrame; 10 import hunt.http.codec.http.frame.PriorityFrame; 11 import hunt.http.codec.http.frame.ResetFrame; 12 import hunt.http.codec.http.frame.SettingsFrame; 13 14 import hunt.http.codec.http.stream.Stream; 15 16 import hunt.util.Common; 17 import hunt.concurrency.Promise; 18 19 alias StreamSession = Session; 20 21 22 /** 23 * <p>A {@link Session} represents the client-side endpoint of a HTTP/2 connection to a single origin server.</p> 24 * <p>Once a {@link Session} has been obtained, it can be used to open HTTP/2 streams:</p> 25 * <pre> 26 * Session session = ...; 27 * HeadersFrame frame = ...; 28 * Promise<Stream> promise = ... 29 * session.newStream(frame, promise, new Stream.Listener.Adapter() 30 * { 31 * void onHeaders(Stream stream, HeadersFrame frame) 32 * { 33 * // Reply received 34 * } 35 * }); 36 * </pre> 37 * <p>A {@link Session} is the active part of the endpoint, and by calling its API applications can generate 38 * events on the connection; conversely {@link Session.Listener} is the passive part of the endpoint, and 39 * has callbacks that are invoked when events happen on the connection.</p> 40 * 41 * @see Session.Listener 42 */ 43 interface Session { 44 /** 45 * <p>Sends the given HEADERS {@code frame} to create a new {@link Stream}.</p> 46 * 47 * @param frame the HEADERS frame containing the HTTP headers 48 * @param promise the promise that gets notified of the stream creation 49 * @param listener the listener that gets notified of stream events 50 */ 51 void newStream(HeadersFrame frame, Promise!Stream promise, Stream.Listener listener); 52 53 /** 54 * <p>Sends the given PRIORITY {@code frame}.</p> 55 * <p>If the {@code frame} references a {@code streamId} that does not exist 56 * (for example {@code 0}), then a new {@code streamId} will be allocated, to 57 * support <em>unused anchor streams</em> that act as parent for other streams.</p> 58 * 59 * @param frame the PRIORITY frame to send 60 * @param callback the callback that gets notified when the frame has been sent 61 * @return the new stream id generated by the PRIORITY frame, or the stream id 62 * that it is already referencing 63 */ 64 int priority(PriorityFrame frame, Callback callback); 65 66 /** 67 * <p>Sends the given SETTINGS {@code frame} to configure the session.</p> 68 * 69 * @param frame the SETTINGS frame to send 70 * @param callback the callback that gets notified when the frame has been sent 71 */ 72 void settings(SettingsFrame frame, Callback callback); 73 74 /** 75 * <p>Sends the given PING {@code frame}.</p> 76 * <p>PING frames may be used to test the connection integrity and to measure 77 * round-trip time.</p> 78 * 79 * @param frame the PING frame to send 80 * @param callback the callback that gets notified when the frame has been sent 81 */ 82 void ping(PingFrame frame, Callback callback); 83 84 /** 85 * <p>Closes the session by sending a GOAWAY frame with the given error code 86 * and payload.</p> 87 * <p>The GOAWAY frame is sent only once; subsequent or concurrent attempts to 88 * close the session will have no effect.</p> 89 * 90 * @param error the error code 91 * @param payload an optional payload (may be null) 92 * @param callback the callback that gets notified when the frame has been sent 93 * @return true if the frame is being sent, false if the session was already closed 94 */ 95 bool close(int error, string payload, Callback callback); 96 97 /** 98 * @return whether the session is not open 99 */ 100 bool isClosed(); 101 102 /** 103 * @return a snapshot of all the streams currently belonging to this session 104 */ 105 Stream[] getStreams(); 106 107 /** 108 * <p>Retrieves the stream with the given {@code streamId}.</p> 109 * 110 * @param streamId the stream id of the stream looked for 111 * @return the stream with the given id, or null if no such stream exist 112 */ 113 Stream getStream(int streamId); 114 115 string toString(); 116 117 /** 118 * <p>A {@link Listener} is the passive counterpart of a {@link Session} and 119 * receives events happening on a HTTP/2 connection.</p> 120 * 121 * @see Session 122 */ 123 interface Listener 124 { 125 /** 126 * <p>Callback method invoked:</p> 127 * <ul> 128 * <li>for clients, just before the preface is sent, to gather the 129 * SETTINGS configuration options the client wants to send to the server;</li> 130 * <li>for servers, just after having received the preface, to gather 131 * the SETTINGS configuration options the server wants to send to the 132 * client.</li> 133 * </ul> 134 * 135 * @param session the session 136 * @return a (possibly empty or null) map containing SETTINGS configuration 137 * options to send. 138 */ 139 Map!(int, int) onPreface(Session session); 140 141 /** 142 * <p>Callback method invoked when a new stream is being created upon 143 * receiving a HEADERS frame representing a HTTP request.</p> 144 * <p>Applications should implement this method to process HTTP requests, 145 * typically providing a HTTP response via 146 * {@link Stream#headers(HeadersFrame, Callback)}.</p> 147 * <p>Applications can detect whether request DATA frames will be arriving 148 * by testing {@link HeadersFrame#isEndStream()}. If the application is 149 * interested in processing the DATA frames, it must return a 150 * {@link Stream.Listener} implementation that overrides 151 * {@link Stream.Listener#onData(Stream, DataFrame, Callback)}.</p> 152 * 153 * @param stream the newly created stream 154 * @param frame the HEADERS frame received 155 * @return a {@link Stream.Listener} that will be notified of stream events 156 */ 157 Stream.Listener onNewStream(Stream stream, HeadersFrame frame); 158 159 /** 160 * <p>Callback method invoked when a SETTINGS frame has been received.</p> 161 * 162 * @param session the session 163 * @param frame the SETTINGS frame received 164 */ 165 void onSettings(Session session, SettingsFrame frame); 166 167 /** 168 * <p>Callback method invoked when a PING frame has been received.</p> 169 * 170 * @param session the session 171 * @param frame the PING frame received 172 */ 173 void onPing(Session session, PingFrame frame); 174 175 /** 176 * <p>Callback method invoked when a RST_STREAM frame has been received for an unknown stream.</p> 177 * 178 * @param session the session 179 * @param frame the RST_STREAM frame received 180 * @see Stream.Listener#onReset(Stream, ResetFrame) 181 */ 182 void onReset(Session session, ResetFrame frame); 183 184 /** 185 * <p>Callback method invoked when a GOAWAY frame has been received.</p> 186 * 187 * @param session the session 188 * @param frame the GOAWAY frame received 189 * @param callback the callback to notify of the GOAWAY processing 190 */ 191 void onClose(Session session, GoAwayFrame frame, Callback callback); 192 193 void onClose(Session session, GoAwayFrame frame); 194 195 /** 196 * <p>Callback method invoked when the idle timeout expired.</p> 197 * @param session the session 198 * @return whether the session should be closed 199 */ 200 bool onIdleTimeout(Session session); 201 202 /** 203 * <p>Callback method invoked when a failure has been detected for this session.</p> 204 * 205 * @param session the session 206 * @param failure the failure 207 * @param callback the callback to notify of failure processing 208 */ 209 void onFailure(Session session, Exception failure, Callback callback); 210 211 void onFailure(Session session, Exception failure); 212 213 // final void onClose(Session session, GoAwayFrame frame, Callback callback) 214 // { 215 // try 216 // { 217 // onClose(session, frame); 218 // callback.succeeded(); 219 // } 220 // catch (Exception x) 221 // { 222 // callback.failed(x); 223 // } 224 // } 225 226 // final void onFailure(Session session, Throwable failure, Callback callback) 227 // { 228 // try 229 // { 230 // onFailure(session, failure); 231 // callback.succeeded(); 232 // } 233 // catch (Exception x) 234 // { 235 // callback.failed(x); 236 // } 237 // } 238 239 string toString(); 240 241 /** 242 * <p>Empty implementation of {@link Stream.Listener}.</p> 243 */ 244 static class Adapter : Session.Listener 245 { 246 247 Map!(int, int) onPreface(Session session) 248 { 249 return null; 250 } 251 252 Stream.Listener onNewStream(Stream stream, HeadersFrame frame) 253 { 254 return null; 255 } 256 257 void onSettings(Session session, SettingsFrame frame) 258 { 259 } 260 261 void onPing(Session session, PingFrame frame) 262 { 263 } 264 265 void onReset(Session session, ResetFrame frame) 266 { 267 } 268 269 void onClose(Session session, GoAwayFrame frame) 270 { 271 } 272 273 void onClose(Session session, GoAwayFrame frame, Callback callback) 274 { 275 try 276 { 277 onClose(session, frame); 278 callback.succeeded(); 279 } 280 catch (Exception x) 281 { 282 callback.failed(x); 283 } 284 } 285 286 bool onIdleTimeout(Session session) 287 { 288 return true; 289 } 290 291 void onFailure(Session session, Exception failure) 292 { 293 } 294 295 void onFailure(Session session, Exception failure, Callback callback) 296 { 297 try 298 { 299 onFailure(session, failure); 300 callback.succeeded(); 301 } 302 catch (Exception x) 303 { 304 callback.failed(x); 305 } 306 } 307 308 override string toString() 309 { 310 return super.toString(); 311 } 312 } 313 } 314 }