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    * http://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, io.netty.buffer.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 }