1 /*
2 * Copyright 2014 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
5 * "License"); you may not use this file except in compliance with the License. You may obtain a
6 * copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software distributed under the License
11 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12 * or implied. See the License for the specific language governing permissions and limitations under
13 * the License.
14 */
15
16 package io.netty5.handler.codec.http2;
17
18 import io.netty5.buffer.api.Buffer;
19 import io.netty5.util.concurrent.Promise;
20 import io.netty5.util.internal.UnstableApi;
21
22 /**
23 * Manager for the state of an HTTP/2 connection with the remote end-point.
24 */
25 @UnstableApi
26 public interface Http2Connection {
27 /**
28 * Listener for life-cycle events for streams in this connection.
29 */
30 interface Listener {
31 /**
32 * Notifies the listener that the given stream was added to the connection. This stream may
33 * not yet be active (i.e. {@code OPEN} or {@code HALF CLOSED}).
34 * <p>
35 * If a {@link RuntimeException} is thrown it will be logged and <strong>not propagated</strong>.
36 * Throwing from this method is not supported and is considered a programming error.
37 */
38 void onStreamAdded(Http2Stream stream);
39
40 /**
41 * Notifies the listener that the given stream was made active (i.e. {@code OPEN} or {@code HALF CLOSED}).
42 * <p>
43 * If a {@link RuntimeException} is thrown it will be logged and <strong>not propagated</strong>.
44 * Throwing from this method is not supported and is considered a programming error.
45 */
46 void onStreamActive(Http2Stream stream);
47
48 /**
49 * Notifies the listener that the given stream has transitioned from {@code OPEN} to {@code HALF CLOSED}.
50 * This method will <strong>not</strong> be called until a state transition occurs from when
51 * {@link #onStreamActive(Http2Stream)} was called.
52 * The stream can be inspected to determine which side is {@code HALF CLOSED}.
53 * <p>
54 * If a {@link RuntimeException} is thrown it will be logged and <strong>not propagated</strong>.
55 * Throwing from this method is not supported and is considered a programming error.
56 */
57 void onStreamHalfClosed(Http2Stream stream);
58
59 /**
60 * Notifies the listener that the given stream is now {@code CLOSED} in both directions and will no longer
61 * be accessible via {@link #forEachActiveStream(Http2StreamVisitor)}.
62 * <p>
63 * If a {@link RuntimeException} is thrown it will be logged and <strong>not propagated</strong>.
64 * Throwing from this method is not supported and is considered a programming error.
65 */
66 void onStreamClosed(Http2Stream stream);
67
68 /**
69 * Notifies the listener that the given stream has now been removed from the connection and
70 * will no longer be returned via {@link Http2Connection#stream(int)}. The connection may
71 * maintain inactive streams for some time before removing them.
72 * <p>
73 * If a {@link RuntimeException} is thrown it will be logged and <strong>not propagated</strong>.
74 * Throwing from this method is not supported and is considered a programming error.
75 */
76 void onStreamRemoved(Http2Stream stream);
77
78 /**
79 * Called when a {@code GOAWAY} frame was sent for the connection.
80 * <p>
81 * If a {@link RuntimeException} is thrown it will be logged and <strong>not propagated</strong>.
82 * Throwing from this method is not supported and is considered a programming error.
83 * @param lastStreamId the last known stream of the remote endpoint.
84 * @param errorCode the error code, if abnormal closure.
85 * @param debugData application-defined debug data.
86 */
87 void onGoAwaySent(int lastStreamId, long errorCode, Buffer debugData);
88
89 /**
90 * Called when a {@code GOAWAY} was received from the remote endpoint. This event handler duplicates {@link
91 * Http2FrameListener#onGoAwayRead(io.netty5.channel.ChannelHandlerContext, int, long, Buffer)}
92 * but is added here in order to simplify application logic for handling {@code GOAWAY} in a uniform way. An
93 * application should generally not handle both events, but if it does this method is called second, after
94 * notifying the {@link Http2FrameListener}.
95 * <p>
96 * If a {@link RuntimeException} is thrown it will be logged and <strong>not propagated</strong>.
97 * Throwing from this method is not supported and is considered a programming error.
98 * @param lastStreamId the last known stream of the remote endpoint.
99 * @param errorCode the error code, if abnormal closure.
100 * @param debugData application-defined debug data.
101 */
102 void onGoAwayReceived(int lastStreamId, long errorCode, Buffer debugData);
103 }
104
105 /**
106 * A view of the connection from one endpoint (local or remote).
107 */
108 interface Endpoint<F extends Http2FlowController> {
109 /**
110 * Increment and get the next generated stream id this endpoint. If negative, the stream IDs are
111 * exhausted for this endpoint an no further streams may be created.
112 */
113 int incrementAndGetNextStreamId();
114
115 /**
116 * Indicates whether the given streamId is from the set of IDs used by this endpoint to
117 * create new streams.
118 */
119 boolean isValidStreamId(int streamId);
120
121 /**
122 * Indicates whether or not this endpoint may have created the given stream. This is {@code true} if
123 * {@link #isValidStreamId(int)} and {@code streamId} <= {@link #lastStreamCreated()}.
124 */
125 boolean mayHaveCreatedStream(int streamId);
126
127 /**
128 * Indicates whether or not this endpoint created the given stream.
129 */
130 boolean created(Http2Stream stream);
131
132 /**
133 * Indicates whether or a stream created by this endpoint can be opened without violating
134 * {@link #maxActiveStreams()}.
135 */
136 boolean canOpenStream();
137
138 /**
139 * Creates a stream initiated by this endpoint. This could fail for the following reasons:
140 * <ul>
141 * <li>The requested stream ID is not the next sequential ID for this endpoint.</li>
142 * <li>The stream already exists.</li>
143 * <li>{@link #canOpenStream()} is {@code false}.</li>
144 * <li>The connection is marked as going away.</li>
145 * </ul>
146 * <p>
147 * The initial state of the stream will be immediately set before notifying {@link Listener}s. The state
148 * transition is sensitive to {@code halfClosed} and is defined by {@link Http2Stream#open(boolean)}.
149 * @param streamId The ID of the stream
150 * @param halfClosed see {@link Http2Stream#open(boolean)}.
151 * @see Http2Stream#open(boolean)
152 */
153 Http2Stream createStream(int streamId, boolean halfClosed) throws Http2Exception;
154
155 /**
156 * Creates a push stream in the reserved state for this endpoint and notifies all listeners.
157 * This could fail for the following reasons:
158 * <ul>
159 * <li>Server push is not allowed to the opposite endpoint.</li>
160 * <li>The requested stream ID is not the next sequential stream ID for this endpoint.</li>
161 * <li>The number of concurrent streams is above the allowed threshold for this endpoint.</li>
162 * <li>The connection is marked as going away.</li>
163 * <li>The parent stream ID does not exist or is not {@code OPEN} from the side sending the push
164 * promise.</li>
165 * <li>Could not set a valid priority for the new stream.</li>
166 * </ul>
167 *
168 * @param streamId the ID of the push stream
169 * @param parent the parent stream used to initiate the push stream.
170 */
171 Http2Stream reservePushStream(int streamId, Http2Stream parent) throws Http2Exception;
172
173 /**
174 * Indicates whether or not this endpoint is the server-side of the connection.
175 */
176 boolean isServer();
177
178 /**
179 * This is the <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_ENABLE_PUSH</a> value sent
180 * from the opposite endpoint. This method should only be called by Netty (not users) as a result of a
181 * receiving a {@code SETTINGS} frame.
182 */
183 void allowPushTo(boolean allow);
184
185 /**
186 * This is the <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_ENABLE_PUSH</a> value sent
187 * from the opposite endpoint. The initial value must be {@code true} for the client endpoint and always false
188 * for a server endpoint.
189 */
190 boolean allowPushTo();
191
192 /**
193 * Gets the number of active streams (i.e. {@code OPEN} or {@code HALF CLOSED}) that were created by this
194 * endpoint.
195 */
196 int numActiveStreams();
197
198 /**
199 * Gets the maximum number of streams (created by this endpoint) that are allowed to be active at
200 * the same time. This is the
201 * <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_CONCURRENT_STREAMS</a>
202 * value sent from the opposite endpoint to restrict stream creation by this endpoint.
203 * <p>
204 * The default value returned by this method must be "unlimited".
205 */
206 int maxActiveStreams();
207
208 /**
209 * Sets the limit for {@code SETTINGS_MAX_CONCURRENT_STREAMS}.
210 * @param maxActiveStreams The maximum number of streams (created by this endpoint) that are allowed to be
211 * active at once. This is the
212 * <a href="https://tools.ietf.org/html/rfc7540#section-6.5.2">SETTINGS_MAX_CONCURRENT_STREAMS</a> value sent
213 * from the opposite endpoint to restrict stream creation by this endpoint.
214 */
215 void maxActiveStreams(int maxActiveStreams);
216
217 /**
218 * Gets the ID of the stream last successfully created by this endpoint.
219 */
220 int lastStreamCreated();
221
222 /**
223 * If a GOAWAY was received for this endpoint, this will be the last stream ID from the
224 * GOAWAY frame. Otherwise, this will be {@code -1}.
225 */
226 int lastStreamKnownByPeer();
227
228 /**
229 * Gets the flow controller for this endpoint.
230 */
231 F flowController();
232
233 /**
234 * Sets the flow controller for this endpoint.
235 */
236 void flowController(F flowController);
237
238 /**
239 * Gets the {@link Endpoint} opposite this one.
240 */
241 Endpoint<? extends Http2FlowController> opposite();
242 }
243
244 /**
245 * A key to be used for associating application-defined properties with streams within this connection.
246 */
247 interface PropertyKey {
248 }
249
250 /**
251 * Close this connection. No more new streams can be created after this point and
252 * all streams that exists (active or otherwise) will be closed and removed.
253 * <p>Note if iterating active streams via {@link #forEachActiveStream(Http2StreamVisitor)} and an exception is
254 * thrown it is necessary to call this method again to ensure the close completes.
255 *
256 * @param promise Will be completed when all streams have been removed, and listeners have been notified.
257 */
258 void close(Promise<Void> promise);
259
260 /**
261 * Creates a new key that is unique within this {@link Http2Connection}.
262 */
263 PropertyKey newKey();
264
265 /**
266 * Adds a listener of stream life-cycle events.
267 */
268 void addListener(Listener listener);
269
270 /**
271 * Removes a listener of stream life-cycle events. If the same listener was added multiple times
272 * then only the first occurrence gets removed.
273 */
274 void removeListener(Listener listener);
275
276 /**
277 * Gets the stream if it exists. If not, returns {@code null}.
278 */
279 Http2Stream stream(int streamId);
280
281 /**
282 * Indicates whether or not the given stream may have existed within this connection. This is a short form
283 * for calling {@link Endpoint#mayHaveCreatedStream(int)} on both endpoints.
284 */
285 boolean streamMayHaveExisted(int streamId);
286
287 /**
288 * Gets the stream object representing the connection, itself (i.e. stream zero). This object
289 * always exists.
290 */
291 Http2Stream connectionStream();
292
293 /**
294 * Gets the number of streams that are actively in use (i.e. {@code OPEN} or {@code HALF CLOSED}).
295 */
296 int numActiveStreams();
297
298 /**
299 * Provide a means of iterating over the collection of active streams.
300 *
301 * @param visitor The visitor which will visit each active stream.
302 * @return The stream before iteration stopped or {@code null} if iteration went past the end.
303 */
304 Http2Stream forEachActiveStream(Http2StreamVisitor visitor) throws Http2Exception;
305
306 /**
307 * Indicates whether or not the local endpoint for this connection is the server.
308 */
309 boolean isServer();
310
311 /**
312 * Gets a view of this connection from the local {@link Endpoint}.
313 */
314 Endpoint<Http2LocalFlowController> local();
315
316 /**
317 * Gets a view of this connection from the remote {@link Endpoint}.
318 */
319 Endpoint<Http2RemoteFlowController> remote();
320
321 /**
322 * Indicates whether or not a {@code GOAWAY} was received from the remote endpoint.
323 */
324 boolean goAwayReceived();
325
326 /**
327 * Indicates that a {@code GOAWAY} was received from the remote endpoint and sets the last known stream.
328 * @param lastKnownStream The Last-Stream-ID in the
329 * <a href="https://tools.ietf.org/html/rfc7540#section-6.8">GOAWAY</a> frame.
330 * @param errorCode the Error Code in the
331 * <a href="https://tools.ietf.org/html/rfc7540#section-6.8">GOAWAY</a> frame.
332 * @param message The Additional Debug Data in the
333 * <a href="https://tools.ietf.org/html/rfc7540#section-6.8">GOAWAY</a> frame. Note that reference count ownership
334 * belongs to the caller (ownership is not transferred to this method).
335 */
336 void goAwayReceived(int lastKnownStream, long errorCode, Buffer message) throws Http2Exception;
337
338 /**
339 * Indicates whether or not a {@code GOAWAY} was sent to the remote endpoint.
340 */
341 boolean goAwaySent();
342
343 /**
344 * Updates the local state of this {@link Http2Connection} as a result of a {@code GOAWAY} to send to the remote
345 * endpoint.
346 * @param lastKnownStream The Last-Stream-ID in the
347 * <a href="https://tools.ietf.org/html/rfc7540#section-6.8">GOAWAY</a> frame.
348 * @param errorCode the Error Code in the
349 * <a href="https://tools.ietf.org/html/rfc7540#section-6.8">GOAWAY</a> frame.
350 * <a href="https://tools.ietf.org/html/rfc7540#section-6.8">GOAWAY</a> frame. Note that reference count ownership
351 * belongs to the caller (ownership is not transferred to this method).
352 * @return {@code true} if the corresponding {@code GOAWAY} frame should be sent to the remote endpoint.
353 */
354 boolean goAwaySent(int lastKnownStream, long errorCode, Buffer message) throws Http2Exception;
355 }