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