1 /*
2  * nghttp3
3  *
4  * Copyright (c) 2019 nghttp3 contributors
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 NGHTTP3_STREAM_H
26 #define NGHTTP3_STREAM_H
27 
28 #ifdef HAVE_CONFIG_H
29 #  include <config.h>
30 #endif /* HAVE_CONFIG_H */
31 
32 #include <nghttp3/nghttp3.h>
33 
34 #include "nghttp3_map.h"
35 #include "nghttp3_tnode.h"
36 #include "nghttp3_ringbuf.h"
37 #include "nghttp3_buf.h"
38 #include "nghttp3_frame.h"
39 #include "nghttp3_qpack.h"
40 
41 #define NGHTTP3_STREAM_MIN_CHUNK_SIZE 256
42 
43 /* NGHTTP3_MIN_UNSENT_BYTES is the minimum unsent bytes which is large
44    enough to fill outgoing single QUIC packet. */
45 #define NGHTTP3_MIN_UNSENT_BYTES 4096
46 
47 /* NGHTTP3_STREAM_MIN_WRITELEN is the minimum length of write to cause
48    the stream to reschedule. */
49 #define NGHTTP3_STREAM_MIN_WRITELEN 800
50 
51 /* nghttp3_stream_type is unidirectional stream type. */
52 typedef enum nghttp3_stream_type {
53   NGHTTP3_STREAM_TYPE_CONTROL = 0x00,
54   NGHTTP3_STREAM_TYPE_PUSH = 0x01,
55   NGHTTP3_STREAM_TYPE_QPACK_ENCODER = 0x02,
56   NGHTTP3_STREAM_TYPE_QPACK_DECODER = 0x03,
57   NGHTTP3_STREAM_TYPE_UNKNOWN = UINT64_MAX,
58 } nghttp3_stream_type;
59 
60 typedef enum nghttp3_ctrl_stream_state {
61   NGHTTP3_CTRL_STREAM_STATE_FRAME_TYPE,
62   NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH,
63   NGHTTP3_CTRL_STREAM_STATE_SETTINGS,
64   NGHTTP3_CTRL_STREAM_STATE_GOAWAY,
65   NGHTTP3_CTRL_STREAM_STATE_MAX_PUSH_ID,
66   NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME,
67   NGHTTP3_CTRL_STREAM_STATE_SETTINGS_ID,
68   NGHTTP3_CTRL_STREAM_STATE_SETTINGS_VALUE,
69   NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE_PRI_ELEM_ID,
70   NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE,
71 } nghttp3_ctrl_stream_state;
72 
73 typedef enum nghttp3_req_stream_state {
74   NGHTTP3_REQ_STREAM_STATE_FRAME_TYPE,
75   NGHTTP3_REQ_STREAM_STATE_FRAME_LENGTH,
76   NGHTTP3_REQ_STREAM_STATE_DATA,
77   NGHTTP3_REQ_STREAM_STATE_HEADERS,
78   NGHTTP3_REQ_STREAM_STATE_IGN_FRAME,
79   NGHTTP3_REQ_STREAM_STATE_IGN_REST,
80 } nghttp3_req_stream_state;
81 
82 typedef struct nghttp3_varint_read_state {
83   int64_t acc;
84   size_t left;
85 } nghttp3_varint_read_state;
86 
87 typedef struct nghttp3_stream_read_state {
88   nghttp3_varint_read_state rvint;
89   nghttp3_frame fr;
90   int state;
91   int64_t left;
92 } nghttp3_stream_read_state;
93 
94 /* NGHTTP3_STREAM_FLAG_NONE indicates that no flag is set. */
95 #define NGHTTP3_STREAM_FLAG_NONE 0x0000
96 /* NGHTTP3_STREAM_FLAG_TYPE_IDENTIFIED is set when a unidirectional
97    stream type is identified. */
98 #define NGHTTP3_STREAM_FLAG_TYPE_IDENTIFIED 0x0001
99 /* NGHTTP3_STREAM_FLAG_FC_BLOCKED indicates that stream is blocked by
100    QUIC flow control. */
101 #define NGHTTP3_STREAM_FLAG_FC_BLOCKED 0x0002
102 /* NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED indicates that application is
103    temporarily unable to provide data. */
104 #define NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED 0x0004
105 /* NGHTTP3_STREAM_FLAG_WRITE_END_STREAM indicates that application
106    finished to feed outgoing data. */
107 #define NGHTTP3_STREAM_FLAG_WRITE_END_STREAM 0x0008
108 /* NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED indicates that stream is
109    blocked due to QPACK decoding. */
110 #define NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED 0x0010
111 /* NGHTTP3_STREAM_FLAG_READ_EOF indicates that remote endpoint sent
112    fin. */
113 #define NGHTTP3_STREAM_FLAG_READ_EOF 0x0020
114 /* NGHTTP3_STREAM_FLAG_CLOSED indicates that QUIC stream was closed.
115    nghttp3_stream object can still alive because it might be blocked
116    by QPACK decoder. */
117 #define NGHTTP3_STREAM_FLAG_CLOSED 0x0040
118 /* NGHTTP3_STREAM_FLAG_SHUT_WR indicates that any further write
119    operation to a stream is prohibited. */
120 #define NGHTTP3_STREAM_FLAG_SHUT_WR 0x0100
121 /* NGHTTP3_STREAM_FLAG_SHUT_RD indicates that a read-side stream is
122    closed abruptly and any incoming and pending stream data is just
123    discarded for a stream. */
124 #define NGHTTP3_STREAM_FLAG_SHUT_RD 0x0200
125 /* NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET indicates that server
126    overrides stream priority. */
127 #define NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET 0x0400
128 
129 typedef enum nghttp3_stream_http_state {
130   NGHTTP3_HTTP_STATE_NONE,
131   NGHTTP3_HTTP_STATE_REQ_INITIAL,
132   NGHTTP3_HTTP_STATE_REQ_BEGIN,
133   NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN,
134   NGHTTP3_HTTP_STATE_REQ_HEADERS_END,
135   NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN,
136   NGHTTP3_HTTP_STATE_REQ_DATA_END,
137   NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN,
138   NGHTTP3_HTTP_STATE_REQ_TRAILERS_END,
139   NGHTTP3_HTTP_STATE_REQ_END,
140   NGHTTP3_HTTP_STATE_RESP_INITIAL,
141   NGHTTP3_HTTP_STATE_RESP_BEGIN,
142   NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN,
143   NGHTTP3_HTTP_STATE_RESP_HEADERS_END,
144   NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN,
145   NGHTTP3_HTTP_STATE_RESP_DATA_END,
146   NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN,
147   NGHTTP3_HTTP_STATE_RESP_TRAILERS_END,
148   NGHTTP3_HTTP_STATE_RESP_END,
149 } nghttp3_stream_http_state;
150 
151 typedef enum nghttp3_stream_http_event {
152   NGHTTP3_HTTP_EVENT_DATA_BEGIN,
153   NGHTTP3_HTTP_EVENT_DATA_END,
154   NGHTTP3_HTTP_EVENT_HEADERS_BEGIN,
155   NGHTTP3_HTTP_EVENT_HEADERS_END,
156   NGHTTP3_HTTP_EVENT_MSG_END,
157 } nghttp3_stream_http_event;
158 
159 typedef struct nghttp3_stream nghttp3_stream;
160 
161 /*
162  * nghttp3_stream_acked_data is a callback function which is invoked
163  * when data sent on stream denoted by |stream_id| supplied from
164  * application is acknowledged by remote endpoint.  The number of
165  * bytes acknowledged is given in |datalen|.
166  *
167  * The implementation of this callback must return 0 if it succeeds.
168  * Returning NGHTTP3_ERR_CALLBACK_FAILURE will return to the caller
169  * immediately.  Any values other than 0 is treated as
170  * NGHTTP3_ERR_CALLBACK_FAILURE.
171  */
172 typedef int (*nghttp3_stream_acked_data)(nghttp3_stream *stream,
173                                          int64_t stream_id, uint64_t datalen,
174                                          void *user_data);
175 
176 typedef struct nghttp3_stream_callbacks {
177   nghttp3_stream_acked_data acked_data;
178 } nghttp3_stream_callbacks;
179 
180 typedef struct nghttp3_http_state {
181   /* status_code is HTTP status code received.  This field is used
182      if connection is initialized as client. */
183   int32_t status_code;
184   /* content_length is the value of received content-length header
185      field. */
186   int64_t content_length;
187   /* recv_content_length is the number of body bytes received so
188      far. */
189   int64_t recv_content_length;
190   uint16_t flags;
191   /* pri is a stream priority produced by nghttp3_pri_to_uint8. */
192   uint8_t pri;
193 } nghttp3_http_state;
194 
195 struct nghttp3_stream {
196   const nghttp3_mem *mem;
197   nghttp3_tnode node;
198   nghttp3_pq_entry qpack_blocked_pe;
199   nghttp3_stream_callbacks callbacks;
200   nghttp3_ringbuf frq;
201   nghttp3_ringbuf chunks;
202   nghttp3_ringbuf outq;
203   /* inq stores the stream raw data which cannot be read because
204      stream is blocked by QPACK decoder. */
205   nghttp3_ringbuf inq;
206   nghttp3_qpack_stream_context qpack_sctx;
207   /* conn is a reference to underlying connection.  It could be NULL
208      if stream is not a request stream. */
209   nghttp3_conn *conn;
210   void *user_data;
211   /* unsent_bytes is the number of bytes in outq not written yet */
212   uint64_t unsent_bytes;
213   /* outq_idx is an index into outq where next write is made. */
214   size_t outq_idx;
215   /* outq_offset is write offset relative to the element at outq_idx
216      in outq. */
217   uint64_t outq_offset;
218   /* ack_offset is offset acknowledged by peer relative to the first
219      element in outq. */
220   uint64_t ack_offset;
221   /* ack_done is the number of bytes notified to an application that
222      they are acknowledged inside the first outq element if it is of
223      type NGHTTP3_BUF_TYPE_ALIEN. */
224   uint64_t ack_done;
225   uint64_t unscheduled_nwrite;
226   nghttp3_stream_type type;
227   nghttp3_stream_read_state rstate;
228   /* error_code indicates the reason of closure of this stream. */
229   uint64_t error_code;
230 
231   struct {
232     uint64_t offset;
233     nghttp3_stream_http_state hstate;
234   } tx;
235 
236   struct {
237     nghttp3_stream_http_state hstate;
238     nghttp3_http_state http;
239   } rx;
240 
241   uint16_t flags;
242 };
243 
244 typedef struct nghttp3_frame_entry {
245   nghttp3_frame fr;
246   union {
247     struct {
248       nghttp3_settings *local_settings;
249     } settings;
250     struct {
251       nghttp3_data_reader dr;
252     } data;
253   } aux;
254 } nghttp3_frame_entry;
255 
256 int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id,
257                        uint64_t seq, const nghttp3_stream_callbacks *callbacks,
258                        const nghttp3_mem *mem);
259 
260 void nghttp3_stream_del(nghttp3_stream *stream);
261 
262 void nghttp3_varint_read_state_reset(nghttp3_varint_read_state *rvint);
263 
264 void nghttp3_stream_read_state_reset(nghttp3_stream_read_state *rstate);
265 
266 nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint,
267                                   const uint8_t *src, size_t srclen, int fin);
268 
269 int nghttp3_stream_frq_add(nghttp3_stream *stream,
270                            const nghttp3_frame_entry *frent);
271 
272 int nghttp3_stream_fill_outq(nghttp3_stream *stream);
273 
274 int nghttp3_stream_write_stream_type(nghttp3_stream *stream);
275 
276 nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin,
277                                     nghttp3_vec *vec, size_t veccnt);
278 
279 int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream);
280 
281 int nghttp3_stream_outq_is_full(nghttp3_stream *stream);
282 
283 int nghttp3_stream_outq_add(nghttp3_stream *stream,
284                             const nghttp3_typed_buf *tbuf);
285 
286 int nghttp3_stream_write_headers(nghttp3_stream *stream,
287                                  nghttp3_frame_entry *frent);
288 
289 int nghttp3_stream_write_header_block(nghttp3_stream *stream,
290                                       nghttp3_qpack_encoder *qenc,
291                                       nghttp3_stream *qenc_stream,
292                                       nghttp3_buf *rbuf, nghttp3_buf *ebuf,
293                                       int64_t frame_type, const nghttp3_nv *nva,
294                                       size_t nvlen);
295 
296 int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof,
297                               nghttp3_frame_entry *frent);
298 
299 int nghttp3_stream_write_settings(nghttp3_stream *stream,
300                                   nghttp3_frame_entry *frent);
301 
302 int nghttp3_stream_write_goaway(nghttp3_stream *stream,
303                                 nghttp3_frame_entry *frent);
304 
305 int nghttp3_stream_write_priority_update(nghttp3_stream *stream,
306                                          nghttp3_frame_entry *frent);
307 
308 int nghttp3_stream_ensure_chunk(nghttp3_stream *stream, size_t need);
309 
310 nghttp3_buf *nghttp3_stream_get_chunk(nghttp3_stream *stream);
311 
312 int nghttp3_stream_is_blocked(nghttp3_stream *stream);
313 
314 int nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n);
315 
316 /*
317  * nghttp3_stream_outq_write_done returns nonzero if all contents in
318  * outq have been written.
319  */
320 int nghttp3_stream_outq_write_done(nghttp3_stream *stream);
321 
322 int nghttp3_stream_add_ack_offset(nghttp3_stream *stream, uint64_t n);
323 
324 /*
325  * nghttp3_stream_is_active returns nonzero if |stream| is active.  In
326  * other words, it has something to send.  This function does not take
327  * into account its descendants.
328  */
329 int nghttp3_stream_is_active(nghttp3_stream *stream);
330 
331 /*
332  * nghttp3_stream_require_schedule returns nonzero if |stream| should
333  * be scheduled.  In other words, |stream| or its descendants have
334  * something to send.
335  */
336 int nghttp3_stream_require_schedule(nghttp3_stream *stream);
337 
338 int nghttp3_stream_buffer_data(nghttp3_stream *stream, const uint8_t *src,
339                                size_t srclen);
340 
341 size_t nghttp3_stream_get_buffered_datalen(nghttp3_stream *stream);
342 
343 int nghttp3_stream_ensure_qpack_stream_context(nghttp3_stream *stream);
344 
345 void nghttp3_stream_delete_qpack_stream_context(nghttp3_stream *stream);
346 
347 int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
348                                          nghttp3_stream_http_event event);
349 
350 int nghttp3_stream_empty_headers_allowed(nghttp3_stream *stream);
351 
352 /*
353  * nghttp3_stream_uni returns nonzero if stream identified by
354  * |stream_id| is unidirectional.
355  */
356 int nghttp3_stream_uni(int64_t stream_id);
357 
358 /*
359  * nghttp3_client_stream_bidi returns nonzero if stream identified by
360  * |stream_id| is client initiated bidirectional stream.
361  */
362 int nghttp3_client_stream_bidi(int64_t stream_id);
363 
364 /*
365  * nghttp3_client_stream_uni returns nonzero if stream identified by
366  * |stream_id| is client initiated unidirectional stream.
367  */
368 int nghttp3_client_stream_uni(int64_t stream_id);
369 
370 /*
371  * nghttp3_server_stream_uni returns nonzero if stream identified by
372  * |stream_id| is server initiated unidirectional stream.
373  */
374 int nghttp3_server_stream_uni(int64_t stream_id);
375 
376 #endif /* NGHTTP3_STREAM_H */
377