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