lsquic_qdec_hdl.c revision a74702c6
1/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * lsquic_qdec_hdl.c -- QPACK decoder streams handler 4 */ 5 6#include <assert.h> 7#include <errno.h> 8#include <inttypes.h> 9#include <stdlib.h> 10#include <string.h> 11#include <sys/queue.h> 12 13#include "lsquic.h" 14#include "lsquic_types.h" 15#include "lsxpack_header.h" 16#include "lsquic_int_types.h" 17#include "lsquic_sfcw.h" 18#include "lsquic_varint.h" 19#include "lsquic_hq.h" 20#include "lsquic_hash.h" 21#include "lsquic_stream.h" 22#include "lsquic_frab_list.h" 23#include "lsqpack.h" 24#include "lsquic_http1x_if.h" 25#include "lsquic_qdec_hdl.h" 26#include "lsquic_mm.h" 27#include "lsquic_engine_public.h" 28#include "lsquic_headers.h" 29#include "lsquic_conn.h" 30#include "lsquic_conn_flow.h" 31#include "lsquic_rtt.h" 32#include "lsquic_conn_public.h" 33#include "lsquic_hq.h" 34#include "lsquic_parse.h" 35#include "lsquic_qpack_exp.h" 36#include "lsquic_util.h" 37 38#define LSQUIC_LOGGER_MODULE LSQLM_QDEC_HDL 39#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(qdh->qdh_conn) 40#include "lsquic_logger.h" 41 42static const struct lsqpack_dec_hset_if dhi_if; 43 44 45struct header_ctx 46{ 47 void *hset; 48 struct qpack_dec_hdl *qdh; 49 enum ppc_flags ppc_flags; 50 struct lsquic_ext_http_prio ehp; 51}; 52 53 54/* We need to allocate struct uncompressed_headers anyway when header set 55 * is complete and we give it to the stream using lsquic_stream_uh_in(). 56 * To save a malloc, we reuse context after we're done with it. 57 */ 58union hblock_ctx 59{ 60 struct header_ctx ctx; 61 unsigned char space_for_uh[sizeof(struct uncompressed_headers)]; 62}; 63 64 65static int 66qdh_write_decoder (struct qpack_dec_hdl *qdh, const unsigned char *buf, 67 size_t sz) 68{ 69 ssize_t nw; 70 71 if (!(qdh->qdh_dec_sm_out && lsquic_frab_list_empty(&qdh->qdh_fral))) 72 { 73 write_to_frab: 74 if (0 == lsquic_frab_list_write(&qdh->qdh_fral, 75 (unsigned char *) buf, sz)) 76 { 77 LSQ_DEBUG("wrote %zu bytes to frab list", sz); 78 lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 79 return 0; 80 } 81 else 82 { 83 LSQ_INFO("error writing to frab list"); 84 return -1; 85 } 86 } 87 88 nw = lsquic_stream_write(qdh->qdh_dec_sm_out, buf, sz); 89 if (nw < 0) 90 { 91 LSQ_INFO("error writing to outgoing QPACK decoder stream: %s", 92 strerror(errno)); 93 return -1; 94 } 95 LSQ_DEBUG("wrote %zd bytes to outgoing QPACK decoder stream", nw); 96 97 if ((size_t) nw == sz) 98 return 0; 99 100 buf = buf + nw; 101 sz -= (size_t) nw; 102 goto write_to_frab; 103} 104 105 106static int 107qdh_write_type (struct qpack_dec_hdl *qdh) 108{ 109 int s; 110 111#ifndef NDEBUG 112 const char *env = getenv("LSQUIC_RND_VARINT_LEN"); 113 if (env && atoi(env)) 114 { 115 s = rand() & 3; 116 LSQ_DEBUG("writing %d-byte stream type", 1 << s); 117 } 118 else 119#endif 120 s = 0; 121 122 switch (s) 123 { 124 case 0: 125 return qdh_write_decoder(qdh, 126 (unsigned char []) { HQUST_QPACK_DEC }, 1); 127 case 1: 128 return qdh_write_decoder(qdh, 129 (unsigned char []) { 0x40, HQUST_QPACK_DEC }, 2); 130 case 2: 131 return qdh_write_decoder(qdh, 132 (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_DEC }, 4); 133 default: 134 return qdh_write_decoder(qdh, 135 (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 HQUST_QPACK_DEC }, 8); 137 } 138} 139 140 141static void 142qdh_begin_out (struct qpack_dec_hdl *qdh) 143{ 144 if (0 != qdh_write_type(qdh)) 145 { 146 LSQ_WARN("%s: could not write to decoder", __func__); 147 qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 148 "cannot write to decoder stream"); 149 } 150} 151 152 153int 154lsquic_qdh_init (struct qpack_dec_hdl *qdh, struct lsquic_conn *conn, 155 int is_server, const struct lsquic_engine_public *enpub, 156 unsigned dyn_table_size, unsigned max_risked_streams) 157{ 158 enum lsqpack_dec_opts dec_opts; 159 160 dec_opts = 0; 161 if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HTTP1X) 162 dec_opts |= LSQPACK_DEC_OPT_HTTP1X; 163 if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAME) 164 dec_opts |= LSQPACK_DEC_OPT_HASH_NAME; 165 if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL) 166 dec_opts |= LSQPACK_DEC_OPT_HASH_NAMEVAL; 167 168 if (conn->cn_flags & LSCONN_SERVER) 169 qdh->qdh_flags |= QDH_SERVER; 170 if (enpub->enp_settings.es_qpack_experiment) 171 { 172 qdh->qdh_exp_rec = lsquic_qpack_exp_new(); 173 if (qdh->qdh_exp_rec) 174 { 175 if (conn->cn_flags & LSCONN_SERVER) 176 qdh->qdh_exp_rec->qer_flags |= QER_SERVER; 177 qdh->qdh_exp_rec->qer_used_max_size = dyn_table_size; 178 qdh->qdh_exp_rec->qer_used_max_blocked = max_risked_streams; 179 } 180 } 181 if (!qdh->qdh_exp_rec && LSQ_LOG_ENABLED_EXT(LSQ_LOG_NOTICE, LSQLM_CONN)) 182 qdh->qdh_flags |= QDH_SAVE_UA; 183 184 qdh->qdh_conn = conn; 185 lsquic_frab_list_init(&qdh->qdh_fral, 0x400, NULL, NULL, NULL); 186 lsqpack_dec_init(&qdh->qdh_decoder, (void *) conn, dyn_table_size, 187 max_risked_streams, &dhi_if, dec_opts); 188 qdh->qdh_flags |= QDH_INITIALIZED; 189 qdh->qdh_enpub = enpub; 190 if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 191 { 192 qdh->qdh_h1x_ctor_ctx = (struct http1x_ctor_ctx) { 193 .conn = conn, 194 .max_headers_sz = MAX_HTTP1X_HEADERS_SIZE, 195 .is_server = is_server, 196 }; 197 qdh->qdh_hsi_ctx = &qdh->qdh_h1x_ctor_ctx; 198 } 199 else 200 qdh->qdh_hsi_ctx = qdh->qdh_enpub->enp_hsi_ctx; 201 if (qdh->qdh_dec_sm_out) 202 qdh_begin_out(qdh); 203 if (qdh->qdh_enc_sm_in) 204 lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1); 205 LSQ_DEBUG("initialized"); 206 return 0; 207} 208 209 210static void 211qdh_log_and_clean_exp_rec (struct qpack_dec_hdl *qdh) 212{ 213 char buf[0x400]; 214 215 qdh->qdh_exp_rec->qer_comp_ratio = lsqpack_dec_ratio(&qdh->qdh_decoder); 216 /* Naughty: poking inside the decoder, it's not exposed. (Should it be?) */ 217 qdh->qdh_exp_rec->qer_peer_max_size = qdh->qdh_decoder.qpd_cur_max_capacity; 218 (void) lsquic_qpack_exp_to_xml(qdh->qdh_exp_rec, buf, sizeof(buf)); 219 LSQ_NOTICE("%s", buf); 220 lsquic_qpack_exp_destroy(qdh->qdh_exp_rec); 221 qdh->qdh_exp_rec = NULL; 222} 223 224 225void 226lsquic_qdh_cleanup (struct qpack_dec_hdl *qdh) 227{ 228 if (qdh->qdh_flags & QDH_INITIALIZED) 229 { 230 LSQ_DEBUG("cleanup"); 231 if (qdh->qdh_exp_rec) 232 qdh_log_and_clean_exp_rec(qdh); 233 if (qdh->qdh_ua) 234 { 235 free(qdh->qdh_ua); 236 qdh->qdh_ua = NULL; 237 } 238 lsqpack_dec_cleanup(&qdh->qdh_decoder); 239 lsquic_frab_list_cleanup(&qdh->qdh_fral); 240 qdh->qdh_flags &= ~QDH_INITIALIZED; 241 } 242} 243 244static lsquic_stream_ctx_t * 245qdh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 246{ 247 struct qpack_dec_hdl *const qdh = stream_if_ctx; 248 qdh->qdh_dec_sm_out = stream; 249 if (qdh->qdh_flags & QDH_INITIALIZED) 250 qdh_begin_out(qdh); 251 LSQ_DEBUG("initialized outgoing decoder stream"); 252 return (void *) qdh; 253} 254 255 256static void 257qdh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 258{ 259 struct qpack_dec_hdl *const qdh = (void *) ctx; 260 struct lsquic_reader reader; 261 ssize_t nw; 262 unsigned char buf[LSQPACK_LONGEST_ICI]; 263 264 if (lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 265 { 266 nw = lsqpack_dec_write_ici(&qdh->qdh_decoder, buf, sizeof(buf)); 267 if (nw > 0) 268 { 269 if (0 == qdh_write_decoder(qdh, buf, nw)) 270 LSQ_DEBUG("wrote %zd-byte TSS instruction", nw); 271 else 272 goto err; 273 } 274 else if (nw < 0) 275 { 276 LSQ_WARN("could not generate TSS instruction"); 277 goto err; 278 } 279 } 280 281 if (lsquic_frab_list_empty(&qdh->qdh_fral)) 282 { 283 LSQ_DEBUG("%s: nothing to write", __func__); 284 lsquic_stream_wantwrite(stream, 0); 285 return; 286 } 287 288 reader = (struct lsquic_reader) { 289 .lsqr_read = lsquic_frab_list_read, 290 .lsqr_size = lsquic_frab_list_size, 291 .lsqr_ctx = &qdh->qdh_fral, 292 }; 293 294 nw = lsquic_stream_writef(stream, &reader); 295 if (nw >= 0) 296 { 297 LSQ_DEBUG("wrote %zd bytes to stream", nw); 298 (void) lsquic_stream_flush(stream); 299 if (lsquic_frab_list_empty(&qdh->qdh_fral)) 300 { 301 lsquic_stream_wantwrite(stream, 0); 302 if (qdh->qdh_on_dec_sent_func) 303 { 304 LSQ_DEBUG("buffered data written: call callback"); 305 qdh->qdh_on_dec_sent_func(qdh->qdh_on_dec_sent_ctx); 306 qdh->qdh_on_dec_sent_func = NULL; 307 qdh->qdh_on_dec_sent_ctx = NULL; 308 } 309 } 310 } 311 else 312 { 313 LSQ_WARN("cannot write to stream: %s", strerror(errno)); 314 err: 315 lsquic_stream_wantwrite(stream, 0); 316 qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 317 "cannot write to stream"); 318 } 319} 320 321 322static void 323qdh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 324{ 325 struct qpack_dec_hdl *const qdh = (void *) ctx; 326 qdh->qdh_dec_sm_out = NULL; 327 LSQ_DEBUG("closed outgoing decoder stream"); 328} 329 330 331static void 332qdh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 333{ 334 assert(0); 335} 336 337 338static const struct lsquic_stream_if qdh_dec_sm_out_if = 339{ 340 .on_new_stream = qdh_out_on_new, 341 .on_read = qdh_out_on_read, 342 .on_write = qdh_out_on_write, 343 .on_close = qdh_out_on_close, 344}; 345const struct lsquic_stream_if *const lsquic_qdh_dec_sm_out_if = 346 &qdh_dec_sm_out_if; 347 348 349static lsquic_stream_ctx_t * 350qdh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 351{ 352 struct qpack_dec_hdl *const qdh = stream_if_ctx; 353 qdh->qdh_enc_sm_in = stream; 354 if (qdh->qdh_flags & QDH_INITIALIZED) 355 lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1); 356 LSQ_DEBUG("initialized incoming encoder stream"); 357 return (void *) qdh; 358} 359 360 361static size_t 362qdh_read_encoder_stream (void *ctx, const unsigned char *buf, size_t sz, 363 int fin) 364{ 365 struct qpack_dec_hdl *const qdh = (void *) ctx; 366 const struct lsqpack_dec_err *qerr; 367 int s; 368 369 if (fin) 370 { 371 LSQ_INFO("encoder stream is closed"); 372 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 373 HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK encoder stream"); 374 goto end; 375 } 376 377 s = lsqpack_dec_enc_in(&qdh->qdh_decoder, buf, sz); 378 if (s != 0) 379 { 380 LSQ_INFO("error reading encoder stream"); 381 qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 382 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 383 HEC_QPACK_ENCODER_STREAM_ERROR, "Error interpreting QPACK encoder " 384 "stream; offset %"PRIu64", line %d", qerr->off, qerr->line); 385 goto end; 386 } 387 if (qdh->qdh_dec_sm_out 388 && lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 389 lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 390 391 LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz); 392 393 end: 394 return sz; 395} 396 397 398static void 399qdh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 400{ 401 struct qpack_dec_hdl *const qdh = (void *) ctx; 402 ssize_t nread; 403 404 nread = lsquic_stream_readf(stream, qdh_read_encoder_stream, qdh); 405 if (nread <= 0) 406 { 407 if (nread < 0) 408 { 409 LSQ_WARN("cannot read from encoder stream: %s", strerror(errno)); 410 qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 411 "cannot read from encoder stream"); 412 } 413 else 414 { 415 LSQ_INFO("encoder stream closed by peer: abort connection"); 416 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 417 HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed"); 418 } 419 lsquic_stream_wantread(stream, 0); 420 } 421} 422 423 424static void 425qdh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 426{ 427 struct qpack_dec_hdl *const qdh = (void *) ctx; 428 LSQ_DEBUG("closed incoming encoder stream"); 429 qdh->qdh_enc_sm_in = NULL; 430} 431 432 433static void 434qdh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 435{ 436 assert(0); 437} 438 439 440static const struct lsquic_stream_if qdh_enc_sm_in_if = 441{ 442 .on_new_stream = qdh_in_on_new, 443 .on_read = qdh_in_on_read, 444 .on_write = qdh_in_on_write, 445 .on_close = qdh_in_on_close, 446}; 447const struct lsquic_stream_if *const lsquic_qdh_enc_sm_in_if = 448 &qdh_enc_sm_in_if; 449 450 451static void 452qdh_hblock_unblocked (void *stream_p) 453{ 454 struct lsquic_stream *const stream = stream_p; 455 lsquic_stream_qdec_unblocked(stream); 456} 457 458 459struct cont_len 460{ 461 unsigned long long value; 462 int has; /* 1: set, 0: not set, -1: invalid */ 463}; 464 465 466static void 467process_content_length (const struct qpack_dec_hdl *qdh /* for logging */, 468 struct cont_len *cl, const char *val /* not NUL-terminated */, 469 unsigned len) 470{ 471 char *endcl, cont_len_buf[30]; 472 473 if (0 == cl->has) 474 { 475 if (len >= sizeof(cont_len_buf)) 476 { 477 LSQ_DEBUG("content-length has invalid value `%.*s'", 478 (int) len, val); 479 cl->has = -1; 480 return; 481 } 482 memcpy(cont_len_buf, val, len); 483 cont_len_buf[len] = '\0'; 484 cl->value = strtoull(cont_len_buf, &endcl, 10); 485 if (*endcl == '\0' && !(ULLONG_MAX == cl->value && ERANGE == errno)) 486 { 487 cl->has = 1; 488 LSQ_DEBUG("content length is %llu", cl->value); 489 } 490 else 491 { 492 cl->has = -1; 493 LSQ_DEBUG("content-length has invalid value `%.*s'", 494 (int) len, val); 495 } 496 } 497 else if (cl->has > 0) 498 { 499 LSQ_DEBUG("header set has two content-length: ambiguous, " 500 "turn off checking"); 501 cl->has = -1; 502 } 503} 504 505 506static int 507is_content_length (const struct lsxpack_header *xhdr) 508{ 509 return ((xhdr->flags & LSXPACK_QPACK_IDX) 510 && xhdr->qpack_index == LSQPACK_TNV_CONTENT_LENGTH_0) 511 || (xhdr->name_len == 14 && 0 == memcmp(lsxpack_header_get_name(xhdr), 512 "content-length", 13)) 513 ; 514} 515 516 517static int 518is_priority (const struct lsxpack_header *xhdr) 519{ 520 return xhdr->name_len == 8 521 && 0 == memcmp(lsxpack_header_get_name(xhdr), "priority", 8); 522} 523 524 525static struct lsxpack_header * 526qdh_prepare_decode (void *stream_p, struct lsxpack_header *xhdr, size_t space) 527{ 528 struct lsquic_stream *const stream = stream_p; 529 union hblock_ctx *const u = stream->sm_hblock_ctx; 530 struct qpack_dec_hdl *const qdh = u->ctx.qdh; 531 532 return qdh->qdh_enpub->enp_hsi_if->hsi_prepare_decode( 533 u->ctx.hset, xhdr, space); 534} 535 536 537static void 538qdh_maybe_set_user_agent (struct qpack_dec_hdl *qdh, 539 const struct lsxpack_header *xhdr, char **ua) 540{ 541 /* Flipped: we are the *decoder* */ 542 const char *const name = qdh->qdh_flags & QDH_SERVER ? 543 "user-agent" : "server"; 544 const size_t len = qdh->qdh_flags & QDH_SERVER ? 10 : 6; 545 546 if (len == xhdr->name_len 547 && 0 == memcmp(name, lsxpack_header_get_name(xhdr), len)) 548 *ua = strndup(lsxpack_header_get_value(xhdr), xhdr->val_len); 549} 550 551 552/* Intercept header errors so that upper-layer errors do not get 553 * misinterpreted as QPACK errors. 554 */ 555static int 556qdh_hsi_process_wrapper (struct qpack_dec_hdl *qdh, void *hset, 557 struct lsxpack_header *xhdr) 558{ 559 int retval; 560 561 retval = qdh->qdh_enpub->enp_hsi_if->hsi_process_header(hset, xhdr); 562 if (0 != retval) 563 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 564 HEC_MESSAGE_ERROR, 565 "error processing headers"); 566 567 return retval; 568} 569 570 571static int 572qdh_process_header (void *stream_p, struct lsxpack_header *xhdr) 573{ 574 struct lsquic_stream *const stream = stream_p; 575 union hblock_ctx *const u = stream->sm_hblock_ctx; 576 struct qpack_dec_hdl *const qdh = u->ctx.qdh; 577 struct cont_len cl; 578 579 if (is_content_length(xhdr)) 580 { 581 cl.has = 0; 582 process_content_length(qdh, &cl, lsxpack_header_get_value(xhdr), 583 xhdr->val_len); 584 if (cl.has > 0) 585 (void) lsquic_stream_verify_len(stream, cl.value); 586 } 587 else if ((stream->sm_bflags & (SMBF_HTTP_PRIO|SMBF_HPRIO_SET)) 588 == SMBF_HTTP_PRIO 589 && is_priority(xhdr)) 590 { 591 u->ctx.ppc_flags &= ~(PPC_INC_NAME|PPC_URG_NAME); 592 (void) lsquic_http_parse_pfv(lsxpack_header_get_value(xhdr), 593 xhdr->val_len, &u->ctx.ppc_flags, &u->ctx.ehp, 594 (char *) stream->conn_pub->mm->acki, 595 sizeof(*stream->conn_pub->mm->acki)); 596 } 597 else if (qdh->qdh_exp_rec && !qdh->qdh_exp_rec->qer_user_agent) 598 qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_exp_rec->qer_user_agent); 599 else if ((qdh->qdh_flags & QDH_SAVE_UA) && !qdh->qdh_ua) 600 qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_ua); 601 602 return qdh_hsi_process_wrapper(qdh, u->ctx.hset, xhdr); 603} 604 605 606static const struct lsqpack_dec_hset_if dhi_if = 607{ 608 .dhi_unblocked = qdh_hblock_unblocked, 609 .dhi_prepare_decode = qdh_prepare_decode, 610 .dhi_process_header = qdh_process_header, 611}; 612 613 614static void 615qdh_maybe_destroy_hblock_ctx (struct qpack_dec_hdl *qdh, 616 struct lsquic_stream *stream) 617{ 618 if (stream->sm_hblock_ctx) 619 { 620 LSQ_DEBUG("destroy hblock_ctx of stream %"PRIu64, stream->id); 621 qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set( 622 stream->sm_hblock_ctx->ctx.hset); 623 free(stream->sm_hblock_ctx); 624 stream->sm_hblock_ctx = NULL; 625 } 626} 627 628 629static enum lsqpack_read_header_status 630qdh_header_read_results (struct qpack_dec_hdl *qdh, 631 struct lsquic_stream *stream, enum lsqpack_read_header_status rhs, 632 const unsigned char *dec_buf, size_t dec_buf_sz) 633{ 634 const struct lsqpack_dec_err *qerr; 635 struct uncompressed_headers *uh; 636 void *hset; 637 638 if (rhs == LQRHS_DONE) 639 { 640 if (1) //!lsquic_stream_header_is_trailer(stream)) 641 { 642 if (stream->sm_hblock_ctx->ctx.ppc_flags 643 & (PPC_INC_SET|PPC_URG_SET)) 644 { 645 assert(stream->sm_bflags & SMBF_HTTP_PRIO); 646 LSQ_DEBUG("Apply Priority from headers to stream %"PRIu64, 647 stream->id); 648 (void) lsquic_stream_set_http_prio(stream, 649 &stream->sm_hblock_ctx->ctx.ehp); 650 } 651 hset = stream->sm_hblock_ctx->ctx.hset; 652 uh = (void *) stream->sm_hblock_ctx; 653 stream->sm_hblock_ctx = NULL; 654 memset(uh, 0, sizeof(*uh)); 655 uh->uh_stream_id = stream->id; 656 uh->uh_oth_stream_id = 0; 657 uh->uh_weight = 0; 658 uh->uh_exclusive = -1; 659 if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 660 uh->uh_flags |= UH_H1H; 661 if (0 != qdh_hsi_process_wrapper(qdh, hset, NULL)) 662 { 663 LSQ_DEBUG("finishing hset failed"); 664 free(uh); 665 qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(hset); 666 return LQRHS_ERROR; 667 } 668 uh->uh_hset = hset; 669 if (0 == lsquic_stream_uh_in(stream, uh)) 670 LSQ_DEBUG("gave hset to stream %"PRIu64, stream->id); 671 else 672 { 673 LSQ_DEBUG("could not give hset to stream %"PRIu64, stream->id); 674 free(uh); 675 qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(hset); 676 return LQRHS_ERROR; 677 } 678 } 679 else 680 { 681 LSQ_DEBUG("discard trailer header set"); 682 qdh_maybe_destroy_hblock_ctx(qdh, stream); 683 } 684 if (qdh->qdh_dec_sm_out) 685 { 686 if (dec_buf_sz 687 && 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz)) 688 { 689 return LQRHS_ERROR; 690 } 691 if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 692 lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 693 } 694 } 695 else if (rhs == LQRHS_ERROR) 696 { 697 qdh_maybe_destroy_hblock_ctx(qdh, stream); 698 qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 699 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 700 HEC_QPACK_DECOMPRESSION_FAILED, "QPACK decompression error; " 701 "stream %"PRIu64", offset %"PRIu64", line %d", qerr->stream_id, 702 qerr->off, qerr->line); 703 } 704 705 return rhs; 706} 707 708 709enum lsqpack_read_header_status 710lsquic_qdh_header_in_begin (struct qpack_dec_hdl *qdh, 711 struct lsquic_stream *stream, uint64_t header_size, 712 const unsigned char **buf, size_t bufsz) 713{ 714 enum lsqpack_read_header_status rhs; 715 void *hset; 716 int is_pp; 717 size_t dec_buf_sz; 718 union hblock_ctx *u; 719 unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 720 721 assert(!(stream->stream_flags & STREAM_U_READ_DONE)); 722 723 if (!(qdh->qdh_flags & QDH_INITIALIZED)) 724 { 725 LSQ_WARN("not initialized: cannot process header block"); 726 return LQRHS_ERROR; 727 } 728 729 u = malloc(sizeof(*u)); 730 if (!u) 731 { 732 LSQ_INFO("cannot allocate hblock_ctx"); 733 return LQRHS_ERROR; 734 } 735 736 is_pp = lsquic_stream_header_is_pp(stream); 737 hset = qdh->qdh_enpub->enp_hsi_if->hsi_create_header_set( 738 qdh->qdh_hsi_ctx, stream, is_pp); 739 if (!hset) 740 { 741 free(u); 742 LSQ_DEBUG("hsi_create_header_set failure"); 743 return LQRHS_ERROR; 744 } 745 746 u->ctx.hset = hset; 747 u->ctx.qdh = qdh; 748 u->ctx.ppc_flags = 0; 749 u->ctx.ehp = (struct lsquic_ext_http_prio) { 750 .urgency = LSQUIC_DEF_HTTP_URGENCY, 751 .incremental = LSQUIC_DEF_HTTP_INCREMENTAL, 752 }; 753 stream->sm_hblock_ctx = u; 754 755 if (qdh->qdh_exp_rec) 756 { 757 const lsquic_time_t now = lsquic_time_now(); 758 if (0 == qdh->qdh_exp_rec->qer_hblock_count) 759 qdh->qdh_exp_rec->qer_first_req = now; 760 qdh->qdh_exp_rec->qer_last_req = now; 761 ++qdh->qdh_exp_rec->qer_hblock_count; 762 qdh->qdh_exp_rec->qer_hblock_size += bufsz; 763 } 764 765 dec_buf_sz = sizeof(dec_buf); 766 rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id, 767 header_size, buf, bufsz, dec_buf, &dec_buf_sz); 768 if (qdh->qdh_exp_rec) 769 qdh->qdh_exp_rec->qer_peer_max_blocked += rhs == LQRHS_BLOCKED; 770 return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 771} 772 773 774enum lsqpack_read_header_status 775lsquic_qdh_header_in_continue (struct qpack_dec_hdl *qdh, 776 struct lsquic_stream *stream, const unsigned char **buf, size_t bufsz) 777{ 778 enum lsqpack_read_header_status rhs; 779 size_t dec_buf_sz; 780 unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 781 782 assert(!(stream->stream_flags & STREAM_U_READ_DONE)); 783 784 if (qdh->qdh_flags & QDH_INITIALIZED) 785 { 786 if (qdh->qdh_exp_rec) 787 qdh->qdh_exp_rec->qer_hblock_size += bufsz; 788 dec_buf_sz = sizeof(dec_buf); 789 rhs = lsqpack_dec_header_read(&qdh->qdh_decoder, stream, 790 buf, bufsz, dec_buf, &dec_buf_sz); 791 if (qdh->qdh_exp_rec) 792 qdh->qdh_exp_rec->qer_peer_max_blocked += rhs == LQRHS_BLOCKED; 793 return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 794 } 795 else 796 { 797 LSQ_WARN("not initialized: cannot process header block"); 798 return LQRHS_ERROR; 799 } 800} 801 802 803static void 804lsquic_qdh_unref_stream (struct qpack_dec_hdl *qdh, 805 struct lsquic_stream *stream) 806{ 807 if (0 == lsqpack_dec_unref_stream(&qdh->qdh_decoder, stream)) 808 LSQ_DEBUG("unreffed stream %"PRIu64, stream->id); 809 else 810 LSQ_WARN("cannot unref stream %"PRIu64, stream->id); 811} 812 813 814void 815lsquic_qdh_cancel_stream (struct qpack_dec_hdl *qdh, 816 struct lsquic_stream *stream) 817{ 818 ssize_t nw; 819 unsigned char buf[LSQPACK_LONGEST_CANCEL]; 820 821 qdh_maybe_destroy_hblock_ctx(qdh, stream); 822 823 if (!qdh->qdh_dec_sm_out) 824 return; 825 826 nw = lsqpack_dec_cancel_stream(&qdh->qdh_decoder, stream, buf, sizeof(buf)); 827 if (nw > 0) 828 { 829 if (0 == qdh_write_decoder(qdh, buf, nw)) 830 LSQ_DEBUG("cancelled stream %"PRIu64" and wrote %zd-byte Cancel " 831 "Stream instruction to the decoder stream", stream->id, nw); 832 } 833 else if (nw == 0) 834 LSQ_WARN("cannot cancel stream %"PRIu64" -- not found", stream->id); 835 else 836 { 837 LSQ_WARN("cannot cancel stream %"PRIu64" -- not enough buffer space " 838 "to encode Cancel Stream instructin", stream->id); 839 lsquic_qdh_unref_stream(qdh, stream); 840 } 841} 842 843 844void 845lsquic_qdh_cancel_stream_id (struct qpack_dec_hdl *qdh, 846 lsquic_stream_id_t stream_id) 847{ 848 ssize_t nw; 849 unsigned char buf[LSQPACK_LONGEST_CANCEL]; 850 851 if (!qdh->qdh_dec_sm_out) 852 return; 853 854 nw = lsqpack_dec_cancel_stream_id(&qdh->qdh_decoder, stream_id, buf, 855 sizeof(buf)); 856 if (nw > 0) 857 { 858 if (0 == qdh_write_decoder(qdh, buf, nw)) 859 LSQ_DEBUG("wrote %zd-byte Cancel Stream instruction for " 860 "stream %"PRIu64" to the decoder stream", nw, stream_id); 861 } 862 else if (nw == 0) 863 LSQ_DEBUG("not generating Cancel Stream instruction for " 864 "stream %"PRIu64, stream_id); 865 else 866 LSQ_WARN("cannot generate Cancel Stream instruction for " 867 "stream %"PRIu64" -- not enough buffer space", stream_id); 868} 869 870 871int 872lsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *qdh, void (*func)(void *), 873 void *ctx) 874{ 875 size_t bytes; 876 877 /* Use size of a single frab list buffer as an arbitrary threshold */ 878 bytes = lsquic_frab_list_size(&qdh->qdh_fral); 879 if (bytes <= qdh->qdh_fral.fl_buf_size) 880 return 0; 881 else 882 { 883 LSQ_DEBUG("have %zu bytes of unsent QPACK decoder stream data: set " 884 "up callback", bytes); 885 qdh->qdh_on_dec_sent_func = func; 886 qdh->qdh_on_dec_sent_ctx = ctx; 887 return 1; 888 } 889} 890 891 892const char * 893lsquic_qdh_get_ua (const struct qpack_dec_hdl *qdh) 894{ 895 if (qdh->qdh_ua) 896 return qdh->qdh_ua; 897 else if (qdh->qdh_exp_rec && qdh->qdh_exp_rec->qer_user_agent) 898 return qdh->qdh_exp_rec->qer_user_agent; 899 else 900 return NULL; 901} 902