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