lsquic_qdec_hdl.c revision 293df8d6
1/* Copyright (c) 2017 - 2021 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 union hblock_ctx *const u = stream->sm_hblock_ctx; 456 struct qpack_dec_hdl *qdh = u->ctx.qdh; 457 458 LSQ_DEBUG("header block for stream %"PRIu64" unblocked", stream->id); 459 lsquic_stream_qdec_unblocked(stream); 460} 461 462 463struct cont_len 464{ 465 unsigned long long value; 466 int has; /* 1: set, 0: not set, -1: invalid */ 467}; 468 469 470static void 471process_content_length (const struct qpack_dec_hdl *qdh /* for logging */, 472 struct cont_len *cl, const char *val /* not NUL-terminated */, 473 unsigned len) 474{ 475 char *endcl, cont_len_buf[30]; 476 477 if (0 == cl->has) 478 { 479 if (len >= sizeof(cont_len_buf)) 480 { 481 LSQ_DEBUG("content-length has invalid value `%.*s'", 482 (int) len, val); 483 cl->has = -1; 484 return; 485 } 486 memcpy(cont_len_buf, val, len); 487 cont_len_buf[len] = '\0'; 488 cl->value = strtoull(cont_len_buf, &endcl, 10); 489 if (*endcl == '\0' && !(ULLONG_MAX == cl->value && ERANGE == errno)) 490 { 491 cl->has = 1; 492 LSQ_DEBUG("content length is %llu", cl->value); 493 } 494 else 495 { 496 cl->has = -1; 497 LSQ_DEBUG("content-length has invalid value `%.*s'", 498 (int) len, val); 499 } 500 } 501 else if (cl->has > 0) 502 { 503 LSQ_DEBUG("header set has two content-length: ambiguous, " 504 "turn off checking"); 505 cl->has = -1; 506 } 507} 508 509 510static int 511is_content_length (const struct lsxpack_header *xhdr) 512{ 513 return ((xhdr->flags & LSXPACK_QPACK_IDX) 514 && xhdr->qpack_index == LSQPACK_TNV_CONTENT_LENGTH_0) 515 || (xhdr->name_len == 14 && 0 == memcmp(lsxpack_header_get_name(xhdr), 516 "content-length", 13)) 517 ; 518} 519 520 521static int 522is_priority (const struct lsxpack_header *xhdr) 523{ 524 return xhdr->name_len == 8 525 && 0 == memcmp(lsxpack_header_get_name(xhdr), "priority", 8); 526} 527 528 529static struct lsxpack_header * 530qdh_prepare_decode (void *stream_p, struct lsxpack_header *xhdr, size_t space) 531{ 532 struct lsquic_stream *const stream = stream_p; 533 union hblock_ctx *const u = stream->sm_hblock_ctx; 534 struct qpack_dec_hdl *const qdh = u->ctx.qdh; 535 536 return qdh->qdh_enpub->enp_hsi_if->hsi_prepare_decode( 537 u->ctx.hset, xhdr, space); 538} 539 540 541static void 542qdh_maybe_set_user_agent (struct qpack_dec_hdl *qdh, 543 const struct lsxpack_header *xhdr, char **ua) 544{ 545 /* Flipped: we are the *decoder* */ 546 const char *const name = qdh->qdh_flags & QDH_SERVER ? 547 "user-agent" : "server"; 548 const size_t len = qdh->qdh_flags & QDH_SERVER ? 10 : 6; 549 550 if (len == xhdr->name_len 551 && 0 == memcmp(name, lsxpack_header_get_name(xhdr), len)) 552 *ua = strndup(lsxpack_header_get_value(xhdr), xhdr->val_len); 553} 554 555 556/* Intercept header errors so that upper-layer errors do not get 557 * misinterpreted as QPACK errors. 558 */ 559static int 560qdh_hsi_process_wrapper (struct qpack_dec_hdl *qdh, void *hset, 561 struct lsxpack_header *xhdr) 562{ 563 int retval; 564 565 retval = qdh->qdh_enpub->enp_hsi_if->hsi_process_header(hset, xhdr); 566 if (0 != retval) 567 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 568 1 == retval ? HEC_MESSAGE_ERROR : HEC_INTERNAL_ERROR, 569 "error processing headers"); 570 571 return retval; 572} 573 574 575static int 576qdh_process_header (void *stream_p, struct lsxpack_header *xhdr) 577{ 578 struct lsquic_stream *const stream = stream_p; 579 union hblock_ctx *const u = stream->sm_hblock_ctx; 580 struct qpack_dec_hdl *const qdh = u->ctx.qdh; 581 struct cont_len cl; 582 583 if (is_content_length(xhdr)) 584 { 585 cl.has = 0; 586 process_content_length(qdh, &cl, lsxpack_header_get_value(xhdr), 587 xhdr->val_len); 588 if (cl.has > 0) 589 (void) lsquic_stream_verify_len(stream, cl.value); 590 } 591 else if ((stream->sm_bflags & (SMBF_HTTP_PRIO|SMBF_HPRIO_SET)) 592 == SMBF_HTTP_PRIO 593 && is_priority(xhdr)) 594 { 595 u->ctx.ppc_flags &= ~(PPC_INC_NAME|PPC_URG_NAME); 596 (void) lsquic_http_parse_pfv(lsxpack_header_get_value(xhdr), 597 xhdr->val_len, &u->ctx.ppc_flags, &u->ctx.ehp, 598 (char *) stream->conn_pub->mm->acki, 599 sizeof(*stream->conn_pub->mm->acki)); 600 } 601 else if (qdh->qdh_exp_rec && !qdh->qdh_exp_rec->qer_user_agent) 602 qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_exp_rec->qer_user_agent); 603 else if ((qdh->qdh_flags & QDH_SAVE_UA) && !qdh->qdh_ua) 604 qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_ua); 605 606 return qdh_hsi_process_wrapper(qdh, u->ctx.hset, xhdr); 607} 608 609 610static const struct lsqpack_dec_hset_if dhi_if = 611{ 612 .dhi_unblocked = qdh_hblock_unblocked, 613 .dhi_prepare_decode = qdh_prepare_decode, 614 .dhi_process_header = qdh_process_header, 615}; 616 617 618static void 619qdh_maybe_destroy_hblock_ctx (struct qpack_dec_hdl *qdh, 620 struct lsquic_stream *stream) 621{ 622 if (stream->sm_hblock_ctx) 623 { 624 LSQ_DEBUG("destroy hblock_ctx of stream %"PRIu64, stream->id); 625 qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set( 626 stream->sm_hblock_ctx->ctx.hset); 627 free(stream->sm_hblock_ctx); 628 stream->sm_hblock_ctx = NULL; 629 } 630} 631 632 633static enum lsqpack_read_header_status 634qdh_header_read_results (struct qpack_dec_hdl *qdh, 635 struct lsquic_stream *stream, enum lsqpack_read_header_status rhs, 636 const unsigned char *dec_buf, size_t dec_buf_sz) 637{ 638 const struct lsqpack_dec_err *qerr; 639 struct uncompressed_headers *uh; 640 void *hset; 641 642 if (rhs == LQRHS_DONE) 643 { 644 if (1) //!lsquic_stream_header_is_trailer(stream)) 645 { 646 if (stream->sm_hblock_ctx->ctx.ppc_flags 647 & (PPC_INC_SET|PPC_URG_SET)) 648 { 649 assert(stream->sm_bflags & SMBF_HTTP_PRIO); 650 LSQ_DEBUG("Apply Priority from headers to stream %"PRIu64, 651 stream->id); 652 (void) lsquic_stream_set_http_prio(stream, 653 &stream->sm_hblock_ctx->ctx.ehp); 654 } 655 hset = stream->sm_hblock_ctx->ctx.hset; 656 uh = (void *) stream->sm_hblock_ctx; 657 stream->sm_hblock_ctx = NULL; 658 memset(uh, 0, sizeof(*uh)); 659 uh->uh_stream_id = stream->id; 660 uh->uh_oth_stream_id = 0; 661 uh->uh_weight = 0; 662 uh->uh_exclusive = -1; 663 if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 664 uh->uh_flags |= UH_H1H; 665 if (0 != qdh_hsi_process_wrapper(qdh, hset, NULL)) 666 { 667 LSQ_DEBUG("finishing hset failed"); 668 free(uh); 669 qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(hset); 670 return LQRHS_ERROR; 671 } 672 uh->uh_hset = hset; 673 if (0 == lsquic_stream_uh_in(stream, uh)) 674 LSQ_DEBUG("gave hset to stream %"PRIu64, stream->id); 675 else 676 { 677 LSQ_DEBUG("could not give hset to stream %"PRIu64, stream->id); 678 free(uh); 679 qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(hset); 680 return LQRHS_ERROR; 681 } 682 } 683 else 684 { 685 LSQ_DEBUG("discard trailer header set"); 686 qdh_maybe_destroy_hblock_ctx(qdh, stream); 687 } 688 if (qdh->qdh_dec_sm_out) 689 { 690 if (dec_buf_sz 691 && 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz)) 692 { 693 return LQRHS_ERROR; 694 } 695 if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 696 lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 697 } 698 } 699 else if (rhs == LQRHS_ERROR) 700 { 701 qdh_maybe_destroy_hblock_ctx(qdh, stream); 702 qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 703 qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 704 HEC_QPACK_DECOMPRESSION_FAILED, "QPACK decompression error; " 705 "stream %"PRIu64", offset %"PRIu64", line %d", qerr->stream_id, 706 qerr->off, qerr->line); 707 } 708 709 return rhs; 710} 711 712 713enum lsqpack_read_header_status 714lsquic_qdh_header_in_begin (struct qpack_dec_hdl *qdh, 715 struct lsquic_stream *stream, uint64_t header_size, 716 const unsigned char **buf, size_t bufsz) 717{ 718 enum lsqpack_read_header_status rhs; 719 void *hset; 720 int is_pp; 721 size_t dec_buf_sz; 722 union hblock_ctx *u; 723 unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 724 725 assert(!(stream->stream_flags & STREAM_U_READ_DONE)); 726 727 if (!(qdh->qdh_flags & QDH_INITIALIZED)) 728 { 729 LSQ_WARN("not initialized: cannot process header block"); 730 return LQRHS_ERROR; 731 } 732 733 u = malloc(sizeof(*u)); 734 if (!u) 735 { 736 LSQ_INFO("cannot allocate hblock_ctx"); 737 return LQRHS_ERROR; 738 } 739 740 is_pp = lsquic_stream_header_is_pp(stream); 741 hset = qdh->qdh_enpub->enp_hsi_if->hsi_create_header_set( 742 qdh->qdh_hsi_ctx, stream, is_pp); 743 if (!hset) 744 { 745 free(u); 746 LSQ_DEBUG("hsi_create_header_set failure"); 747 return LQRHS_ERROR; 748 } 749 750 u->ctx.hset = hset; 751 u->ctx.qdh = qdh; 752 u->ctx.ppc_flags = 0; 753 u->ctx.ehp = (struct lsquic_ext_http_prio) { 754 .urgency = LSQUIC_DEF_HTTP_URGENCY, 755 .incremental = LSQUIC_DEF_HTTP_INCREMENTAL, 756 }; 757 stream->sm_hblock_ctx = u; 758 759 if (qdh->qdh_exp_rec) 760 { 761 const lsquic_time_t now = lsquic_time_now(); 762 if (0 == qdh->qdh_exp_rec->qer_hblock_count) 763 qdh->qdh_exp_rec->qer_first_req = now; 764 qdh->qdh_exp_rec->qer_last_req = now; 765 ++qdh->qdh_exp_rec->qer_hblock_count; 766 qdh->qdh_exp_rec->qer_hblock_size += bufsz; 767 } 768 769 dec_buf_sz = sizeof(dec_buf); 770 rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id, 771 header_size, buf, bufsz, dec_buf, &dec_buf_sz); 772 if (qdh->qdh_exp_rec) 773 qdh->qdh_exp_rec->qer_peer_max_blocked += rhs == LQRHS_BLOCKED; 774 return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 775} 776 777 778enum lsqpack_read_header_status 779lsquic_qdh_header_in_continue (struct qpack_dec_hdl *qdh, 780 struct lsquic_stream *stream, const unsigned char **buf, size_t bufsz) 781{ 782 enum lsqpack_read_header_status rhs; 783 size_t dec_buf_sz; 784 unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 785 786 assert(!(stream->stream_flags & STREAM_U_READ_DONE)); 787 788 if (qdh->qdh_flags & QDH_INITIALIZED) 789 { 790 if (qdh->qdh_exp_rec) 791 qdh->qdh_exp_rec->qer_hblock_size += bufsz; 792 dec_buf_sz = sizeof(dec_buf); 793 rhs = lsqpack_dec_header_read(&qdh->qdh_decoder, stream, 794 buf, bufsz, dec_buf, &dec_buf_sz); 795 if (qdh->qdh_exp_rec) 796 qdh->qdh_exp_rec->qer_peer_max_blocked += rhs == LQRHS_BLOCKED; 797 return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 798 } 799 else 800 { 801 LSQ_WARN("not initialized: cannot process header block"); 802 return LQRHS_ERROR; 803 } 804} 805 806 807static void 808lsquic_qdh_unref_stream (struct qpack_dec_hdl *qdh, 809 struct lsquic_stream *stream) 810{ 811 if (0 == lsqpack_dec_unref_stream(&qdh->qdh_decoder, stream)) 812 LSQ_DEBUG("unreffed stream %"PRIu64, stream->id); 813 else 814 LSQ_WARN("cannot unref stream %"PRIu64, stream->id); 815} 816 817 818void 819lsquic_qdh_cancel_stream (struct qpack_dec_hdl *qdh, 820 struct lsquic_stream *stream) 821{ 822 ssize_t nw; 823 unsigned char buf[LSQPACK_LONGEST_CANCEL]; 824 825 qdh_maybe_destroy_hblock_ctx(qdh, stream); 826 827 if (!qdh->qdh_dec_sm_out) 828 return; 829 830 nw = lsqpack_dec_cancel_stream(&qdh->qdh_decoder, stream, buf, sizeof(buf)); 831 if (nw > 0) 832 { 833 if (0 == qdh_write_decoder(qdh, buf, nw)) 834 LSQ_DEBUG("cancelled stream %"PRIu64" and wrote %zd-byte Cancel " 835 "Stream instruction to the decoder stream", stream->id, nw); 836 } 837 else if (nw == 0) 838 LSQ_WARN("cannot cancel stream %"PRIu64" -- not found", stream->id); 839 else 840 { 841 LSQ_WARN("cannot cancel stream %"PRIu64" -- not enough buffer space " 842 "to encode Cancel Stream instructin", stream->id); 843 lsquic_qdh_unref_stream(qdh, stream); 844 } 845} 846 847 848void 849lsquic_qdh_cancel_stream_id (struct qpack_dec_hdl *qdh, 850 lsquic_stream_id_t stream_id) 851{ 852 ssize_t nw; 853 unsigned char buf[LSQPACK_LONGEST_CANCEL]; 854 855 if (!qdh->qdh_dec_sm_out) 856 return; 857 858 nw = lsqpack_dec_cancel_stream_id(&qdh->qdh_decoder, stream_id, buf, 859 sizeof(buf)); 860 if (nw > 0) 861 { 862 if (0 == qdh_write_decoder(qdh, buf, nw)) 863 LSQ_DEBUG("wrote %zd-byte Cancel Stream instruction for " 864 "stream %"PRIu64" to the decoder stream", nw, stream_id); 865 } 866 else if (nw == 0) 867 LSQ_DEBUG("not generating Cancel Stream instruction for " 868 "stream %"PRIu64, stream_id); 869 else 870 LSQ_WARN("cannot generate Cancel Stream instruction for " 871 "stream %"PRIu64" -- not enough buffer space", stream_id); 872} 873 874 875int 876lsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *qdh, void (*func)(void *), 877 void *ctx) 878{ 879 size_t bytes; 880 881 /* Use size of a single frab list buffer as an arbitrary threshold */ 882 bytes = lsquic_frab_list_size(&qdh->qdh_fral); 883 if (bytes <= qdh->qdh_fral.fl_buf_size) 884 return 0; 885 else 886 { 887 LSQ_DEBUG("have %zu bytes of unsent QPACK decoder stream data: set " 888 "up callback", bytes); 889 qdh->qdh_on_dec_sent_func = func; 890 qdh->qdh_on_dec_sent_ctx = ctx; 891 return 1; 892 } 893} 894 895 896const char * 897lsquic_qdh_get_ua (const struct qpack_dec_hdl *qdh) 898{ 899 if (qdh->qdh_ua) 900 return qdh->qdh_ua; 901 else if (qdh->qdh_exp_rec && qdh->qdh_exp_rec->qer_user_agent) 902 return qdh->qdh_exp_rec->qer_user_agent; 903 else 904 return NULL; 905} 906