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