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 }