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#include "nghttp3_conn.h"
26
27#include <assert.h>
28#include <string.h>
29#include <stdio.h>
30
31#include "nghttp3_mem.h"
32#include "nghttp3_macro.h"
33#include "nghttp3_err.h"
34#include "nghttp3_conv.h"
35#include "nghttp3_http.h"
36
37/* NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY is the upper bound of the
38   dynamic table capacity that QPACK encoder is willing to use. */
39#define NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY 4096
40
41/*
42 * conn_remote_stream_uni returns nonzero if |stream_id| is remote
43 * unidirectional stream ID.
44 */
45static int conn_remote_stream_uni(nghttp3_conn *conn, int64_t stream_id) {
46  if (conn->server) {
47    return (stream_id & 0x03) == 0x02;
48  }
49  return (stream_id & 0x03) == 0x03;
50}
51
52static int conn_call_begin_headers(nghttp3_conn *conn, nghttp3_stream *stream) {
53  int rv;
54
55  if (!conn->callbacks.begin_headers) {
56    return 0;
57  }
58
59  rv = conn->callbacks.begin_headers(conn, stream->node.nid.id, conn->user_data,
60                                     stream->user_data);
61  if (rv != 0) {
62    /* TODO Allow ignore headers */
63    return NGHTTP3_ERR_CALLBACK_FAILURE;
64  }
65
66  return 0;
67}
68
69static int conn_call_end_headers(nghttp3_conn *conn, nghttp3_stream *stream,
70                                 int fin) {
71  int rv;
72
73  if (!conn->callbacks.end_headers) {
74    return 0;
75  }
76
77  rv = conn->callbacks.end_headers(conn, stream->node.nid.id, fin,
78                                   conn->user_data, stream->user_data);
79  if (rv != 0) {
80    /* TODO Allow ignore headers */
81    return NGHTTP3_ERR_CALLBACK_FAILURE;
82  }
83
84  return 0;
85}
86
87static int conn_call_begin_trailers(nghttp3_conn *conn,
88                                    nghttp3_stream *stream) {
89  int rv;
90
91  if (!conn->callbacks.begin_trailers) {
92    return 0;
93  }
94
95  rv = conn->callbacks.begin_trailers(conn, stream->node.nid.id,
96                                      conn->user_data, stream->user_data);
97  if (rv != 0) {
98    /* TODO Allow ignore headers */
99    return NGHTTP3_ERR_CALLBACK_FAILURE;
100  }
101
102  return 0;
103}
104
105static int conn_call_end_trailers(nghttp3_conn *conn, nghttp3_stream *stream,
106                                  int fin) {
107  int rv;
108
109  if (!conn->callbacks.end_trailers) {
110    return 0;
111  }
112
113  rv = conn->callbacks.end_trailers(conn, stream->node.nid.id, fin,
114                                    conn->user_data, stream->user_data);
115  if (rv != 0) {
116    /* TODO Allow ignore headers */
117    return NGHTTP3_ERR_CALLBACK_FAILURE;
118  }
119
120  return 0;
121}
122
123static int conn_call_end_stream(nghttp3_conn *conn, nghttp3_stream *stream) {
124  int rv;
125
126  if (!conn->callbacks.end_stream) {
127    return 0;
128  }
129
130  rv = conn->callbacks.end_stream(conn, stream->node.nid.id, conn->user_data,
131                                  stream->user_data);
132  if (rv != 0) {
133    return NGHTTP3_ERR_CALLBACK_FAILURE;
134  }
135
136  return 0;
137}
138
139static int conn_call_stop_sending(nghttp3_conn *conn, nghttp3_stream *stream,
140                                  uint64_t app_error_code) {
141  int rv;
142
143  if (!conn->callbacks.stop_sending) {
144    return 0;
145  }
146
147  rv = conn->callbacks.stop_sending(conn, stream->node.nid.id, app_error_code,
148                                    conn->user_data, stream->user_data);
149  if (rv != 0) {
150    return NGHTTP3_ERR_CALLBACK_FAILURE;
151  }
152
153  return 0;
154}
155
156static int conn_call_reset_stream(nghttp3_conn *conn, nghttp3_stream *stream,
157                                  uint64_t app_error_code) {
158  int rv;
159
160  if (!conn->callbacks.reset_stream) {
161    return 0;
162  }
163
164  rv = conn->callbacks.reset_stream(conn, stream->node.nid.id, app_error_code,
165                                    conn->user_data, stream->user_data);
166  if (rv != 0) {
167    return NGHTTP3_ERR_CALLBACK_FAILURE;
168  }
169
170  return 0;
171}
172
173static int conn_call_deferred_consume(nghttp3_conn *conn,
174                                      nghttp3_stream *stream,
175                                      size_t nconsumed) {
176  int rv;
177
178  if (nconsumed == 0 || !conn->callbacks.deferred_consume) {
179    return 0;
180  }
181
182  rv = conn->callbacks.deferred_consume(conn, stream->node.nid.id, nconsumed,
183                                        conn->user_data, stream->user_data);
184  if (rv != 0) {
185    return NGHTTP3_ERR_CALLBACK_FAILURE;
186  }
187
188  return 0;
189}
190
191static int ricnt_less(const nghttp3_pq_entry *lhsx,
192                      const nghttp3_pq_entry *rhsx) {
193  nghttp3_stream *lhs =
194      nghttp3_struct_of(lhsx, nghttp3_stream, qpack_blocked_pe);
195  nghttp3_stream *rhs =
196      nghttp3_struct_of(rhsx, nghttp3_stream, qpack_blocked_pe);
197
198  return lhs->qpack_sctx.ricnt < rhs->qpack_sctx.ricnt;
199}
200
201static int cycle_less(const nghttp3_pq_entry *lhsx,
202                      const nghttp3_pq_entry *rhsx) {
203  const nghttp3_tnode *lhs = nghttp3_struct_of(lhsx, nghttp3_tnode, pe);
204  const nghttp3_tnode *rhs = nghttp3_struct_of(rhsx, nghttp3_tnode, pe);
205
206  if (lhs->cycle == rhs->cycle) {
207    return lhs->seq < rhs->seq;
208  }
209
210  return rhs->cycle - lhs->cycle <= NGHTTP3_TNODE_MAX_CYCLE_GAP;
211}
212
213static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version,
214                    const nghttp3_callbacks *callbacks, int settings_version,
215                    const nghttp3_settings *settings, const nghttp3_mem *mem,
216                    void *user_data) {
217  int rv;
218  nghttp3_conn *conn;
219  size_t i;
220  (void)callbacks_version;
221  (void)settings_version;
222
223  if (mem == NULL) {
224    mem = nghttp3_mem_default();
225  }
226
227  conn = nghttp3_mem_calloc(mem, 1, sizeof(nghttp3_conn));
228  if (conn == NULL) {
229    return NGHTTP3_ERR_NOMEM;
230  }
231
232  nghttp3_objalloc_init(&conn->out_chunk_objalloc,
233                        NGHTTP3_STREAM_MIN_CHUNK_SIZE * 16, mem);
234  nghttp3_objalloc_stream_init(&conn->stream_objalloc, 64, mem);
235
236  nghttp3_map_init(&conn->streams, mem);
237
238  rv = nghttp3_qpack_decoder_init(&conn->qdec,
239                                  settings->qpack_max_dtable_capacity,
240                                  settings->qpack_blocked_streams, mem);
241  if (rv != 0) {
242    goto qdec_init_fail;
243  }
244
245  rv = nghttp3_qpack_encoder_init(
246      &conn->qenc, settings->qpack_encoder_max_dtable_capacity, mem);
247  if (rv != 0) {
248    goto qenc_init_fail;
249  }
250
251  nghttp3_pq_init(&conn->qpack_blocked_streams, ricnt_less, mem);
252
253  for (i = 0; i < NGHTTP3_URGENCY_LEVELS; ++i) {
254    nghttp3_pq_init(&conn->sched[i].spq, cycle_less, mem);
255  }
256
257  nghttp3_idtr_init(&conn->remote.bidi.idtr, server, mem);
258
259  conn->callbacks = *callbacks;
260  conn->local.settings = *settings;
261  if (!server) {
262    conn->local.settings.enable_connect_protocol = 0;
263  }
264  nghttp3_settings_default(&conn->remote.settings);
265  conn->mem = mem;
266  conn->user_data = user_data;
267  conn->next_seq = 0;
268  conn->server = server;
269  conn->rx.goaway_id = NGHTTP3_VARINT_MAX + 1;
270  conn->tx.goaway_id = NGHTTP3_VARINT_MAX + 1;
271  conn->rx.max_stream_id_bidi = -4;
272
273  *pconn = conn;
274
275  return 0;
276
277qenc_init_fail:
278  nghttp3_qpack_decoder_free(&conn->qdec);
279qdec_init_fail:
280  nghttp3_map_free(&conn->streams);
281  nghttp3_objalloc_free(&conn->stream_objalloc);
282  nghttp3_objalloc_free(&conn->out_chunk_objalloc);
283  nghttp3_mem_free(mem, conn);
284
285  return rv;
286}
287
288int nghttp3_conn_client_new_versioned(nghttp3_conn **pconn,
289                                      int callbacks_version,
290                                      const nghttp3_callbacks *callbacks,
291                                      int settings_version,
292                                      const nghttp3_settings *settings,
293                                      const nghttp3_mem *mem, void *user_data) {
294  int rv;
295
296  rv = conn_new(pconn, /* server = */ 0, callbacks_version, callbacks,
297                settings_version, settings, mem, user_data);
298  if (rv != 0) {
299    return rv;
300  }
301
302  return 0;
303}
304
305int nghttp3_conn_server_new_versioned(nghttp3_conn **pconn,
306                                      int callbacks_version,
307                                      const nghttp3_callbacks *callbacks,
308                                      int settings_version,
309                                      const nghttp3_settings *settings,
310                                      const nghttp3_mem *mem, void *user_data) {
311  int rv;
312
313  rv = conn_new(pconn, /* server = */ 1, callbacks_version, callbacks,
314                settings_version, settings, mem, user_data);
315  if (rv != 0) {
316    return rv;
317  }
318
319  return 0;
320}
321
322static int free_stream(void *data, void *ptr) {
323  nghttp3_stream *stream = data;
324
325  (void)ptr;
326
327  nghttp3_stream_del(stream);
328
329  return 0;
330}
331
332void nghttp3_conn_del(nghttp3_conn *conn) {
333  size_t i;
334
335  if (conn == NULL) {
336    return;
337  }
338
339  nghttp3_buf_free(&conn->tx.qpack.ebuf, conn->mem);
340  nghttp3_buf_free(&conn->tx.qpack.rbuf, conn->mem);
341
342  nghttp3_idtr_free(&conn->remote.bidi.idtr);
343
344  for (i = 0; i < NGHTTP3_URGENCY_LEVELS; ++i) {
345    nghttp3_pq_free(&conn->sched[i].spq);
346  }
347
348  nghttp3_pq_free(&conn->qpack_blocked_streams);
349
350  nghttp3_qpack_encoder_free(&conn->qenc);
351  nghttp3_qpack_decoder_free(&conn->qdec);
352
353  nghttp3_map_each_free(&conn->streams, free_stream, NULL);
354  nghttp3_map_free(&conn->streams);
355
356  nghttp3_objalloc_free(&conn->stream_objalloc);
357  nghttp3_objalloc_free(&conn->out_chunk_objalloc);
358
359  nghttp3_mem_free(conn->mem, conn);
360}
361
362static int conn_bidi_idtr_open(nghttp3_conn *conn, int64_t stream_id) {
363  int rv;
364
365  rv = nghttp3_idtr_open(&conn->remote.bidi.idtr, stream_id);
366  if (rv != 0) {
367    return rv;
368  }
369
370  if (nghttp3_ksl_len(&conn->remote.bidi.idtr.gap.gap) > 32) {
371    nghttp3_gaptr_drop_first_gap(&conn->remote.bidi.idtr.gap);
372  }
373
374  return 0;
375}
376
377nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id,
378                                       const uint8_t *src, size_t srclen,
379                                       int fin) {
380  nghttp3_stream *stream;
381  size_t bidi_nproc;
382  int rv;
383
384  stream = nghttp3_conn_find_stream(conn, stream_id);
385  if (stream == NULL) {
386    /* TODO Assert idtr */
387    /* QUIC transport ensures that this is new stream. */
388    if (conn->server) {
389      if (nghttp3_client_stream_bidi(stream_id)) {
390        rv = conn_bidi_idtr_open(conn, stream_id);
391        if (rv != 0) {
392          if (nghttp3_err_is_fatal(rv)) {
393            return rv;
394          }
395
396          /* Ignore return value.  We might drop the first gap if there
397             are many gaps if QUIC stack allows too many holes in stream
398             ID space.  idtr is used to decide whether PRIORITY_UPDATE
399             frame should be ignored or not and the frame is optional.
400             Ignoring them causes no harm. */
401        }
402
403        conn->rx.max_stream_id_bidi =
404            nghttp3_max(conn->rx.max_stream_id_bidi, stream_id);
405        rv = nghttp3_conn_create_stream(conn, &stream, stream_id);
406        if (rv != 0) {
407          return rv;
408        }
409
410        if ((conn->flags & NGHTTP3_CONN_FLAG_GOAWAY_QUEUED) &&
411            conn->tx.goaway_id <= stream_id) {
412          stream->rstate.state = NGHTTP3_REQ_STREAM_STATE_IGN_REST;
413
414          rv = nghttp3_conn_reject_stream(conn, stream);
415          if (rv != 0) {
416            return rv;
417          }
418        }
419      } else {
420        /* unidirectional stream */
421        if (srclen == 0 && fin) {
422          return 0;
423        }
424
425        rv = nghttp3_conn_create_stream(conn, &stream, stream_id);
426        if (rv != 0) {
427          return rv;
428        }
429      }
430
431      stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL;
432      stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL;
433    } else if (nghttp3_stream_uni(stream_id)) {
434      if (srclen == 0 && fin) {
435        return 0;
436      }
437
438      rv = nghttp3_conn_create_stream(conn, &stream, stream_id);
439      if (rv != 0) {
440        return rv;
441      }
442
443      stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL;
444      stream->tx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL;
445    } else {
446      /* client doesn't expect to receive new bidirectional stream
447         from server. */
448      return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR;
449    }
450  } else if (conn->server) {
451    if (nghttp3_client_stream_bidi(stream_id)) {
452      if (stream->rx.hstate == NGHTTP3_HTTP_STATE_NONE) {
453        stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL;
454        stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL;
455      }
456    }
457  } else if (nghttp3_stream_uni(stream_id) &&
458             stream->type == NGHTTP3_STREAM_TYPE_PUSH) {
459    if (stream->rx.hstate == NGHTTP3_HTTP_STATE_NONE) {
460      stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL;
461      stream->tx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL;
462    }
463  }
464
465  if (srclen == 0 && !fin) {
466    return 0;
467  }
468
469  if (nghttp3_stream_uni(stream_id)) {
470    return nghttp3_conn_read_uni(conn, stream, src, srclen, fin);
471  }
472
473  if (fin) {
474    stream->flags |= NGHTTP3_STREAM_FLAG_READ_EOF;
475  }
476  return nghttp3_conn_read_bidi(conn, &bidi_nproc, stream, src, srclen, fin);
477}
478
479static nghttp3_ssize conn_read_type(nghttp3_conn *conn, nghttp3_stream *stream,
480                                    const uint8_t *src, size_t srclen,
481                                    int fin) {
482  nghttp3_stream_read_state *rstate = &stream->rstate;
483  nghttp3_varint_read_state *rvint = &rstate->rvint;
484  nghttp3_ssize nread;
485  int64_t stream_type;
486
487  assert(srclen);
488
489  nread = nghttp3_read_varint(rvint, src, srclen, fin);
490  if (nread < 0) {
491    return NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR;
492  }
493
494  if (rvint->left) {
495    return nread;
496  }
497
498  stream_type = rvint->acc;
499  nghttp3_varint_read_state_reset(rvint);
500
501  switch (stream_type) {
502  case NGHTTP3_STREAM_TYPE_CONTROL:
503    if (conn->flags & NGHTTP3_CONN_FLAG_CONTROL_OPENED) {
504      return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR;
505    }
506    conn->flags |= NGHTTP3_CONN_FLAG_CONTROL_OPENED;
507    stream->type = NGHTTP3_STREAM_TYPE_CONTROL;
508    rstate->state = NGHTTP3_CTRL_STREAM_STATE_FRAME_TYPE;
509    break;
510  case NGHTTP3_STREAM_TYPE_PUSH:
511    return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR;
512  case NGHTTP3_STREAM_TYPE_QPACK_ENCODER:
513    if (conn->flags & NGHTTP3_CONN_FLAG_QPACK_ENCODER_OPENED) {
514      return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR;
515    }
516    conn->flags |= NGHTTP3_CONN_FLAG_QPACK_ENCODER_OPENED;
517    stream->type = NGHTTP3_STREAM_TYPE_QPACK_ENCODER;
518    break;
519  case NGHTTP3_STREAM_TYPE_QPACK_DECODER:
520    if (conn->flags & NGHTTP3_CONN_FLAG_QPACK_DECODER_OPENED) {
521      return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR;
522    }
523    conn->flags |= NGHTTP3_CONN_FLAG_QPACK_DECODER_OPENED;
524    stream->type = NGHTTP3_STREAM_TYPE_QPACK_DECODER;
525    break;
526  default:
527    stream->type = NGHTTP3_STREAM_TYPE_UNKNOWN;
528    break;
529  }
530
531  stream->flags |= NGHTTP3_STREAM_FLAG_TYPE_IDENTIFIED;
532
533  return nread;
534}
535
536static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream);
537
538nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
539                                    const uint8_t *src, size_t srclen,
540                                    int fin) {
541  nghttp3_ssize nread = 0;
542  nghttp3_ssize nconsumed = 0;
543  int rv;
544
545  assert(srclen || fin);
546
547  if (!(stream->flags & NGHTTP3_STREAM_FLAG_TYPE_IDENTIFIED)) {
548    if (srclen == 0 && fin) {
549      /* Ignore stream if it is closed before reading stream header.
550         If it is closed while reading it, return error, making it
551         consistent in our code base. */
552      if (stream->rstate.rvint.left) {
553        return NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR;
554      }
555
556      rv = conn_delete_stream(conn, stream);
557      assert(0 == rv);
558
559      return 0;
560    }
561    nread = conn_read_type(conn, stream, src, srclen, fin);
562    if (nread < 0) {
563      return (int)nread;
564    }
565    if (!(stream->flags & NGHTTP3_STREAM_FLAG_TYPE_IDENTIFIED)) {
566      assert((size_t)nread == srclen);
567      return (nghttp3_ssize)srclen;
568    }
569
570    src += nread;
571    srclen -= (size_t)nread;
572
573    if (srclen == 0) {
574      return nread;
575    }
576  }
577
578  switch (stream->type) {
579  case NGHTTP3_STREAM_TYPE_CONTROL:
580    if (fin) {
581      return NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM;
582    }
583    nconsumed = nghttp3_conn_read_control(conn, stream, src, srclen);
584    break;
585  case NGHTTP3_STREAM_TYPE_QPACK_ENCODER:
586    if (fin) {
587      return NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM;
588    }
589    nconsumed = nghttp3_conn_read_qpack_encoder(conn, src, srclen);
590    break;
591  case NGHTTP3_STREAM_TYPE_QPACK_DECODER:
592    if (fin) {
593      return NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM;
594    }
595    nconsumed = nghttp3_conn_read_qpack_decoder(conn, src, srclen);
596    break;
597  case NGHTTP3_STREAM_TYPE_UNKNOWN:
598    nconsumed = (nghttp3_ssize)srclen;
599
600    rv = conn_call_stop_sending(conn, stream, NGHTTP3_H3_STREAM_CREATION_ERROR);
601    if (rv != 0) {
602      return rv;
603    }
604    break;
605  default:
606    /* unreachable */
607    assert(0);
608  }
609
610  if (nconsumed < 0) {
611    return nconsumed;
612  }
613
614  return nread + nconsumed;
615}
616
617static int frame_fin(nghttp3_stream_read_state *rstate, size_t len) {
618  return (int64_t)len >= rstate->left;
619}
620
621nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
622                                        nghttp3_stream *stream,
623                                        const uint8_t *src, size_t srclen) {
624  const uint8_t *p = src, *end = src + srclen;
625  int rv;
626  nghttp3_stream_read_state *rstate = &stream->rstate;
627  nghttp3_varint_read_state *rvint = &rstate->rvint;
628  nghttp3_ssize nread;
629  size_t nconsumed = 0;
630  int busy = 0;
631  size_t len;
632  const uint8_t *pri_field_value = NULL;
633  size_t pri_field_valuelen = 0;
634
635  assert(srclen);
636
637  for (; p != end || busy;) {
638    busy = 0;
639    switch (rstate->state) {
640    case NGHTTP3_CTRL_STREAM_STATE_FRAME_TYPE:
641      assert(end - p > 0);
642      nread = nghttp3_read_varint(rvint, p, (size_t)(end - p), /* fin = */ 0);
643      if (nread < 0) {
644        return NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR;
645      }
646
647      p += nread;
648      nconsumed += (size_t)nread;
649      if (rvint->left) {
650        return (nghttp3_ssize)nconsumed;
651      }
652
653      rstate->fr.hd.type = rvint->acc;
654      nghttp3_varint_read_state_reset(rvint);
655      rstate->state = NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH;
656      if (p == end) {
657        break;
658      }
659      /* Fall through */
660    case NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH:
661      assert(end - p > 0);
662      nread = nghttp3_read_varint(rvint, p, (size_t)(end - p), /* fin = */ 0);
663      if (nread < 0) {
664        return NGHTTP3_ERR_H3_FRAME_ERROR;
665      }
666
667      p += nread;
668      nconsumed += (size_t)nread;
669      if (rvint->left) {
670        return (nghttp3_ssize)nconsumed;
671      }
672
673      rstate->left = rstate->fr.hd.length = rvint->acc;
674      nghttp3_varint_read_state_reset(rvint);
675
676      if (!(conn->flags & NGHTTP3_CONN_FLAG_SETTINGS_RECVED)) {
677        if (rstate->fr.hd.type != NGHTTP3_FRAME_SETTINGS) {
678          return NGHTTP3_ERR_H3_MISSING_SETTINGS;
679        }
680        conn->flags |= NGHTTP3_CONN_FLAG_SETTINGS_RECVED;
681      } else if (rstate->fr.hd.type == NGHTTP3_FRAME_SETTINGS) {
682        return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
683      }
684
685      switch (rstate->fr.hd.type) {
686      case NGHTTP3_FRAME_SETTINGS:
687        /* SETTINGS frame might be empty. */
688        if (rstate->left == 0) {
689          nghttp3_stream_read_state_reset(rstate);
690          break;
691        }
692        rstate->state = NGHTTP3_CTRL_STREAM_STATE_SETTINGS;
693        break;
694      case NGHTTP3_FRAME_GOAWAY:
695        if (rstate->left == 0) {
696          return NGHTTP3_ERR_H3_FRAME_ERROR;
697        }
698        rstate->state = NGHTTP3_CTRL_STREAM_STATE_GOAWAY;
699        break;
700      case NGHTTP3_FRAME_MAX_PUSH_ID:
701        if (!conn->server) {
702          return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
703        }
704        if (rstate->left == 0) {
705          return NGHTTP3_ERR_H3_FRAME_ERROR;
706        }
707        rstate->state = NGHTTP3_CTRL_STREAM_STATE_MAX_PUSH_ID;
708        break;
709      case NGHTTP3_FRAME_PRIORITY_UPDATE:
710        if (!conn->server) {
711          return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
712        }
713        if (rstate->left == 0) {
714          return NGHTTP3_ERR_H3_FRAME_ERROR;
715        }
716        rstate->state = NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE_PRI_ELEM_ID;
717        break;
718      case NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID:
719        /* We do not support push */
720        return NGHTTP3_ERR_H3_ID_ERROR;
721      case NGHTTP3_FRAME_CANCEL_PUSH: /* We do not support push */
722      case NGHTTP3_FRAME_DATA:
723      case NGHTTP3_FRAME_HEADERS:
724      case NGHTTP3_FRAME_PUSH_PROMISE:
725      case NGHTTP3_H2_FRAME_PRIORITY:
726      case NGHTTP3_H2_FRAME_PING:
727      case NGHTTP3_H2_FRAME_WINDOW_UPDATE:
728      case NGHTTP3_H2_FRAME_CONTINUATION:
729        return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
730      default:
731        /* TODO Handle reserved frame type */
732        busy = 1;
733        rstate->state = NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME;
734        break;
735      }
736      break;
737    case NGHTTP3_CTRL_STREAM_STATE_SETTINGS:
738      for (; p != end;) {
739        if (rstate->left == 0) {
740          nghttp3_stream_read_state_reset(rstate);
741          break;
742        }
743        /* Read Identifier */
744        len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
745        assert(len > 0);
746        nread = nghttp3_read_varint(rvint, p, len, frame_fin(rstate, len));
747        if (nread < 0) {
748          return NGHTTP3_ERR_H3_FRAME_ERROR;
749        }
750
751        p += nread;
752        nconsumed += (size_t)nread;
753        rstate->left -= nread;
754        if (rvint->left) {
755          rstate->state = NGHTTP3_CTRL_STREAM_STATE_SETTINGS_ID;
756          return (nghttp3_ssize)nconsumed;
757        }
758        rstate->fr.settings.iv[0].id = (uint64_t)rvint->acc;
759        nghttp3_varint_read_state_reset(rvint);
760
761        /* Read Value */
762        if (rstate->left == 0) {
763          return NGHTTP3_ERR_H3_FRAME_ERROR;
764        }
765
766        len -= (size_t)nread;
767        if (len == 0) {
768          rstate->state = NGHTTP3_CTRL_STREAM_STATE_SETTINGS_VALUE;
769          break;
770        }
771
772        nread = nghttp3_read_varint(rvint, p, len, frame_fin(rstate, len));
773        if (nread < 0) {
774          return NGHTTP3_ERR_H3_FRAME_ERROR;
775        }
776
777        p += nread;
778        nconsumed += (size_t)nread;
779        rstate->left -= nread;
780        if (rvint->left) {
781          rstate->state = NGHTTP3_CTRL_STREAM_STATE_SETTINGS_VALUE;
782          return (nghttp3_ssize)nconsumed;
783        }
784        rstate->fr.settings.iv[0].value = (uint64_t)rvint->acc;
785        nghttp3_varint_read_state_reset(rvint);
786
787        rv =
788            nghttp3_conn_on_settings_entry_received(conn, &rstate->fr.settings);
789        if (rv != 0) {
790          return rv;
791        }
792      }
793      break;
794    case NGHTTP3_CTRL_STREAM_STATE_SETTINGS_ID:
795      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
796      assert(len > 0);
797      nread = nghttp3_read_varint(rvint, p, len, frame_fin(rstate, len));
798      if (nread < 0) {
799        return NGHTTP3_ERR_H3_FRAME_ERROR;
800      }
801
802      p += nread;
803      nconsumed += (size_t)nread;
804      rstate->left -= nread;
805      if (rvint->left) {
806        return (nghttp3_ssize)nconsumed;
807      }
808      rstate->fr.settings.iv[0].id = (uint64_t)rvint->acc;
809      nghttp3_varint_read_state_reset(rvint);
810
811      if (rstate->left == 0) {
812        return NGHTTP3_ERR_H3_FRAME_ERROR;
813      }
814
815      rstate->state = NGHTTP3_CTRL_STREAM_STATE_SETTINGS_VALUE;
816
817      if (p == end) {
818        return (nghttp3_ssize)nconsumed;
819      }
820      /* Fall through */
821    case NGHTTP3_CTRL_STREAM_STATE_SETTINGS_VALUE:
822      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
823      assert(len > 0);
824      nread = nghttp3_read_varint(rvint, p, len, frame_fin(rstate, len));
825      if (nread < 0) {
826        return NGHTTP3_ERR_H3_FRAME_ERROR;
827      }
828
829      p += nread;
830      nconsumed += (size_t)nread;
831      rstate->left -= nread;
832      if (rvint->left) {
833        return (nghttp3_ssize)nconsumed;
834      }
835      rstate->fr.settings.iv[0].value = (uint64_t)rvint->acc;
836      nghttp3_varint_read_state_reset(rvint);
837
838      rv = nghttp3_conn_on_settings_entry_received(conn, &rstate->fr.settings);
839      if (rv != 0) {
840        return rv;
841      }
842
843      if (rstate->left) {
844        rstate->state = NGHTTP3_CTRL_STREAM_STATE_SETTINGS;
845        break;
846      }
847
848      nghttp3_stream_read_state_reset(rstate);
849      break;
850    case NGHTTP3_CTRL_STREAM_STATE_GOAWAY:
851      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
852      assert(len > 0);
853      nread = nghttp3_read_varint(rvint, p, len, frame_fin(rstate, len));
854      if (nread < 0) {
855        return NGHTTP3_ERR_H3_FRAME_ERROR;
856      }
857
858      p += nread;
859      nconsumed += (size_t)nread;
860      rstate->left -= nread;
861      if (rvint->left) {
862        return (nghttp3_ssize)nconsumed;
863      }
864
865      if (!conn->server && !nghttp3_client_stream_bidi(rvint->acc)) {
866        return NGHTTP3_ERR_H3_ID_ERROR;
867      }
868      if (conn->rx.goaway_id < rvint->acc) {
869        return NGHTTP3_ERR_H3_ID_ERROR;
870      }
871
872      conn->flags |= NGHTTP3_CONN_FLAG_GOAWAY_RECVED;
873      conn->rx.goaway_id = rvint->acc;
874      nghttp3_varint_read_state_reset(rvint);
875
876      if (conn->callbacks.shutdown) {
877        rv =
878            conn->callbacks.shutdown(conn, conn->rx.goaway_id, conn->user_data);
879        if (rv != 0) {
880          return NGHTTP3_ERR_CALLBACK_FAILURE;
881        }
882      }
883
884      nghttp3_stream_read_state_reset(rstate);
885      break;
886    case NGHTTP3_CTRL_STREAM_STATE_MAX_PUSH_ID:
887      /* server side only */
888      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
889      assert(len > 0);
890      nread = nghttp3_read_varint(rvint, p, len, frame_fin(rstate, len));
891      if (nread < 0) {
892        return NGHTTP3_ERR_H3_FRAME_ERROR;
893      }
894
895      p += nread;
896      nconsumed += (size_t)nread;
897      rstate->left -= nread;
898      if (rvint->left) {
899        return (nghttp3_ssize)nconsumed;
900      }
901
902      if (conn->local.uni.max_pushes > (uint64_t)rvint->acc + 1) {
903        return NGHTTP3_ERR_H3_FRAME_ERROR;
904      }
905
906      conn->local.uni.max_pushes = (uint64_t)rvint->acc + 1;
907      nghttp3_varint_read_state_reset(rvint);
908
909      nghttp3_stream_read_state_reset(rstate);
910      break;
911    case NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE_PRI_ELEM_ID:
912      /* server side only */
913      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
914      assert(len > 0);
915      nread = nghttp3_read_varint(rvint, p, len, frame_fin(rstate, len));
916      if (nread < 0) {
917        return NGHTTP3_ERR_H3_FRAME_ERROR;
918      }
919
920      p += nread;
921      nconsumed += (size_t)nread;
922      rstate->left -= nread;
923      if (rvint->left) {
924        return (nghttp3_ssize)nconsumed;
925      }
926
927      rstate->fr.priority_update.pri_elem_id = rvint->acc;
928      nghttp3_varint_read_state_reset(rvint);
929
930      if (rstate->left == 0) {
931        rstate->fr.priority_update.pri.urgency = NGHTTP3_DEFAULT_URGENCY;
932        rstate->fr.priority_update.pri.inc = 0;
933
934        rv = nghttp3_conn_on_priority_update(conn, &rstate->fr.priority_update);
935        if (rv != 0) {
936          return rv;
937        }
938
939        nghttp3_stream_read_state_reset(rstate);
940        break;
941      }
942
943      rstate->state = NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE;
944
945      /* Fall through */
946    case NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE:
947      /* We need to buffer Priority Field Value because it might be
948         fragmented. */
949      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
950      assert(len > 0);
951      if (conn->rx.pri_fieldbuflen == 0 && rstate->left == (int64_t)len) {
952        /* Everything is in the input buffer.  Apply same length
953           limit we impose when buffering the field. */
954        if (len > sizeof(conn->rx.pri_fieldbuf)) {
955          busy = 1;
956          rstate->state = NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME;
957          break;
958        }
959
960        pri_field_value = p;
961        pri_field_valuelen = len;
962      } else if (len + conn->rx.pri_fieldbuflen >
963                 sizeof(conn->rx.pri_fieldbuf)) {
964        busy = 1;
965        rstate->state = NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME;
966        break;
967      } else {
968        memcpy(conn->rx.pri_fieldbuf + conn->rx.pri_fieldbuflen, p, len);
969        conn->rx.pri_fieldbuflen += len;
970
971        if (rstate->left == (int64_t)len) {
972          pri_field_value = conn->rx.pri_fieldbuf;
973          pri_field_valuelen = conn->rx.pri_fieldbuflen;
974        }
975      }
976
977      p += len;
978      nconsumed += len;
979      rstate->left -= (int64_t)len;
980
981      if (rstate->left) {
982        return (nghttp3_ssize)nconsumed;
983      }
984
985      rstate->fr.priority_update.pri.urgency = NGHTTP3_DEFAULT_URGENCY;
986      rstate->fr.priority_update.pri.inc = 0;
987
988      if (nghttp3_http_parse_priority(&rstate->fr.priority_update.pri,
989                                      pri_field_value,
990                                      pri_field_valuelen) != 0) {
991        return NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR;
992      }
993
994      rv = nghttp3_conn_on_priority_update(conn, &rstate->fr.priority_update);
995      if (rv != 0) {
996        return rv;
997      }
998
999      conn->rx.pri_fieldbuflen = 0;
1000
1001      nghttp3_stream_read_state_reset(rstate);
1002      break;
1003    case NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME:
1004      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
1005      p += len;
1006      nconsumed += len;
1007      rstate->left -= (int64_t)len;
1008
1009      if (rstate->left) {
1010        return (nghttp3_ssize)nconsumed;
1011      }
1012
1013      nghttp3_stream_read_state_reset(rstate);
1014      break;
1015    default:
1016      /* unreachable */
1017      assert(0);
1018    }
1019  }
1020
1021  return (nghttp3_ssize)nconsumed;
1022}
1023
1024static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream) {
1025  int bidi = nghttp3_client_stream_bidi(stream->node.nid.id);
1026  int rv;
1027
1028  rv = conn_call_deferred_consume(conn, stream,
1029                                  nghttp3_stream_get_buffered_datalen(stream));
1030  if (rv != 0) {
1031    return rv;
1032  }
1033
1034  if (bidi && conn->callbacks.stream_close) {
1035    rv = conn->callbacks.stream_close(conn, stream->node.nid.id,
1036                                      stream->error_code, conn->user_data,
1037                                      stream->user_data);
1038    if (rv != 0) {
1039      return NGHTTP3_ERR_CALLBACK_FAILURE;
1040    }
1041  }
1042
1043  rv = nghttp3_map_remove(&conn->streams,
1044                          (nghttp3_map_key_type)stream->node.nid.id);
1045
1046  assert(0 == rv);
1047
1048  nghttp3_stream_del(stream);
1049
1050  return 0;
1051}
1052
1053static int conn_process_blocked_stream_data(nghttp3_conn *conn,
1054                                            nghttp3_stream *stream) {
1055  nghttp3_buf *buf;
1056  size_t nproc;
1057  nghttp3_ssize nconsumed;
1058  int rv;
1059  size_t len;
1060
1061  assert(nghttp3_client_stream_bidi(stream->node.nid.id));
1062
1063  for (;;) {
1064    len = nghttp3_ringbuf_len(&stream->inq);
1065    if (len == 0) {
1066      break;
1067    }
1068
1069    buf = nghttp3_ringbuf_get(&stream->inq, 0);
1070
1071    nconsumed = nghttp3_conn_read_bidi(
1072        conn, &nproc, stream, buf->pos, nghttp3_buf_len(buf),
1073        len == 1 && (stream->flags & NGHTTP3_STREAM_FLAG_READ_EOF));
1074    if (nconsumed < 0) {
1075      return (int)nconsumed;
1076    }
1077
1078    buf->pos += nproc;
1079
1080    rv = conn_call_deferred_consume(conn, stream, (size_t)nconsumed);
1081    if (rv != 0) {
1082      return 0;
1083    }
1084
1085    if (nghttp3_buf_len(buf) == 0) {
1086      nghttp3_buf_free(buf, stream->mem);
1087      nghttp3_ringbuf_pop_front(&stream->inq);
1088    }
1089
1090    if (stream->flags & NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED) {
1091      break;
1092    }
1093  }
1094
1095  if (!(stream->flags & NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED) &&
1096      (stream->flags & NGHTTP3_STREAM_FLAG_CLOSED)) {
1097    assert(stream->qpack_blocked_pe.index == NGHTTP3_PQ_BAD_INDEX);
1098
1099    rv = conn_delete_stream(conn, stream);
1100    if (rv != 0) {
1101      return rv;
1102    }
1103  }
1104
1105  return 0;
1106}
1107
1108nghttp3_ssize nghttp3_conn_read_qpack_encoder(nghttp3_conn *conn,
1109                                              const uint8_t *src,
1110                                              size_t srclen) {
1111  nghttp3_ssize nconsumed =
1112      nghttp3_qpack_decoder_read_encoder(&conn->qdec, src, srclen);
1113  nghttp3_stream *stream;
1114  int rv;
1115
1116  if (nconsumed < 0) {
1117    return nconsumed;
1118  }
1119
1120  for (; !nghttp3_pq_empty(&conn->qpack_blocked_streams);) {
1121    stream = nghttp3_struct_of(nghttp3_pq_top(&conn->qpack_blocked_streams),
1122                               nghttp3_stream, qpack_blocked_pe);
1123    if (nghttp3_qpack_stream_context_get_ricnt(&stream->qpack_sctx) >
1124        nghttp3_qpack_decoder_get_icnt(&conn->qdec)) {
1125      break;
1126    }
1127
1128    nghttp3_conn_qpack_blocked_streams_pop(conn);
1129    stream->qpack_blocked_pe.index = NGHTTP3_PQ_BAD_INDEX;
1130    stream->flags &= (uint16_t)~NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED;
1131
1132    rv = conn_process_blocked_stream_data(conn, stream);
1133    if (rv != 0) {
1134      return rv;
1135    }
1136  }
1137
1138  return nconsumed;
1139}
1140
1141nghttp3_ssize nghttp3_conn_read_qpack_decoder(nghttp3_conn *conn,
1142                                              const uint8_t *src,
1143                                              size_t srclen) {
1144  return nghttp3_qpack_encoder_read_decoder(&conn->qenc, src, srclen);
1145}
1146
1147static nghttp3_tnode *stream_get_sched_node(nghttp3_stream *stream) {
1148  return &stream->node;
1149}
1150
1151static int conn_update_stream_priority(nghttp3_conn *conn,
1152                                       nghttp3_stream *stream, uint8_t pri) {
1153  assert(nghttp3_client_stream_bidi(stream->node.nid.id));
1154
1155  if (stream->node.pri == pri) {
1156    return 0;
1157  }
1158
1159  nghttp3_conn_unschedule_stream(conn, stream);
1160
1161  stream->node.pri = pri;
1162
1163  if (nghttp3_stream_require_schedule(stream)) {
1164    return nghttp3_conn_schedule_stream(conn, stream);
1165  }
1166
1167  return 0;
1168}
1169
1170nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc,
1171                                     nghttp3_stream *stream, const uint8_t *src,
1172                                     size_t srclen, int fin) {
1173  const uint8_t *p = src, *end = src ? src + srclen : src;
1174  int rv;
1175  nghttp3_stream_read_state *rstate = &stream->rstate;
1176  nghttp3_varint_read_state *rvint = &rstate->rvint;
1177  nghttp3_ssize nread;
1178  size_t nconsumed = 0;
1179  int busy = 0;
1180  size_t len;
1181
1182  if (stream->flags & NGHTTP3_STREAM_FLAG_SHUT_RD) {
1183    *pnproc = srclen;
1184
1185    return (nghttp3_ssize)srclen;
1186  }
1187
1188  if (stream->flags & NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED) {
1189    *pnproc = 0;
1190
1191    if (srclen == 0) {
1192      return 0;
1193    }
1194
1195    rv = nghttp3_stream_buffer_data(stream, p, (size_t)(end - p));
1196    if (rv != 0) {
1197      return rv;
1198    }
1199    return 0;
1200  }
1201
1202  for (; p != end || busy;) {
1203    busy = 0;
1204    switch (rstate->state) {
1205    case NGHTTP3_REQ_STREAM_STATE_FRAME_TYPE:
1206      assert(end - p > 0);
1207      nread = nghttp3_read_varint(rvint, p, (size_t)(end - p), fin);
1208      if (nread < 0) {
1209        return NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR;
1210      }
1211
1212      p += nread;
1213      nconsumed += (size_t)nread;
1214      if (rvint->left) {
1215        goto almost_done;
1216      }
1217
1218      rstate->fr.hd.type = rvint->acc;
1219      nghttp3_varint_read_state_reset(rvint);
1220      rstate->state = NGHTTP3_REQ_STREAM_STATE_FRAME_LENGTH;
1221      if (p == end) {
1222        goto almost_done;
1223      }
1224      /* Fall through */
1225    case NGHTTP3_REQ_STREAM_STATE_FRAME_LENGTH:
1226      assert(end - p > 0);
1227      nread = nghttp3_read_varint(rvint, p, (size_t)(end - p), fin);
1228      if (nread < 0) {
1229        return NGHTTP3_ERR_H3_FRAME_ERROR;
1230      }
1231
1232      p += nread;
1233      nconsumed += (size_t)nread;
1234      if (rvint->left) {
1235        goto almost_done;
1236      }
1237
1238      rstate->left = rstate->fr.hd.length = rvint->acc;
1239      nghttp3_varint_read_state_reset(rvint);
1240
1241      switch (rstate->fr.hd.type) {
1242      case NGHTTP3_FRAME_DATA:
1243        rv = nghttp3_stream_transit_rx_http_state(
1244            stream, NGHTTP3_HTTP_EVENT_DATA_BEGIN);
1245        if (rv != 0) {
1246          return rv;
1247        }
1248        /* DATA frame might be empty. */
1249        if (rstate->left == 0) {
1250          rv = nghttp3_stream_transit_rx_http_state(
1251              stream, NGHTTP3_HTTP_EVENT_DATA_END);
1252          assert(0 == rv);
1253
1254          nghttp3_stream_read_state_reset(rstate);
1255          break;
1256        }
1257        rstate->state = NGHTTP3_REQ_STREAM_STATE_DATA;
1258        break;
1259      case NGHTTP3_FRAME_HEADERS:
1260        rv = nghttp3_stream_transit_rx_http_state(
1261            stream, NGHTTP3_HTTP_EVENT_HEADERS_BEGIN);
1262        if (rv != 0) {
1263          return rv;
1264        }
1265        if (rstate->left == 0) {
1266          rv = nghttp3_stream_empty_headers_allowed(stream);
1267          if (rv != 0) {
1268            return rv;
1269          }
1270
1271          rv = nghttp3_stream_transit_rx_http_state(
1272              stream, NGHTTP3_HTTP_EVENT_HEADERS_END);
1273          assert(0 == rv);
1274
1275          nghttp3_stream_read_state_reset(rstate);
1276          break;
1277        }
1278
1279        switch (stream->rx.hstate) {
1280        case NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN:
1281        case NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN:
1282          rv = conn_call_begin_headers(conn, stream);
1283          break;
1284        case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN:
1285        case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN:
1286          rv = conn_call_begin_trailers(conn, stream);
1287          break;
1288        default:
1289          /* Unreachable */
1290          assert(0);
1291        }
1292
1293        if (rv != 0) {
1294          return rv;
1295        }
1296
1297        rstate->state = NGHTTP3_REQ_STREAM_STATE_HEADERS;
1298        break;
1299      case NGHTTP3_FRAME_PUSH_PROMISE: /* We do not support push */
1300      case NGHTTP3_FRAME_CANCEL_PUSH:
1301      case NGHTTP3_FRAME_SETTINGS:
1302      case NGHTTP3_FRAME_GOAWAY:
1303      case NGHTTP3_FRAME_MAX_PUSH_ID:
1304      case NGHTTP3_FRAME_PRIORITY_UPDATE:
1305      case NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID:
1306      case NGHTTP3_H2_FRAME_PRIORITY:
1307      case NGHTTP3_H2_FRAME_PING:
1308      case NGHTTP3_H2_FRAME_WINDOW_UPDATE:
1309      case NGHTTP3_H2_FRAME_CONTINUATION:
1310        return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1311      default:
1312        /* TODO Handle reserved frame type */
1313        busy = 1;
1314        rstate->state = NGHTTP3_REQ_STREAM_STATE_IGN_FRAME;
1315        break;
1316      }
1317      break;
1318    case NGHTTP3_REQ_STREAM_STATE_DATA:
1319      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
1320      rv = nghttp3_conn_on_data(conn, stream, p, len);
1321      if (rv != 0) {
1322        return rv;
1323      }
1324      p += len;
1325      rstate->left -= (int64_t)len;
1326
1327      if (rstate->left) {
1328        goto almost_done;
1329      }
1330
1331      rv = nghttp3_stream_transit_rx_http_state(stream,
1332                                                NGHTTP3_HTTP_EVENT_DATA_END);
1333      assert(0 == rv);
1334
1335      nghttp3_stream_read_state_reset(rstate);
1336      break;
1337    case NGHTTP3_REQ_STREAM_STATE_HEADERS:
1338      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
1339      nread = nghttp3_conn_on_headers(conn, stream, p, len,
1340                                      (int64_t)len == rstate->left);
1341      if (nread < 0) {
1342        if (nread == NGHTTP3_ERR_MALFORMED_HTTP_HEADER) {
1343          goto http_header_error;
1344        }
1345
1346        return nread;
1347      }
1348
1349      p += nread;
1350      nconsumed += (size_t)nread;
1351      rstate->left -= nread;
1352
1353      if (stream->flags & NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED) {
1354        if (p != end && nghttp3_stream_get_buffered_datalen(stream) == 0) {
1355          rv = nghttp3_stream_buffer_data(stream, p, (size_t)(end - p));
1356          if (rv != 0) {
1357            return rv;
1358          }
1359        }
1360        *pnproc = (size_t)(p - src);
1361        return (nghttp3_ssize)nconsumed;
1362      }
1363
1364      if (rstate->left) {
1365        goto almost_done;
1366      }
1367
1368      switch (stream->rx.hstate) {
1369      case NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN:
1370        rv = nghttp3_http_on_request_headers(&stream->rx.http);
1371        break;
1372      case NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN:
1373        rv = nghttp3_http_on_response_headers(&stream->rx.http);
1374        break;
1375      case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN:
1376      case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN:
1377        rv = 0;
1378        break;
1379      default:
1380        /* Unreachable */
1381        assert(0);
1382        abort();
1383      }
1384
1385      if (rv != 0) {
1386        if (rv == NGHTTP3_ERR_MALFORMED_HTTP_HEADER) {
1387          goto http_header_error;
1388        }
1389
1390        return rv;
1391      }
1392
1393      switch (stream->rx.hstate) {
1394      case NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN:
1395        /* Only server utilizes priority information to schedule
1396           streams. */
1397        if (conn->server &&
1398            (stream->rx.http.flags & NGHTTP3_HTTP_FLAG_PRIORITY) &&
1399            !(stream->flags & NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED) &&
1400            !(stream->flags & NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET)) {
1401          rv = conn_update_stream_priority(conn, stream, stream->rx.http.pri);
1402          if (rv != 0) {
1403            return rv;
1404          }
1405        }
1406        /* fall through */
1407      case NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN:
1408        rv = conn_call_end_headers(conn, stream, p == end && fin);
1409        break;
1410      case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN:
1411      case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN:
1412        rv = conn_call_end_trailers(conn, stream, p == end && fin);
1413        break;
1414      default:
1415        /* Unreachable */
1416        assert(0);
1417      }
1418
1419      if (rv != 0) {
1420        return rv;
1421      }
1422
1423      rv = nghttp3_stream_transit_rx_http_state(stream,
1424                                                NGHTTP3_HTTP_EVENT_HEADERS_END);
1425      assert(0 == rv);
1426
1427      nghttp3_stream_read_state_reset(rstate);
1428
1429      break;
1430
1431    http_header_error:
1432      stream->flags |= NGHTTP3_STREAM_FLAG_HTTP_ERROR;
1433
1434      busy = 1;
1435      rstate->state = NGHTTP3_REQ_STREAM_STATE_IGN_REST;
1436
1437      rv = conn_call_stop_sending(conn, stream, NGHTTP3_H3_MESSAGE_ERROR);
1438      if (rv != 0) {
1439        return rv;
1440      }
1441
1442      rv = conn_call_reset_stream(conn, stream, NGHTTP3_H3_MESSAGE_ERROR);
1443      if (rv != 0) {
1444        return rv;
1445      }
1446
1447      break;
1448    case NGHTTP3_REQ_STREAM_STATE_IGN_FRAME:
1449      len = (size_t)nghttp3_min(rstate->left, (int64_t)(end - p));
1450      p += len;
1451      nconsumed += len;
1452      rstate->left -= (int64_t)len;
1453
1454      if (rstate->left) {
1455        goto almost_done;
1456      }
1457
1458      nghttp3_stream_read_state_reset(rstate);
1459      break;
1460    case NGHTTP3_REQ_STREAM_STATE_IGN_REST:
1461      nconsumed += (size_t)(end - p);
1462      *pnproc = (size_t)(end - src);
1463      return (nghttp3_ssize)nconsumed;
1464    }
1465  }
1466
1467almost_done:
1468  if (fin) {
1469    switch (rstate->state) {
1470    case NGHTTP3_REQ_STREAM_STATE_FRAME_TYPE:
1471      if (rvint->left) {
1472        return NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR;
1473      }
1474      rv = nghttp3_stream_transit_rx_http_state(stream,
1475                                                NGHTTP3_HTTP_EVENT_MSG_END);
1476      if (rv != 0) {
1477        return rv;
1478      }
1479      rv = conn_call_end_stream(conn, stream);
1480      if (rv != 0) {
1481        return rv;
1482      }
1483      break;
1484    case NGHTTP3_REQ_STREAM_STATE_IGN_REST:
1485      break;
1486    default:
1487      return NGHTTP3_ERR_H3_FRAME_ERROR;
1488    }
1489  }
1490
1491  *pnproc = (size_t)(p - src);
1492  return (nghttp3_ssize)nconsumed;
1493}
1494
1495int nghttp3_conn_on_data(nghttp3_conn *conn, nghttp3_stream *stream,
1496                         const uint8_t *data, size_t datalen) {
1497  int rv;
1498
1499  rv = nghttp3_http_on_data_chunk(stream, datalen);
1500  if (rv != 0) {
1501    return rv;
1502  }
1503
1504  if (!conn->callbacks.recv_data) {
1505    return 0;
1506  }
1507
1508  rv = conn->callbacks.recv_data(conn, stream->node.nid.id, data, datalen,
1509                                 conn->user_data, stream->user_data);
1510  if (rv != 0) {
1511    return NGHTTP3_ERR_CALLBACK_FAILURE;
1512  }
1513
1514  return 0;
1515}
1516
1517static nghttp3_pq *conn_get_sched_pq(nghttp3_conn *conn, nghttp3_tnode *tnode) {
1518  uint32_t urgency = nghttp3_pri_uint8_urgency(tnode->pri);
1519
1520  assert(urgency < NGHTTP3_URGENCY_LEVELS);
1521
1522  return &conn->sched[urgency].spq;
1523}
1524
1525static nghttp3_ssize conn_decode_headers(nghttp3_conn *conn,
1526                                         nghttp3_stream *stream,
1527                                         const uint8_t *src, size_t srclen,
1528                                         int fin) {
1529  nghttp3_ssize nread;
1530  int rv;
1531  nghttp3_qpack_decoder *qdec = &conn->qdec;
1532  nghttp3_qpack_nv nv;
1533  uint8_t flags;
1534  nghttp3_buf buf;
1535  nghttp3_recv_header recv_header = NULL;
1536  nghttp3_http_state *http;
1537  int request = 0;
1538  int trailers = 0;
1539
1540  switch (stream->rx.hstate) {
1541  case NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN:
1542    request = 1;
1543    /* Fall through */
1544  case NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN:
1545    recv_header = conn->callbacks.recv_header;
1546    break;
1547  case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN:
1548    request = 1;
1549    /* Fall through */
1550  case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN:
1551    trailers = 1;
1552    recv_header = conn->callbacks.recv_trailer;
1553    break;
1554  default:
1555    /* Unreachable */
1556    assert(0);
1557  }
1558  http = &stream->rx.http;
1559
1560  nghttp3_buf_wrap_init(&buf, (uint8_t *)src, srclen);
1561  buf.last = buf.end;
1562
1563  for (;;) {
1564    nread = nghttp3_qpack_decoder_read_request(qdec, &stream->qpack_sctx, &nv,
1565                                               &flags, buf.pos,
1566                                               nghttp3_buf_len(&buf), fin);
1567
1568    if (nread < 0) {
1569      return (int)nread;
1570    }
1571
1572    buf.pos += nread;
1573
1574    if (flags & NGHTTP3_QPACK_DECODE_FLAG_BLOCKED) {
1575      if (conn->local.settings.qpack_blocked_streams <=
1576          nghttp3_pq_size(&conn->qpack_blocked_streams)) {
1577        return NGHTTP3_ERR_QPACK_DECOMPRESSION_FAILED;
1578      }
1579
1580      stream->flags |= NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED;
1581      rv = nghttp3_conn_qpack_blocked_streams_push(conn, stream);
1582      if (rv != 0) {
1583        return rv;
1584      }
1585      break;
1586    }
1587
1588    if (flags & NGHTTP3_QPACK_DECODE_FLAG_FINAL) {
1589      nghttp3_qpack_stream_context_reset(&stream->qpack_sctx);
1590      break;
1591    }
1592
1593    if (nread == 0) {
1594      break;
1595    }
1596
1597    if (flags & NGHTTP3_QPACK_DECODE_FLAG_EMIT) {
1598      rv = nghttp3_http_on_header(
1599          http, &nv, request, trailers,
1600          conn->server && conn->local.settings.enable_connect_protocol);
1601      switch (rv) {
1602      case NGHTTP3_ERR_MALFORMED_HTTP_HEADER:
1603        break;
1604      case NGHTTP3_ERR_REMOVE_HTTP_HEADER:
1605        rv = 0;
1606        break;
1607      case 0:
1608        if (recv_header) {
1609          rv = recv_header(conn, stream->node.nid.id, nv.token, nv.name,
1610                           nv.value, nv.flags, conn->user_data,
1611                           stream->user_data);
1612          if (rv != 0) {
1613            rv = NGHTTP3_ERR_CALLBACK_FAILURE;
1614          }
1615        }
1616        break;
1617      default:
1618        /* Unreachable */
1619        assert(0);
1620      }
1621
1622      nghttp3_rcbuf_decref(nv.name);
1623      nghttp3_rcbuf_decref(nv.value);
1624
1625      if (rv != 0) {
1626        return rv;
1627      }
1628    }
1629  }
1630
1631  return buf.pos - src;
1632}
1633
1634nghttp3_ssize nghttp3_conn_on_headers(nghttp3_conn *conn,
1635                                      nghttp3_stream *stream,
1636                                      const uint8_t *src, size_t srclen,
1637                                      int fin) {
1638  if (srclen == 0 && !fin) {
1639    return 0;
1640  }
1641
1642  return conn_decode_headers(conn, stream, src, srclen, fin);
1643}
1644
1645int nghttp3_conn_on_settings_entry_received(nghttp3_conn *conn,
1646                                            const nghttp3_frame_settings *fr) {
1647  const nghttp3_settings_entry *ent = &fr->iv[0];
1648  nghttp3_settings *dest = &conn->remote.settings;
1649
1650  /* TODO Check for duplicates */
1651  switch (ent->id) {
1652  case NGHTTP3_SETTINGS_ID_MAX_FIELD_SECTION_SIZE:
1653    dest->max_field_section_size = ent->value;
1654    break;
1655  case NGHTTP3_SETTINGS_ID_QPACK_MAX_TABLE_CAPACITY:
1656    if (dest->qpack_max_dtable_capacity != 0) {
1657      return NGHTTP3_ERR_H3_SETTINGS_ERROR;
1658    }
1659
1660    if (ent->value == 0) {
1661      break;
1662    }
1663
1664    dest->qpack_max_dtable_capacity = (size_t)ent->value;
1665
1666    nghttp3_qpack_encoder_set_max_dtable_capacity(&conn->qenc,
1667                                                  (size_t)ent->value);
1668    break;
1669  case NGHTTP3_SETTINGS_ID_QPACK_BLOCKED_STREAMS:
1670    if (dest->qpack_blocked_streams != 0) {
1671      return NGHTTP3_ERR_H3_SETTINGS_ERROR;
1672    }
1673
1674    if (ent->value == 0) {
1675      break;
1676    }
1677
1678    dest->qpack_blocked_streams = (size_t)ent->value;
1679
1680    nghttp3_qpack_encoder_set_max_blocked_streams(
1681        &conn->qenc, (size_t)nghttp3_min(100, ent->value));
1682    break;
1683  case NGHTTP3_SETTINGS_ID_ENABLE_CONNECT_PROTOCOL:
1684    if (!conn->server) {
1685      break;
1686    }
1687    if (ent->value != 0 && ent->value != 1) {
1688      return NGHTTP3_ERR_H3_SETTINGS_ERROR;
1689    }
1690    if (ent->value == 0 && dest->enable_connect_protocol) {
1691      return NGHTTP3_ERR_H3_SETTINGS_ERROR;
1692    }
1693    dest->enable_connect_protocol = (int)ent->value;
1694    break;
1695  case NGHTTP3_H2_SETTINGS_ID_ENABLE_PUSH:
1696  case NGHTTP3_H2_SETTINGS_ID_MAX_CONCURRENT_STREAMS:
1697  case NGHTTP3_H2_SETTINGS_ID_INITIAL_WINDOW_SIZE:
1698  case NGHTTP3_H2_SETTINGS_ID_MAX_FRAME_SIZE:
1699    return NGHTTP3_ERR_H3_SETTINGS_ERROR;
1700  default:
1701    /* Ignore unknown settings ID */
1702    break;
1703  }
1704
1705  return 0;
1706}
1707
1708static int
1709conn_on_priority_update_stream(nghttp3_conn *conn,
1710                               const nghttp3_frame_priority_update *fr) {
1711  int64_t stream_id = fr->pri_elem_id;
1712  nghttp3_stream *stream;
1713  int rv;
1714
1715  if (!nghttp3_client_stream_bidi(stream_id) ||
1716      nghttp3_ord_stream_id(stream_id) > conn->remote.bidi.max_client_streams) {
1717    return NGHTTP3_ERR_H3_ID_ERROR;
1718  }
1719
1720  stream = nghttp3_conn_find_stream(conn, stream_id);
1721  if (stream == NULL) {
1722    if ((conn->flags & NGHTTP3_CONN_FLAG_GOAWAY_QUEUED) &&
1723        conn->tx.goaway_id <= stream_id) {
1724      /* Connection is going down.  Ignore priority signal. */
1725      return 0;
1726    }
1727
1728    rv = conn_bidi_idtr_open(conn, stream_id);
1729    if (rv != 0) {
1730      if (nghttp3_err_is_fatal(rv)) {
1731        return rv;
1732      }
1733
1734      assert(rv == NGHTTP3_ERR_STREAM_IN_USE);
1735
1736      /* The stream is gone.  Just ignore. */
1737      return 0;
1738    }
1739
1740    conn->rx.max_stream_id_bidi =
1741        nghttp3_max(conn->rx.max_stream_id_bidi, stream_id);
1742    rv = nghttp3_conn_create_stream(conn, &stream, stream_id);
1743    if (rv != 0) {
1744      return rv;
1745    }
1746
1747    stream->node.pri = nghttp3_pri_to_uint8(&fr->pri);
1748    stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED;
1749
1750    return 0;
1751  }
1752
1753  if (stream->flags & NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET) {
1754    return 0;
1755  }
1756
1757  stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED;
1758
1759  return conn_update_stream_priority(conn, stream,
1760                                     nghttp3_pri_to_uint8(&fr->pri));
1761}
1762
1763int nghttp3_conn_on_priority_update(nghttp3_conn *conn,
1764                                    const nghttp3_frame_priority_update *fr) {
1765  assert(conn->server);
1766  assert(fr->hd.type == NGHTTP3_FRAME_PRIORITY_UPDATE);
1767
1768  return conn_on_priority_update_stream(conn, fr);
1769}
1770
1771static int conn_stream_acked_data(nghttp3_stream *stream, int64_t stream_id,
1772                                  uint64_t datalen, void *user_data) {
1773  nghttp3_conn *conn = stream->conn;
1774  int rv;
1775
1776  if (!conn->callbacks.acked_stream_data) {
1777    return 0;
1778  }
1779
1780  rv = conn->callbacks.acked_stream_data(conn, stream_id, datalen,
1781                                         conn->user_data, user_data);
1782  if (rv != 0) {
1783    return NGHTTP3_ERR_CALLBACK_FAILURE;
1784  }
1785
1786  return 0;
1787}
1788
1789int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream,
1790                               int64_t stream_id) {
1791  nghttp3_stream *stream;
1792  int rv;
1793  nghttp3_stream_callbacks callbacks = {
1794      conn_stream_acked_data,
1795  };
1796
1797  rv = nghttp3_stream_new(&stream, stream_id, conn->next_seq, &callbacks,
1798                          &conn->out_chunk_objalloc, &conn->stream_objalloc,
1799                          conn->mem);
1800  if (rv != 0) {
1801    return rv;
1802  }
1803
1804  stream->conn = conn;
1805
1806  rv = nghttp3_map_insert(&conn->streams,
1807                          (nghttp3_map_key_type)stream->node.nid.id, stream);
1808  if (rv != 0) {
1809    nghttp3_stream_del(stream);
1810    return rv;
1811  }
1812
1813  ++conn->next_seq;
1814  *pstream = stream;
1815
1816  return 0;
1817}
1818
1819nghttp3_stream *nghttp3_conn_find_stream(nghttp3_conn *conn,
1820                                         int64_t stream_id) {
1821  return nghttp3_map_find(&conn->streams, (nghttp3_map_key_type)stream_id);
1822}
1823
1824int nghttp3_conn_bind_control_stream(nghttp3_conn *conn, int64_t stream_id) {
1825  nghttp3_stream *stream;
1826  nghttp3_frame_entry frent;
1827  int rv;
1828
1829  assert(!conn->server || nghttp3_server_stream_uni(stream_id));
1830  assert(conn->server || nghttp3_client_stream_uni(stream_id));
1831
1832  if (conn->tx.ctrl) {
1833    return NGHTTP3_ERR_INVALID_STATE;
1834  }
1835
1836  rv = nghttp3_conn_create_stream(conn, &stream, stream_id);
1837  if (rv != 0) {
1838    return rv;
1839  }
1840
1841  stream->type = NGHTTP3_STREAM_TYPE_CONTROL;
1842
1843  conn->tx.ctrl = stream;
1844
1845  rv = nghttp3_stream_write_stream_type(stream);
1846  if (rv != 0) {
1847    return rv;
1848  }
1849
1850  frent.fr.hd.type = NGHTTP3_FRAME_SETTINGS;
1851  frent.aux.settings.local_settings = &conn->local.settings;
1852
1853  return nghttp3_stream_frq_add(stream, &frent);
1854}
1855
1856int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn, int64_t qenc_stream_id,
1857                                    int64_t qdec_stream_id) {
1858  nghttp3_stream *stream;
1859  int rv;
1860
1861  assert(!conn->server || nghttp3_server_stream_uni(qenc_stream_id));
1862  assert(!conn->server || nghttp3_server_stream_uni(qdec_stream_id));
1863  assert(conn->server || nghttp3_client_stream_uni(qenc_stream_id));
1864  assert(conn->server || nghttp3_client_stream_uni(qdec_stream_id));
1865
1866  if (conn->tx.qenc || conn->tx.qdec) {
1867    return NGHTTP3_ERR_INVALID_STATE;
1868  }
1869
1870  rv = nghttp3_conn_create_stream(conn, &stream, qenc_stream_id);
1871  if (rv != 0) {
1872    return rv;
1873  }
1874
1875  stream->type = NGHTTP3_STREAM_TYPE_QPACK_ENCODER;
1876
1877  conn->tx.qenc = stream;
1878
1879  rv = nghttp3_stream_write_stream_type(stream);
1880  if (rv != 0) {
1881    return rv;
1882  }
1883
1884  rv = nghttp3_conn_create_stream(conn, &stream, qdec_stream_id);
1885  if (rv != 0) {
1886    return rv;
1887  }
1888
1889  stream->type = NGHTTP3_STREAM_TYPE_QPACK_DECODER;
1890
1891  conn->tx.qdec = stream;
1892
1893  return nghttp3_stream_write_stream_type(stream);
1894}
1895
1896static nghttp3_ssize conn_writev_stream(nghttp3_conn *conn, int64_t *pstream_id,
1897                                        int *pfin, nghttp3_vec *vec,
1898                                        size_t veccnt, nghttp3_stream *stream) {
1899  int rv;
1900  nghttp3_ssize n;
1901
1902  assert(veccnt > 0);
1903
1904  /* If stream is blocked by read callback, don't attempt to fill
1905     more. */
1906  if (!(stream->flags & NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED)) {
1907    rv = nghttp3_stream_fill_outq(stream);
1908    if (rv != 0) {
1909      return rv;
1910    }
1911  }
1912
1913  if (!nghttp3_stream_uni(stream->node.nid.id) && conn->tx.qenc &&
1914      !nghttp3_stream_is_blocked(conn->tx.qenc)) {
1915    n = nghttp3_stream_writev(conn->tx.qenc, pfin, vec, veccnt);
1916    if (n < 0) {
1917      return n;
1918    }
1919    if (n) {
1920      *pstream_id = conn->tx.qenc->node.nid.id;
1921      return n;
1922    }
1923  }
1924
1925  n = nghttp3_stream_writev(stream, pfin, vec, veccnt);
1926  if (n < 0) {
1927    return n;
1928  }
1929  /* We might just want to write stream fin without sending any stream
1930     data. */
1931  if (n == 0 && *pfin == 0) {
1932    return 0;
1933  }
1934
1935  *pstream_id = stream->node.nid.id;
1936
1937  return n;
1938}
1939
1940nghttp3_ssize nghttp3_conn_writev_stream(nghttp3_conn *conn,
1941                                         int64_t *pstream_id, int *pfin,
1942                                         nghttp3_vec *vec, size_t veccnt) {
1943  nghttp3_ssize ncnt;
1944  nghttp3_stream *stream;
1945  int rv;
1946
1947  *pstream_id = -1;
1948  *pfin = 0;
1949
1950  if (veccnt == 0) {
1951    return 0;
1952  }
1953
1954  if (conn->tx.ctrl && !nghttp3_stream_is_blocked(conn->tx.ctrl)) {
1955    ncnt =
1956        conn_writev_stream(conn, pstream_id, pfin, vec, veccnt, conn->tx.ctrl);
1957    if (ncnt) {
1958      return ncnt;
1959    }
1960  }
1961
1962  if (conn->tx.qdec && !nghttp3_stream_is_blocked(conn->tx.qdec)) {
1963    rv = nghttp3_stream_write_qpack_decoder_stream(conn->tx.qdec);
1964    if (rv != 0) {
1965      return rv;
1966    }
1967
1968    ncnt =
1969        conn_writev_stream(conn, pstream_id, pfin, vec, veccnt, conn->tx.qdec);
1970    if (ncnt) {
1971      return ncnt;
1972    }
1973  }
1974
1975  if (conn->tx.qenc && !nghttp3_stream_is_blocked(conn->tx.qenc)) {
1976    ncnt =
1977        conn_writev_stream(conn, pstream_id, pfin, vec, veccnt, conn->tx.qenc);
1978    if (ncnt) {
1979      return ncnt;
1980    }
1981  }
1982
1983  stream = nghttp3_conn_get_next_tx_stream(conn);
1984  if (stream == NULL) {
1985    return 0;
1986  }
1987
1988  ncnt = conn_writev_stream(conn, pstream_id, pfin, vec, veccnt, stream);
1989  if (ncnt < 0) {
1990    return ncnt;
1991  }
1992
1993  if (nghttp3_client_stream_bidi(stream->node.nid.id) &&
1994      !nghttp3_stream_require_schedule(stream)) {
1995    nghttp3_conn_unschedule_stream(conn, stream);
1996  }
1997
1998  return ncnt;
1999}
2000
2001nghttp3_stream *nghttp3_conn_get_next_tx_stream(nghttp3_conn *conn) {
2002  size_t i;
2003  nghttp3_tnode *tnode;
2004  nghttp3_pq *pq;
2005
2006  for (i = 0; i < NGHTTP3_URGENCY_LEVELS; ++i) {
2007    pq = &conn->sched[i].spq;
2008    if (nghttp3_pq_empty(pq)) {
2009      continue;
2010    }
2011
2012    tnode = nghttp3_struct_of(nghttp3_pq_top(pq), nghttp3_tnode, pe);
2013
2014    return nghttp3_struct_of(tnode, nghttp3_stream, node);
2015  }
2016
2017  return NULL;
2018}
2019
2020int nghttp3_conn_add_write_offset(nghttp3_conn *conn, int64_t stream_id,
2021                                  size_t n) {
2022  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2023  int rv;
2024
2025  if (stream == NULL) {
2026    return 0;
2027  }
2028
2029  rv = nghttp3_stream_add_outq_offset(stream, n);
2030  if (rv != 0) {
2031    return rv;
2032  }
2033
2034  stream->unscheduled_nwrite += n;
2035
2036  if (!nghttp3_client_stream_bidi(stream->node.nid.id)) {
2037    return 0;
2038  }
2039
2040  if (!nghttp3_stream_require_schedule(stream)) {
2041    nghttp3_conn_unschedule_stream(conn, stream);
2042    return 0;
2043  }
2044
2045  if (stream->unscheduled_nwrite < NGHTTP3_STREAM_MIN_WRITELEN) {
2046    return 0;
2047  }
2048
2049  return nghttp3_conn_schedule_stream(conn, stream);
2050}
2051
2052int nghttp3_conn_add_ack_offset(nghttp3_conn *conn, int64_t stream_id,
2053                                uint64_t n) {
2054  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2055
2056  if (stream == NULL) {
2057    return 0;
2058  }
2059
2060  return nghttp3_stream_add_ack_offset(stream, n);
2061}
2062
2063static int conn_submit_headers_data(nghttp3_conn *conn, nghttp3_stream *stream,
2064                                    const nghttp3_nv *nva, size_t nvlen,
2065                                    const nghttp3_data_reader *dr) {
2066  int rv;
2067  nghttp3_nv *nnva;
2068  nghttp3_frame_entry frent;
2069
2070  rv = nghttp3_nva_copy(&nnva, nva, nvlen, conn->mem);
2071  if (rv != 0) {
2072    return rv;
2073  }
2074
2075  frent.fr.hd.type = NGHTTP3_FRAME_HEADERS;
2076  frent.fr.headers.nva = nnva;
2077  frent.fr.headers.nvlen = nvlen;
2078
2079  rv = nghttp3_stream_frq_add(stream, &frent);
2080  if (rv != 0) {
2081    nghttp3_nva_del(nnva, conn->mem);
2082    return rv;
2083  }
2084
2085  if (dr) {
2086    frent.fr.hd.type = NGHTTP3_FRAME_DATA;
2087    frent.aux.data.dr = *dr;
2088
2089    rv = nghttp3_stream_frq_add(stream, &frent);
2090    if (rv != 0) {
2091      return rv;
2092    }
2093  }
2094
2095  if (nghttp3_stream_require_schedule(stream)) {
2096    return nghttp3_conn_schedule_stream(conn, stream);
2097  }
2098
2099  return 0;
2100}
2101
2102int nghttp3_conn_schedule_stream(nghttp3_conn *conn, nghttp3_stream *stream) {
2103  /* Assume that stream stays on the same urgency level */
2104  nghttp3_tnode *node = stream_get_sched_node(stream);
2105  int rv;
2106
2107  rv = nghttp3_tnode_schedule(node, conn_get_sched_pq(conn, node),
2108                              stream->unscheduled_nwrite);
2109  if (rv != 0) {
2110    return rv;
2111  }
2112
2113  stream->unscheduled_nwrite = 0;
2114
2115  return 0;
2116}
2117
2118int nghttp3_conn_ensure_stream_scheduled(nghttp3_conn *conn,
2119                                         nghttp3_stream *stream) {
2120  if (nghttp3_tnode_is_scheduled(stream_get_sched_node(stream))) {
2121    return 0;
2122  }
2123
2124  return nghttp3_conn_schedule_stream(conn, stream);
2125}
2126
2127void nghttp3_conn_unschedule_stream(nghttp3_conn *conn,
2128                                    nghttp3_stream *stream) {
2129  nghttp3_tnode *node = stream_get_sched_node(stream);
2130
2131  nghttp3_tnode_unschedule(node, conn_get_sched_pq(conn, node));
2132}
2133
2134int nghttp3_conn_submit_request(nghttp3_conn *conn, int64_t stream_id,
2135                                const nghttp3_nv *nva, size_t nvlen,
2136                                const nghttp3_data_reader *dr,
2137                                void *stream_user_data) {
2138  nghttp3_stream *stream;
2139  int rv;
2140
2141  assert(!conn->server);
2142  assert(conn->tx.qenc);
2143
2144  assert(nghttp3_client_stream_bidi(stream_id));
2145
2146  /* TODO Should we check that stream_id is client stream_id? */
2147  /* TODO Check GOAWAY last stream ID */
2148  if (nghttp3_stream_uni(stream_id)) {
2149    return NGHTTP3_ERR_INVALID_ARGUMENT;
2150  }
2151
2152  if (conn->flags & NGHTTP3_CONN_FLAG_GOAWAY_RECVED) {
2153    return NGHTTP3_ERR_CONN_CLOSING;
2154  }
2155
2156  stream = nghttp3_conn_find_stream(conn, stream_id);
2157  if (stream != NULL) {
2158    return NGHTTP3_ERR_STREAM_IN_USE;
2159  }
2160
2161  rv = nghttp3_conn_create_stream(conn, &stream, stream_id);
2162  if (rv != 0) {
2163    return rv;
2164  }
2165  stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL;
2166  stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_END;
2167  stream->user_data = stream_user_data;
2168
2169  nghttp3_http_record_request_method(stream, nva, nvlen);
2170
2171  if (dr == NULL) {
2172    stream->flags |= NGHTTP3_STREAM_FLAG_WRITE_END_STREAM;
2173  }
2174
2175  return conn_submit_headers_data(conn, stream, nva, nvlen, dr);
2176}
2177
2178int nghttp3_conn_submit_info(nghttp3_conn *conn, int64_t stream_id,
2179                             const nghttp3_nv *nva, size_t nvlen) {
2180  nghttp3_stream *stream;
2181
2182  /* TODO Verify that it is allowed to send info (non-final response)
2183     now. */
2184  assert(conn->server);
2185  assert(conn->tx.qenc);
2186
2187  stream = nghttp3_conn_find_stream(conn, stream_id);
2188  if (stream == NULL) {
2189    return NGHTTP3_ERR_STREAM_NOT_FOUND;
2190  }
2191
2192  return conn_submit_headers_data(conn, stream, nva, nvlen, NULL);
2193}
2194
2195int nghttp3_conn_submit_response(nghttp3_conn *conn, int64_t stream_id,
2196                                 const nghttp3_nv *nva, size_t nvlen,
2197                                 const nghttp3_data_reader *dr) {
2198  nghttp3_stream *stream;
2199
2200  /* TODO Verify that it is allowed to send response now. */
2201  assert(conn->server);
2202  assert(conn->tx.qenc);
2203
2204  stream = nghttp3_conn_find_stream(conn, stream_id);
2205  if (stream == NULL) {
2206    return NGHTTP3_ERR_STREAM_NOT_FOUND;
2207  }
2208
2209  if (dr == NULL) {
2210    stream->flags |= NGHTTP3_STREAM_FLAG_WRITE_END_STREAM;
2211  }
2212
2213  return conn_submit_headers_data(conn, stream, nva, nvlen, dr);
2214}
2215
2216int nghttp3_conn_submit_trailers(nghttp3_conn *conn, int64_t stream_id,
2217                                 const nghttp3_nv *nva, size_t nvlen) {
2218  nghttp3_stream *stream;
2219
2220  /* TODO Verify that it is allowed to send trailer now. */
2221  assert(conn->tx.qenc);
2222
2223  stream = nghttp3_conn_find_stream(conn, stream_id);
2224  if (stream == NULL) {
2225    return NGHTTP3_ERR_STREAM_NOT_FOUND;
2226  }
2227
2228  if (stream->flags & NGHTTP3_STREAM_FLAG_WRITE_END_STREAM) {
2229    return NGHTTP3_ERR_INVALID_STATE;
2230  }
2231
2232  stream->flags |= NGHTTP3_STREAM_FLAG_WRITE_END_STREAM;
2233
2234  return conn_submit_headers_data(conn, stream, nva, nvlen, NULL);
2235}
2236
2237int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn) {
2238  nghttp3_frame_entry frent;
2239  int rv;
2240
2241  assert(conn->tx.ctrl);
2242
2243  frent.fr.hd.type = NGHTTP3_FRAME_GOAWAY;
2244  frent.fr.goaway.id = conn->server ? NGHTTP3_SHUTDOWN_NOTICE_STREAM_ID
2245                                    : NGHTTP3_SHUTDOWN_NOTICE_PUSH_ID;
2246
2247  assert(frent.fr.goaway.id <= conn->tx.goaway_id);
2248
2249  rv = nghttp3_stream_frq_add(conn->tx.ctrl, &frent);
2250  if (rv != 0) {
2251    return rv;
2252  }
2253
2254  conn->tx.goaway_id = frent.fr.goaway.id;
2255  conn->flags |= NGHTTP3_CONN_FLAG_GOAWAY_QUEUED;
2256
2257  return 0;
2258}
2259
2260int nghttp3_conn_shutdown(nghttp3_conn *conn) {
2261  nghttp3_frame_entry frent;
2262  int rv;
2263
2264  assert(conn->tx.ctrl);
2265
2266  frent.fr.hd.type = NGHTTP3_FRAME_GOAWAY;
2267  if (conn->server) {
2268    frent.fr.goaway.id =
2269        nghttp3_min((1ll << 62) - 4, conn->rx.max_stream_id_bidi + 4);
2270  } else {
2271    frent.fr.goaway.id = 0;
2272  }
2273
2274  assert(frent.fr.goaway.id <= conn->tx.goaway_id);
2275
2276  rv = nghttp3_stream_frq_add(conn->tx.ctrl, &frent);
2277  if (rv != 0) {
2278    return rv;
2279  }
2280
2281  conn->tx.goaway_id = frent.fr.goaway.id;
2282  conn->flags |= NGHTTP3_CONN_FLAG_GOAWAY_QUEUED;
2283
2284  return 0;
2285}
2286
2287int nghttp3_conn_reject_stream(nghttp3_conn *conn, nghttp3_stream *stream) {
2288  int rv;
2289
2290  rv = conn_call_stop_sending(conn, stream, NGHTTP3_H3_REQUEST_REJECTED);
2291  if (rv != 0) {
2292    return rv;
2293  }
2294
2295  return conn_call_reset_stream(conn, stream, NGHTTP3_H3_REQUEST_REJECTED);
2296}
2297
2298void nghttp3_conn_block_stream(nghttp3_conn *conn, int64_t stream_id) {
2299  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2300
2301  if (stream == NULL) {
2302    return;
2303  }
2304
2305  stream->flags |= NGHTTP3_STREAM_FLAG_FC_BLOCKED;
2306  stream->unscheduled_nwrite = 0;
2307
2308  if (nghttp3_client_stream_bidi(stream->node.nid.id)) {
2309    nghttp3_conn_unschedule_stream(conn, stream);
2310  }
2311}
2312
2313void nghttp3_conn_shutdown_stream_write(nghttp3_conn *conn, int64_t stream_id) {
2314  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2315
2316  if (stream == NULL) {
2317    return;
2318  }
2319
2320  stream->flags |= NGHTTP3_STREAM_FLAG_SHUT_WR;
2321  stream->unscheduled_nwrite = 0;
2322
2323  if (nghttp3_client_stream_bidi(stream->node.nid.id)) {
2324    nghttp3_conn_unschedule_stream(conn, stream);
2325  }
2326}
2327
2328int nghttp3_conn_unblock_stream(nghttp3_conn *conn, int64_t stream_id) {
2329  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2330
2331  if (stream == NULL) {
2332    return 0;
2333  }
2334
2335  stream->flags &= (uint16_t)~NGHTTP3_STREAM_FLAG_FC_BLOCKED;
2336
2337  if (nghttp3_client_stream_bidi(stream->node.nid.id) &&
2338      nghttp3_stream_require_schedule(stream)) {
2339    return nghttp3_conn_ensure_stream_scheduled(conn, stream);
2340  }
2341
2342  return 0;
2343}
2344
2345int nghttp3_conn_is_stream_writable(nghttp3_conn *conn, int64_t stream_id) {
2346  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2347
2348  if (stream == NULL) {
2349    return 0;
2350  }
2351
2352  return (stream->flags &
2353          (NGHTTP3_STREAM_FLAG_FC_BLOCKED |
2354           NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED | NGHTTP3_STREAM_FLAG_SHUT_WR |
2355           NGHTTP3_STREAM_FLAG_CLOSED)) == 0;
2356}
2357
2358int nghttp3_conn_resume_stream(nghttp3_conn *conn, int64_t stream_id) {
2359  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2360
2361  if (stream == NULL) {
2362    return 0;
2363  }
2364
2365  stream->flags &= (uint16_t)~NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED;
2366
2367  if (nghttp3_client_stream_bidi(stream->node.nid.id) &&
2368      nghttp3_stream_require_schedule(stream)) {
2369    return nghttp3_conn_ensure_stream_scheduled(conn, stream);
2370  }
2371
2372  return 0;
2373}
2374
2375int nghttp3_conn_close_stream(nghttp3_conn *conn, int64_t stream_id,
2376                              uint64_t app_error_code) {
2377  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2378
2379  if (stream == NULL) {
2380    return NGHTTP3_ERR_STREAM_NOT_FOUND;
2381  }
2382
2383  if (nghttp3_stream_uni(stream_id) &&
2384      stream->type != NGHTTP3_STREAM_TYPE_PUSH &&
2385      stream->type != NGHTTP3_STREAM_TYPE_UNKNOWN) {
2386    return NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM;
2387  }
2388
2389  stream->error_code = app_error_code;
2390
2391  nghttp3_conn_unschedule_stream(conn, stream);
2392
2393  if (stream->qpack_blocked_pe.index == NGHTTP3_PQ_BAD_INDEX) {
2394    return conn_delete_stream(conn, stream);
2395  }
2396
2397  stream->flags |= NGHTTP3_STREAM_FLAG_CLOSED;
2398  return 0;
2399}
2400
2401int nghttp3_conn_shutdown_stream_read(nghttp3_conn *conn, int64_t stream_id) {
2402  nghttp3_stream *stream;
2403
2404  if (!nghttp3_client_stream_bidi(stream_id)) {
2405    return 0;
2406  }
2407
2408  stream = nghttp3_conn_find_stream(conn, stream_id);
2409  if (stream) {
2410    if (stream->flags & NGHTTP3_STREAM_FLAG_SHUT_RD) {
2411      return 0;
2412    }
2413
2414    stream->flags |= NGHTTP3_STREAM_FLAG_SHUT_RD;
2415  }
2416
2417  return nghttp3_qpack_decoder_cancel_stream(&conn->qdec, stream_id);
2418}
2419
2420int nghttp3_conn_qpack_blocked_streams_push(nghttp3_conn *conn,
2421                                            nghttp3_stream *stream) {
2422  assert(stream->qpack_blocked_pe.index == NGHTTP3_PQ_BAD_INDEX);
2423
2424  return nghttp3_pq_push(&conn->qpack_blocked_streams,
2425                         &stream->qpack_blocked_pe);
2426}
2427
2428void nghttp3_conn_qpack_blocked_streams_pop(nghttp3_conn *conn) {
2429  assert(!nghttp3_pq_empty(&conn->qpack_blocked_streams));
2430  nghttp3_pq_pop(&conn->qpack_blocked_streams);
2431}
2432
2433void nghttp3_conn_set_max_client_streams_bidi(nghttp3_conn *conn,
2434                                              uint64_t max_streams) {
2435  assert(conn->server);
2436  assert(conn->remote.bidi.max_client_streams <= max_streams);
2437
2438  conn->remote.bidi.max_client_streams = max_streams;
2439}
2440
2441void nghttp3_conn_set_max_concurrent_streams(nghttp3_conn *conn,
2442                                             size_t max_concurrent_streams) {
2443  nghttp3_qpack_decoder_set_max_concurrent_streams(&conn->qdec,
2444                                                   max_concurrent_streams);
2445}
2446
2447int nghttp3_conn_set_stream_user_data(nghttp3_conn *conn, int64_t stream_id,
2448                                      void *stream_user_data) {
2449  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2450
2451  if (stream == NULL) {
2452    return NGHTTP3_ERR_STREAM_NOT_FOUND;
2453  }
2454
2455  stream->user_data = stream_user_data;
2456
2457  return 0;
2458}
2459
2460uint64_t nghttp3_conn_get_frame_payload_left(nghttp3_conn *conn,
2461                                             int64_t stream_id) {
2462  nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id);
2463
2464  if (stream == NULL) {
2465    return 0;
2466  }
2467
2468  return (uint64_t)stream->rstate.left;
2469}
2470
2471int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, nghttp3_pri *dest,
2472                                     int64_t stream_id) {
2473  nghttp3_stream *stream;
2474
2475  assert(conn->server);
2476
2477  if (!nghttp3_client_stream_bidi(stream_id)) {
2478    return NGHTTP3_ERR_INVALID_ARGUMENT;
2479  }
2480
2481  stream = nghttp3_conn_find_stream(conn, stream_id);
2482  if (stream == NULL) {
2483    return NGHTTP3_ERR_STREAM_NOT_FOUND;
2484  }
2485
2486  dest->urgency = nghttp3_pri_uint8_urgency(stream->node.pri);
2487  dest->inc = nghttp3_pri_uint8_inc(stream->node.pri);
2488
2489  return 0;
2490}
2491
2492int nghttp3_conn_set_stream_priority(nghttp3_conn *conn, int64_t stream_id,
2493                                     const nghttp3_pri *pri) {
2494  nghttp3_stream *stream;
2495  nghttp3_frame_entry frent;
2496
2497  assert(pri->urgency < NGHTTP3_URGENCY_LEVELS);
2498  assert(pri->inc == 0 || pri->inc == 1);
2499
2500  if (!nghttp3_client_stream_bidi(stream_id)) {
2501    return NGHTTP3_ERR_INVALID_ARGUMENT;
2502  }
2503
2504  stream = nghttp3_conn_find_stream(conn, stream_id);
2505  if (stream == NULL) {
2506    return NGHTTP3_ERR_STREAM_NOT_FOUND;
2507  }
2508
2509  if (conn->server) {
2510    stream->flags |= NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET;
2511
2512    return conn_update_stream_priority(conn, stream, nghttp3_pri_to_uint8(pri));
2513  }
2514
2515  frent.fr.hd.type = NGHTTP3_FRAME_PRIORITY_UPDATE;
2516  frent.fr.priority_update.pri_elem_id = stream_id;
2517  frent.fr.priority_update.pri = *pri;
2518
2519  return nghttp3_stream_frq_add(conn->tx.ctrl, &frent);
2520}
2521
2522int nghttp3_conn_is_remote_qpack_encoder_stream(nghttp3_conn *conn,
2523                                                int64_t stream_id) {
2524  nghttp3_stream *stream;
2525
2526  if (!conn_remote_stream_uni(conn, stream_id)) {
2527    return 0;
2528  }
2529
2530  stream = nghttp3_conn_find_stream(conn, stream_id);
2531  return stream && stream->type == NGHTTP3_STREAM_TYPE_QPACK_ENCODER;
2532}
2533
2534void nghttp3_settings_default_versioned(int settings_version,
2535                                        nghttp3_settings *settings) {
2536  (void)settings_version;
2537
2538  memset(settings, 0, sizeof(nghttp3_settings));
2539  settings->max_field_section_size = NGHTTP3_VARINT_MAX;
2540  settings->qpack_encoder_max_dtable_capacity =
2541      NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY;
2542}
2543