1 /* 2 * nghttp2 - HTTP/2 C Library 3 * 4 * Copyright (c) 2012 Tatsuhiro Tsujikawa 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 #ifndef NGHTTP2_STREAM_H 26 #define NGHTTP2_STREAM_H 27 28 #ifdef HAVE_CONFIG_H 29 # include <config.h> 30 #endif /* HAVE_CONFIG_H */ 31 32 #include <nghttp2/nghttp2.h> 33 #include "nghttp2_outbound_item.h" 34 #include "nghttp2_map.h" 35 #include "nghttp2_pq.h" 36 #include "nghttp2_int.h" 37 38 /* 39 * If local peer is stream initiator: 40 * NGHTTP2_STREAM_OPENING : upon sending request HEADERS 41 * NGHTTP2_STREAM_OPENED : upon receiving response HEADERS 42 * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM 43 * 44 * If remote peer is stream initiator: 45 * NGHTTP2_STREAM_OPENING : upon receiving request HEADERS 46 * NGHTTP2_STREAM_OPENED : upon sending response HEADERS 47 * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM 48 */ 49 typedef enum { 50 /* Initial state */ 51 NGHTTP2_STREAM_INITIAL, 52 /* For stream initiator: request HEADERS has been sent, but response 53 HEADERS has not been received yet. For receiver: request HEADERS 54 has been received, but it does not send response HEADERS yet. */ 55 NGHTTP2_STREAM_OPENING, 56 /* For stream initiator: response HEADERS is received. For receiver: 57 response HEADERS is sent. */ 58 NGHTTP2_STREAM_OPENED, 59 /* RST_STREAM is received, but somehow we need to keep stream in 60 memory. */ 61 NGHTTP2_STREAM_CLOSING, 62 /* PUSH_PROMISE is received or sent */ 63 NGHTTP2_STREAM_RESERVED, 64 /* Stream is created in this state if it is used as anchor in 65 dependency tree. */ 66 NGHTTP2_STREAM_IDLE 67 } nghttp2_stream_state; 68 69 typedef enum { 70 NGHTTP2_SHUT_NONE = 0, 71 /* Indicates further receptions will be disallowed. */ 72 NGHTTP2_SHUT_RD = 0x01, 73 /* Indicates further transmissions will be disallowed. */ 74 NGHTTP2_SHUT_WR = 0x02, 75 /* Indicates both further receptions and transmissions will be 76 disallowed. */ 77 NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR 78 } nghttp2_shut_flag; 79 80 typedef enum { 81 NGHTTP2_STREAM_FLAG_NONE = 0, 82 /* Indicates that this stream is pushed stream and not opened 83 yet. */ 84 NGHTTP2_STREAM_FLAG_PUSH = 0x01, 85 /* Indicates that this stream was closed */ 86 NGHTTP2_STREAM_FLAG_CLOSED = 0x02, 87 /* Indicates the item is deferred due to flow control. */ 88 NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04, 89 /* Indicates the item is deferred by user callback */ 90 NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08, 91 /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and 92 NGHTTP2_STREAM_FLAG_DEFERRED_USER. */ 93 NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c 94 95 } nghttp2_stream_flag; 96 97 /* HTTP related flags to enforce HTTP semantics */ 98 typedef enum { 99 NGHTTP2_HTTP_FLAG_NONE = 0, 100 /* header field seen so far */ 101 NGHTTP2_HTTP_FLAG__AUTHORITY = 1, 102 NGHTTP2_HTTP_FLAG__PATH = 1 << 1, 103 NGHTTP2_HTTP_FLAG__METHOD = 1 << 2, 104 NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3, 105 /* host is not pseudo header, but we require either host or 106 :authority */ 107 NGHTTP2_HTTP_FLAG_HOST = 1 << 4, 108 NGHTTP2_HTTP_FLAG__STATUS = 1 << 5, 109 /* required header fields for HTTP request except for CONNECT 110 method. */ 111 NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD | 112 NGHTTP2_HTTP_FLAG__PATH | 113 NGHTTP2_HTTP_FLAG__SCHEME, 114 NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6, 115 /* HTTP method flags */ 116 NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7, 117 NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8, 118 NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9, 119 NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10, 120 NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT | 121 NGHTTP2_HTTP_FLAG_METH_HEAD | 122 NGHTTP2_HTTP_FLAG_METH_OPTIONS | 123 NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND, 124 /* :path category */ 125 /* path starts with "/" */ 126 NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11, 127 /* path "*" */ 128 NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12, 129 /* scheme */ 130 /* "http" or "https" scheme */ 131 NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13, 132 /* set if final response is expected */ 133 NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14, 134 NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15, 135 } nghttp2_http_flag; 136 137 struct nghttp2_stream { 138 /* Intrusive Map */ 139 nghttp2_map_entry map_entry; 140 /* Entry for dep_prev->obq */ 141 nghttp2_pq_entry pq_entry; 142 /* Priority Queue storing direct descendant (nghttp2_stream). Only 143 streams which itself has some data to send, or has a descendant 144 which has some data to sent. */ 145 nghttp2_pq obq; 146 /* Content-Length of request/response body. -1 if unknown. */ 147 int64_t content_length; 148 /* Received body so far */ 149 int64_t recv_content_length; 150 /* Base last_cycle for direct descendent streams. */ 151 uint64_t descendant_last_cycle; 152 /* Next scheduled time to sent item */ 153 uint64_t cycle; 154 /* Next seq used for direct descendant streams */ 155 uint64_t descendant_next_seq; 156 /* Secondary key for prioritization to break a tie for cycle. This 157 value is monotonically increased for single parent stream. */ 158 uint64_t seq; 159 /* pointers to form dependency tree. If multiple streams depend on 160 a stream, only one stream (left most) has non-NULL dep_prev which 161 points to the stream it depends on. The remaining streams are 162 linked using sib_prev and sib_next. The stream which has 163 non-NULL dep_prev always NULL sib_prev. The right most stream 164 has NULL sib_next. If this stream is a root of dependency tree, 165 dep_prev and sib_prev are NULL. */ 166 nghttp2_stream *dep_prev, *dep_next; 167 nghttp2_stream *sib_prev, *sib_next; 168 /* When stream is kept after closure, it may be kept in doubly 169 linked list pointed by nghttp2_session closed_stream_head. 170 closed_next points to the next stream object if it is the element 171 of the list. */ 172 nghttp2_stream *closed_prev, *closed_next; 173 /* The arbitrary data provided by user for this stream. */ 174 void *stream_user_data; 175 /* Item to send */ 176 nghttp2_outbound_item *item; 177 /* Last written length of frame payload */ 178 size_t last_writelen; 179 /* stream ID */ 180 int32_t stream_id; 181 /* Current remote window size. This value is computed against the 182 current initial window size of remote endpoint. */ 183 int32_t remote_window_size; 184 /* Keep track of the number of bytes received without 185 WINDOW_UPDATE. This could be negative after submitting negative 186 value to WINDOW_UPDATE */ 187 int32_t recv_window_size; 188 /* The number of bytes consumed by the application and now is 189 subject to WINDOW_UPDATE. This is only used when auto 190 WINDOW_UPDATE is turned off. */ 191 int32_t consumed_size; 192 /* The amount of recv_window_size cut using submitting negative 193 value to WINDOW_UPDATE */ 194 int32_t recv_reduction; 195 /* window size for local flow control. It is initially set to 196 NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by 197 submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ 198 int32_t local_window_size; 199 /* weight of this stream */ 200 int32_t weight; 201 /* This is unpaid penalty (offset) when calculating cycle. */ 202 uint32_t pending_penalty; 203 /* sum of weight of direct descendants */ 204 int32_t sum_dep_weight; 205 nghttp2_stream_state state; 206 /* status code from remote server */ 207 int16_t status_code; 208 /* Bitwise OR of zero or more nghttp2_http_flag values */ 209 uint16_t http_flags; 210 /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */ 211 uint8_t flags; 212 /* Bitwise OR of zero or more nghttp2_shut_flag values */ 213 uint8_t shut_flags; 214 /* Nonzero if this stream has been queued to stream pointed by 215 dep_prev. We maintain the invariant that if a stream is queued, 216 then its ancestors, except for root, are also queued. This 217 invariant may break in fatal error condition. */ 218 uint8_t queued; 219 /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to 220 this stream. The nonzero does not necessarily mean WINDOW_UPDATE 221 is not queued. */ 222 uint8_t window_update_queued; 223 }; 224 225 void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, 226 uint8_t flags, nghttp2_stream_state initial_state, 227 int32_t weight, int32_t remote_initial_window_size, 228 int32_t local_initial_window_size, 229 void *stream_user_data, nghttp2_mem *mem); 230 231 void nghttp2_stream_free(nghttp2_stream *stream); 232 233 /* 234 * Disallow either further receptions or transmissions, or both. 235 * |flag| is bitwise OR of one or more of nghttp2_shut_flag. 236 */ 237 void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag); 238 239 /* 240 * Defer |stream->item|. We won't call this function in the situation 241 * where |stream->item| == NULL. The |flags| is bitwise OR of zero or 242 * more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and 243 * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates 244 * the reason of this action. 245 * 246 * This function returns 0 if it succeeds, or one of the following 247 * negative error codes: 248 * 249 * NGHTTP2_ERR_NOMEM 250 * Out of memory 251 */ 252 int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags); 253 254 /* 255 * Put back deferred data in this stream to active state. The |flags| 256 * are one or more of bitwise OR of the following values: 257 * NGHTTP2_STREAM_FLAG_DEFERRED_USER and 258 * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are 259 * cleared if they are set. So even if this function is called, if 260 * one of flag is still set, data does not become active. 261 * 262 * This function returns 0 if it succeeds, or one of the following 263 * negative error codes: 264 * 265 * NGHTTP2_ERR_NOMEM 266 * Out of memory 267 */ 268 int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); 269 270 /* 271 * Returns nonzero if item is deferred by whatever reason. 272 */ 273 int nghttp2_stream_check_deferred_item(nghttp2_stream *stream); 274 275 /* 276 * Returns nonzero if item is deferred by flow control. 277 */ 278 int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream); 279 280 /* 281 * Updates the remote window size with the new value 282 * |new_initial_window_size|. The |old_initial_window_size| is used to 283 * calculate the current window size. 284 * 285 * This function returns 0 if it succeeds or -1. The failure is due to 286 * overflow. 287 */ 288 int nghttp2_stream_update_remote_initial_window_size( 289 nghttp2_stream *stream, int32_t new_initial_window_size, 290 int32_t old_initial_window_size); 291 292 /* 293 * Updates the local window size with the new value 294 * |new_initial_window_size|. The |old_initial_window_size| is used to 295 * calculate the current window size. 296 * 297 * This function returns 0 if it succeeds or -1. The failure is due to 298 * overflow. 299 */ 300 int nghttp2_stream_update_local_initial_window_size( 301 nghttp2_stream *stream, int32_t new_initial_window_size, 302 int32_t old_initial_window_size); 303 304 /* 305 * Call this function if promised stream |stream| is replied with 306 * HEADERS. This function makes the state of the |stream| to 307 * NGHTTP2_STREAM_OPENED. 308 */ 309 void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream); 310 311 /* 312 * Returns nonzero if |target| is an ancestor of |stream|. 313 */ 314 int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, 315 nghttp2_stream *target); 316 317 /* 318 * Computes distributed weight of a stream of the |weight| under the 319 * |stream| if |stream| is removed from a dependency tree. 320 */ 321 int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, 322 int32_t weight); 323 324 /* 325 * Makes the |stream| depend on the |dep_stream|. This dependency is 326 * exclusive. All existing direct descendants of |dep_stream| become 327 * the descendants of the |stream|. This function assumes 328 * |stream->item| is NULL. 329 * 330 * This function returns 0 if it succeeds, or one of the following 331 * negative error codes: 332 * 333 * NGHTTP2_ERR_NOMEM 334 * Out of memory 335 */ 336 int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, 337 nghttp2_stream *stream); 338 339 /* 340 * Makes the |stream| depend on the |dep_stream|. This dependency is 341 * not exclusive. This function assumes |stream->item| is NULL. 342 */ 343 void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream); 344 345 /* 346 * Removes the |stream| from the current dependency tree. This 347 * function assumes |stream->item| is NULL. 348 */ 349 int nghttp2_stream_dep_remove(nghttp2_stream *stream); 350 351 /* 352 * Attaches |item| to |stream|. 353 * 354 * This function returns 0 if it succeeds, or one of the following 355 * negative error codes: 356 * 357 * NGHTTP2_ERR_NOMEM 358 * Out of memory 359 */ 360 int nghttp2_stream_attach_item(nghttp2_stream *stream, 361 nghttp2_outbound_item *item); 362 363 /* 364 * Detaches |stream->item|. This function does not free 365 * |stream->item|. The caller must free it. 366 * 367 * This function returns 0 if it succeeds, or one of the following 368 * negative error codes: 369 * 370 * NGHTTP2_ERR_NOMEM 371 * Out of memory 372 */ 373 int nghttp2_stream_detach_item(nghttp2_stream *stream); 374 375 /* 376 * Makes the |stream| depend on the |dep_stream|. This dependency is 377 * exclusive. 378 * 379 * This function returns 0 if it succeeds, or one of the following 380 * negative error codes: 381 * 382 * NGHTTP2_ERR_NOMEM 383 * Out of memory 384 */ 385 int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, 386 nghttp2_stream *stream); 387 388 /* 389 * Makes the |stream| depend on the |dep_stream|. This dependency is 390 * not exclusive. 391 * 392 * This function returns 0 if it succeeds, or one of the following 393 * negative error codes: 394 * 395 * NGHTTP2_ERR_NOMEM 396 * Out of memory 397 */ 398 int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, 399 nghttp2_stream *stream); 400 401 /* 402 * Removes subtree whose root stream is |stream|. The 403 * effective_weight of streams in removed subtree is not updated. 404 * 405 * This function returns 0 if it succeeds, or one of the following 406 * negative error codes: 407 * 408 * NGHTTP2_ERR_NOMEM 409 * Out of memory 410 */ 411 void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); 412 413 /* 414 * Returns nonzero if |stream| is in any dependency tree. 415 */ 416 int nghttp2_stream_in_dep_tree(nghttp2_stream *stream); 417 418 /* 419 * Schedules transmission of |stream|'s item, assuming stream->item is 420 * attached, and stream->last_writelen was updated. 421 */ 422 void nghttp2_stream_reschedule(nghttp2_stream *stream); 423 424 /* 425 * Changes |stream|'s weight to |weight|. If |stream| is queued, it 426 * will be rescheduled based on new weight. 427 */ 428 void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight); 429 430 /* 431 * Returns a stream which has highest priority, updating 432 * descendant_last_cycle of selected stream's ancestors. 433 */ 434 nghttp2_outbound_item * 435 nghttp2_stream_next_outbound_item(nghttp2_stream *stream); 436 437 #endif /* NGHTTP2_STREAM */ 438