View Javadoc
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 }