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&lt;Stream&gt; 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 }