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.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 }