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.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; 135 136 struct nghttp2_stream { 137 /* Intrusive Map */ 138 nghttp2_map_entry map_entry; 139 /* Entry for dep_prev->obq */ 140 nghttp2_pq_entry pq_entry; 141 /* Priority Queue storing direct descendant (nghttp2_stream). Only 142 streams which itself has some data to send, or has a descendant 143 which has some data to sent. */ 144 nghttp2_pq obq; 145 /* Content-Length of request/response body. -1 if unknown. */ 146 int64_t content_length; 147 /* Received body so far */ 148 int64_t recv_content_length; 149 /* Base last_cycle for direct descendent streams. */ 150 uint32_t descendant_last_cycle; 151 /* Next scheduled time to sent item */ 152 uint32_t cycle; 153 /* Next seq used for direct descendant streams */ 154 uint64_t descendant_next_seq; 155 /* Secondary key for prioritization to break a tie for cycle. This 156 value is monotonically increased for single parent stream. */ 157 uint64_t seq; 158 /* pointers to form dependency tree. If multiple streams depend on 159 a stream, only one stream (left most) has non-NULL dep_prev which 160 points to the stream it depends on. The remaining streams are 161 linked using sib_prev and sib_next. The stream which has 162 non-NULL dep_prev always NULL sib_prev. The right most stream 163 has NULL sib_next. If this stream is a root of dependency tree, 164 dep_prev and sib_prev are NULL. */ 165 nghttp2_stream *dep_prev, *dep_next; 166 nghttp2_stream *sib_prev, *sib_next; 167 /* When stream is kept after closure, it may be kept in doubly 168 linked list pointed by nghttp2_session closed_stream_head. 169 closed_next points to the next stream object if it is the element 170 of the list. */ 171 nghttp2_stream *closed_prev, *closed_next; 172 /* The arbitrary data provided by user for this stream. */ 173 void *stream_user_data; 174 /* Item to send */ 175 nghttp2_outbound_item *item; 176 /* Last written length of frame payload */ 177 size_t last_writelen; 178 /* stream ID */ 179 int32_t stream_id; 180 /* Current remote window size. This value is computed against the 181 current initial window size of remote endpoint. */ 182 int32_t remote_window_size; 183 /* Keep track of the number of bytes received without 184 WINDOW_UPDATE. This could be negative after submitting negative 185 value to WINDOW_UPDATE */ 186 int32_t recv_window_size; 187 /* The number of bytes consumed by the application and now is 188 subject to WINDOW_UPDATE. This is only used when auto 189 WINDOW_UPDATE is turned off. */ 190 int32_t consumed_size; 191 /* The amount of recv_window_size cut using submitting negative 192 value to WINDOW_UPDATE */ 193 int32_t recv_reduction; 194 /* window size for local flow control. It is initially set to 195 NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by 196 submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */ 197 int32_t local_window_size; 198 /* weight of this stream */ 199 int32_t weight; 200 /* This is unpaid penalty (offset) when calculating cycle. */ 201 uint32_t pending_penalty; 202 /* sum of weight of direct descendants */ 203 int32_t sum_dep_weight; 204 nghttp2_stream_state state; 205 /* status code from remote server */ 206 int16_t status_code; 207 /* Bitwise OR of zero or more nghttp2_http_flag values */ 208 uint16_t http_flags; 209 /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */ 210 uint8_t flags; 211 /* Bitwise OR of zero or more nghttp2_shut_flag values */ 212 uint8_t shut_flags; 213 /* Nonzero if this stream has been queued to stream pointed by 214 dep_prev. We maintain the invariant that if a stream is queued, 215 then its ancestors, except for root, are also queued. This 216 invariant may break in fatal error condition. */ 217 uint8_t queued; 218 /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to 219 this stream. The nonzero does not necessarily mean WINDOW_UPDATE 220 is not queued. */ 221 uint8_t window_update_queued; 222 }; 223 224 void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, 225 uint8_t flags, nghttp2_stream_state initial_state, 226 int32_t weight, int32_t remote_initial_window_size, 227 int32_t local_initial_window_size, 228 void *stream_user_data, nghttp2_mem *mem); 229 230 void nghttp2_stream_free(nghttp2_stream *stream); 231 232 /* 233 * Disallow either further receptions or transmissions, or both. 234 * |flag| is bitwise OR of one or more of nghttp2_shut_flag. 235 */ 236 void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag); 237 238 /* 239 * Defer |stream->item|. We won't call this function in the situation 240 * where |stream->item| == NULL. The |flags| is bitwise OR of zero or 241 * more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and 242 * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates 243 * the reason of this action. 244 * 245 * This function returns 0 if it succeeds, or one of the following 246 * negative error codes: 247 * 248 * NGHTTP2_ERR_NOMEM 249 * Out of memory 250 */ 251 int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags); 252 253 /* 254 * Put back deferred data in this stream to active state. The |flags| 255 * are one or more of bitwise OR of the following values: 256 * NGHTTP2_STREAM_FLAG_DEFERRED_USER and 257 * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are 258 * cleared if they are set. So even if this function is called, if 259 * one of flag is still set, data does not become active. 260 * 261 * This function returns 0 if it succeeds, or one of the following 262 * negative error codes: 263 * 264 * NGHTTP2_ERR_NOMEM 265 * Out of memory 266 */ 267 int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags); 268 269 /* 270 * Returns nonzero if item is deferred by whatever reason. 271 */ 272 int nghttp2_stream_check_deferred_item(nghttp2_stream *stream); 273 274 /* 275 * Returns nonzero if item is deferred by flow control. 276 */ 277 int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream); 278 279 /* 280 * Updates the remote window size with the new value 281 * |new_initial_window_size|. The |old_initial_window_size| is used to 282 * calculate the current window size. 283 * 284 * This function returns 0 if it succeeds or -1. The failure is due to 285 * overflow. 286 */ 287 int nghttp2_stream_update_remote_initial_window_size( 288 nghttp2_stream *stream, int32_t new_initial_window_size, 289 int32_t old_initial_window_size); 290 291 /* 292 * Updates the local window size with the new value 293 * |new_initial_window_size|. The |old_initial_window_size| is used to 294 * calculate the current window size. 295 * 296 * This function returns 0 if it succeeds or -1. The failure is due to 297 * overflow. 298 */ 299 int nghttp2_stream_update_local_initial_window_size( 300 nghttp2_stream *stream, int32_t new_initial_window_size, 301 int32_t old_initial_window_size); 302 303 /* 304 * Call this function if promised stream |stream| is replied with 305 * HEADERS. This function makes the state of the |stream| to 306 * NGHTTP2_STREAM_OPENED. 307 */ 308 void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream); 309 310 /* 311 * Returns nonzero if |target| is an ancestor of |stream|. 312 */ 313 int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream, 314 nghttp2_stream *target); 315 316 /* 317 * Computes distributed weight of a stream of the |weight| under the 318 * |stream| if |stream| is removed from a dependency tree. 319 */ 320 int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream, 321 int32_t weight); 322 323 /* 324 * Makes the |stream| depend on the |dep_stream|. This dependency is 325 * exclusive. All existing direct descendants of |dep_stream| become 326 * the descendants of the |stream|. This function assumes 327 * |stream->item| is NULL. 328 * 329 * This function returns 0 if it succeeds, or one of the following 330 * negative error codes: 331 * 332 * NGHTTP2_ERR_NOMEM 333 * Out of memory 334 */ 335 int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream, 336 nghttp2_stream *stream); 337 338 /* 339 * Makes the |stream| depend on the |dep_stream|. This dependency is 340 * not exclusive. This function assumes |stream->item| is NULL. 341 */ 342 void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream); 343 344 /* 345 * Removes the |stream| from the current dependency tree. This 346 * function assumes |stream->item| is NULL. 347 */ 348 int nghttp2_stream_dep_remove(nghttp2_stream *stream); 349 350 /* 351 * Attaches |item| to |stream|. 352 * 353 * This function returns 0 if it succeeds, or one of the following 354 * negative error codes: 355 * 356 * NGHTTP2_ERR_NOMEM 357 * Out of memory 358 */ 359 int nghttp2_stream_attach_item(nghttp2_stream *stream, 360 nghttp2_outbound_item *item); 361 362 /* 363 * Detaches |stream->item|. This function does not free 364 * |stream->item|. The caller must free it. 365 * 366 * This function returns 0 if it succeeds, or one of the following 367 * negative error codes: 368 * 369 * NGHTTP2_ERR_NOMEM 370 * Out of memory 371 */ 372 int nghttp2_stream_detach_item(nghttp2_stream *stream); 373 374 /* 375 * Makes the |stream| depend on the |dep_stream|. This dependency is 376 * exclusive. 377 * 378 * This function returns 0 if it succeeds, or one of the following 379 * negative error codes: 380 * 381 * NGHTTP2_ERR_NOMEM 382 * Out of memory 383 */ 384 int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream, 385 nghttp2_stream *stream); 386 387 /* 388 * Makes the |stream| depend on the |dep_stream|. This dependency is 389 * not exclusive. 390 * 391 * This function returns 0 if it succeeds, or one of the following 392 * negative error codes: 393 * 394 * NGHTTP2_ERR_NOMEM 395 * Out of memory 396 */ 397 int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream, 398 nghttp2_stream *stream); 399 400 /* 401 * Removes subtree whose root stream is |stream|. The 402 * effective_weight of streams in removed subtree is not updated. 403 * 404 * This function returns 0 if it succeeds, or one of the following 405 * negative error codes: 406 * 407 * NGHTTP2_ERR_NOMEM 408 * Out of memory 409 */ 410 void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream); 411 412 /* 413 * Returns nonzero if |stream| is in any dependency tree. 414 */ 415 int nghttp2_stream_in_dep_tree(nghttp2_stream *stream); 416 417 /* 418 * Schedules transmission of |stream|'s item, assuming stream->item is 419 * attached, and stream->last_writelen was updated. 420 */ 421 void nghttp2_stream_reschedule(nghttp2_stream *stream); 422 423 /* 424 * Changes |stream|'s weight to |weight|. If |stream| is queued, it 425 * will be rescheduled based on new weight. 426 */ 427 void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight); 428 429 /* 430 * Returns a stream which has highest priority, updating 431 * descendant_last_cycle of selected stream's ancestors. 432 */ 433 nghttp2_outbound_item *nghttp2_stream_next_outbound_item( 434 nghttp2_stream *stream); 435 436 #endif /* NGHTTP2_STREAM */ 437