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