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