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