• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
conn_remote_stream_uni(nghttp3_conn * conn,int64_t stream_id)45 static 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 
conn_call_begin_headers(nghttp3_conn * conn,nghttp3_stream * stream)52 static 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 
conn_call_end_headers(nghttp3_conn * conn,nghttp3_stream * stream,int fin)69 static 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 
conn_call_begin_trailers(nghttp3_conn * conn,nghttp3_stream * stream)87 static 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 
conn_call_end_trailers(nghttp3_conn * conn,nghttp3_stream * stream,int fin)105 static 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 
conn_call_end_stream(nghttp3_conn * conn,nghttp3_stream * stream)123 static 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 
conn_call_stop_sending(nghttp3_conn * conn,nghttp3_stream * stream,uint64_t app_error_code)139 static 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 
conn_call_reset_stream(nghttp3_conn * conn,nghttp3_stream * stream,uint64_t app_error_code)156 static 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 
conn_call_deferred_consume(nghttp3_conn * conn,nghttp3_stream * stream,size_t nconsumed)173 static 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 
ricnt_less(const nghttp3_pq_entry * lhsx,const nghttp3_pq_entry * rhsx)191 static 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 
cycle_less(const nghttp3_pq_entry * lhsx,const nghttp3_pq_entry * rhsx)201 static 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 
conn_new(nghttp3_conn ** pconn,int server,int callbacks_version,const nghttp3_callbacks * callbacks,int settings_version,const nghttp3_settings * settings,const nghttp3_mem * mem,void * user_data)213 static 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 
277 qenc_init_fail:
278   nghttp3_qpack_decoder_free(&conn->qdec);
279 qdec_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 
nghttp3_conn_client_new_versioned(nghttp3_conn ** pconn,int callbacks_version,const nghttp3_callbacks * callbacks,int settings_version,const nghttp3_settings * settings,const nghttp3_mem * mem,void * user_data)288 int 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 
nghttp3_conn_server_new_versioned(nghttp3_conn ** pconn,int callbacks_version,const nghttp3_callbacks * callbacks,int settings_version,const nghttp3_settings * settings,const nghttp3_mem * mem,void * user_data)305 int 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 
free_stream(void * data,void * ptr)322 static 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 
nghttp3_conn_del(nghttp3_conn * conn)332 void 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 
conn_bidi_idtr_open(nghttp3_conn * conn,int64_t stream_id)362 static 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 
nghttp3_conn_read_stream(nghttp3_conn * conn,int64_t stream_id,const uint8_t * src,size_t srclen,int fin)377 nghttp3_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 
conn_read_type(nghttp3_conn * conn,nghttp3_stream * stream,const uint8_t * src,size_t srclen,int fin)479 static 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 
536 static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream);
537 
nghttp3_conn_read_uni(nghttp3_conn * conn,nghttp3_stream * stream,const uint8_t * src,size_t srclen,int fin)538 nghttp3_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 
frame_fin(nghttp3_stream_read_state * rstate,size_t len)617 static int frame_fin(nghttp3_stream_read_state *rstate, size_t len) {
618   return (int64_t)len >= rstate->left;
619 }
620 
nghttp3_conn_read_control(nghttp3_conn * conn,nghttp3_stream * stream,const uint8_t * src,size_t srclen)621 nghttp3_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 
conn_delete_stream(nghttp3_conn * conn,nghttp3_stream * stream)1024 static 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 
conn_process_blocked_stream_data(nghttp3_conn * conn,nghttp3_stream * stream)1053 static 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 
nghttp3_conn_read_qpack_encoder(nghttp3_conn * conn,const uint8_t * src,size_t srclen)1108 nghttp3_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 
nghttp3_conn_read_qpack_decoder(nghttp3_conn * conn,const uint8_t * src,size_t srclen)1141 nghttp3_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 
stream_get_sched_node(nghttp3_stream * stream)1147 static nghttp3_tnode *stream_get_sched_node(nghttp3_stream *stream) {
1148   return &stream->node;
1149 }
1150 
conn_update_stream_priority(nghttp3_conn * conn,nghttp3_stream * stream,uint8_t pri)1151 static 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 
nghttp3_conn_read_bidi(nghttp3_conn * conn,size_t * pnproc,nghttp3_stream * stream,const uint8_t * src,size_t srclen,int fin)1170 nghttp3_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 
1467 almost_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 
nghttp3_conn_on_data(nghttp3_conn * conn,nghttp3_stream * stream,const uint8_t * data,size_t datalen)1495 int 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 
conn_get_sched_pq(nghttp3_conn * conn,nghttp3_tnode * tnode)1517 static 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 
conn_decode_headers(nghttp3_conn * conn,nghttp3_stream * stream,const uint8_t * src,size_t srclen,int fin)1525 static 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 
nghttp3_conn_on_headers(nghttp3_conn * conn,nghttp3_stream * stream,const uint8_t * src,size_t srclen,int fin)1634 nghttp3_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 
nghttp3_conn_on_settings_entry_received(nghttp3_conn * conn,const nghttp3_frame_settings * fr)1645 int 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 
1708 static int
conn_on_priority_update_stream(nghttp3_conn * conn,const nghttp3_frame_priority_update * fr)1709 conn_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 
nghttp3_conn_on_priority_update(nghttp3_conn * conn,const nghttp3_frame_priority_update * fr)1763 int 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 
conn_stream_acked_data(nghttp3_stream * stream,int64_t stream_id,uint64_t datalen,void * user_data)1771 static 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 
nghttp3_conn_create_stream(nghttp3_conn * conn,nghttp3_stream ** pstream,int64_t stream_id)1789 int 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 
nghttp3_conn_find_stream(nghttp3_conn * conn,int64_t stream_id)1819 nghttp3_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 
nghttp3_conn_bind_control_stream(nghttp3_conn * conn,int64_t stream_id)1824 int 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 
nghttp3_conn_bind_qpack_streams(nghttp3_conn * conn,int64_t qenc_stream_id,int64_t qdec_stream_id)1856 int 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 
conn_writev_stream(nghttp3_conn * conn,int64_t * pstream_id,int * pfin,nghttp3_vec * vec,size_t veccnt,nghttp3_stream * stream)1896 static 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 
nghttp3_conn_writev_stream(nghttp3_conn * conn,int64_t * pstream_id,int * pfin,nghttp3_vec * vec,size_t veccnt)1940 nghttp3_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 
nghttp3_conn_get_next_tx_stream(nghttp3_conn * conn)2001 nghttp3_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 
nghttp3_conn_add_write_offset(nghttp3_conn * conn,int64_t stream_id,size_t n)2020 int 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 
nghttp3_conn_add_ack_offset(nghttp3_conn * conn,int64_t stream_id,uint64_t n)2052 int 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 
conn_submit_headers_data(nghttp3_conn * conn,nghttp3_stream * stream,const nghttp3_nv * nva,size_t nvlen,const nghttp3_data_reader * dr)2063 static 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 
nghttp3_conn_schedule_stream(nghttp3_conn * conn,nghttp3_stream * stream)2102 int 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 
nghttp3_conn_ensure_stream_scheduled(nghttp3_conn * conn,nghttp3_stream * stream)2118 int 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 
nghttp3_conn_unschedule_stream(nghttp3_conn * conn,nghttp3_stream * stream)2127 void 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 
nghttp3_conn_submit_request(nghttp3_conn * conn,int64_t stream_id,const nghttp3_nv * nva,size_t nvlen,const nghttp3_data_reader * dr,void * stream_user_data)2134 int 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 
nghttp3_conn_submit_info(nghttp3_conn * conn,int64_t stream_id,const nghttp3_nv * nva,size_t nvlen)2178 int 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 
nghttp3_conn_submit_response(nghttp3_conn * conn,int64_t stream_id,const nghttp3_nv * nva,size_t nvlen,const nghttp3_data_reader * dr)2195 int 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 
nghttp3_conn_submit_trailers(nghttp3_conn * conn,int64_t stream_id,const nghttp3_nv * nva,size_t nvlen)2216 int 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 
nghttp3_conn_submit_shutdown_notice(nghttp3_conn * conn)2237 int 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 
nghttp3_conn_shutdown(nghttp3_conn * conn)2260 int 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 
nghttp3_conn_reject_stream(nghttp3_conn * conn,nghttp3_stream * stream)2287 int 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 
nghttp3_conn_block_stream(nghttp3_conn * conn,int64_t stream_id)2298 void 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 
nghttp3_conn_shutdown_stream_write(nghttp3_conn * conn,int64_t stream_id)2313 void 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 
nghttp3_conn_unblock_stream(nghttp3_conn * conn,int64_t stream_id)2328 int 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 
nghttp3_conn_is_stream_writable(nghttp3_conn * conn,int64_t stream_id)2345 int 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 
nghttp3_conn_resume_stream(nghttp3_conn * conn,int64_t stream_id)2358 int 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 
nghttp3_conn_close_stream(nghttp3_conn * conn,int64_t stream_id,uint64_t app_error_code)2375 int 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 
nghttp3_conn_shutdown_stream_read(nghttp3_conn * conn,int64_t stream_id)2401 int 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 
nghttp3_conn_qpack_blocked_streams_push(nghttp3_conn * conn,nghttp3_stream * stream)2420 int 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 
nghttp3_conn_qpack_blocked_streams_pop(nghttp3_conn * conn)2428 void 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 
nghttp3_conn_set_max_client_streams_bidi(nghttp3_conn * conn,uint64_t max_streams)2433 void 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 
nghttp3_conn_set_max_concurrent_streams(nghttp3_conn * conn,size_t max_concurrent_streams)2441 void 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 
nghttp3_conn_set_stream_user_data(nghttp3_conn * conn,int64_t stream_id,void * stream_user_data)2447 int 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 
nghttp3_conn_get_frame_payload_left(nghttp3_conn * conn,int64_t stream_id)2460 uint64_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 
nghttp3_conn_get_stream_priority(nghttp3_conn * conn,nghttp3_pri * dest,int64_t stream_id)2471 int 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 
nghttp3_conn_set_stream_priority(nghttp3_conn * conn,int64_t stream_id,const nghttp3_pri * pri)2492 int 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 
nghttp3_conn_is_remote_qpack_encoder_stream(nghttp3_conn * conn,int64_t stream_id)2522 int 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 
nghttp3_settings_default_versioned(int settings_version,nghttp3_settings * settings)2534 void 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