1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 25392f7a3SLiteSpeed Tech/* 35392f7a3SLiteSpeed Tech * lsquic_qdec_hdl.c -- QPACK decoder streams handler 45392f7a3SLiteSpeed Tech */ 55392f7a3SLiteSpeed Tech 65392f7a3SLiteSpeed Tech#include <assert.h> 75392f7a3SLiteSpeed Tech#include <errno.h> 85392f7a3SLiteSpeed Tech#include <inttypes.h> 95392f7a3SLiteSpeed Tech#include <stdlib.h> 105392f7a3SLiteSpeed Tech#include <string.h> 115392f7a3SLiteSpeed Tech#include <sys/queue.h> 125392f7a3SLiteSpeed Tech 135392f7a3SLiteSpeed Tech#include "lsquic.h" 145392f7a3SLiteSpeed Tech#include "lsquic_types.h" 15a5fa05f9SDmitri Tikhonov#include "lsxpack_header.h" 165392f7a3SLiteSpeed Tech#include "lsquic_int_types.h" 175392f7a3SLiteSpeed Tech#include "lsquic_sfcw.h" 185392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 195392f7a3SLiteSpeed Tech#include "lsquic_hq.h" 205392f7a3SLiteSpeed Tech#include "lsquic_hash.h" 215392f7a3SLiteSpeed Tech#include "lsquic_stream.h" 225392f7a3SLiteSpeed Tech#include "lsquic_frab_list.h" 235392f7a3SLiteSpeed Tech#include "lsqpack.h" 245392f7a3SLiteSpeed Tech#include "lsquic_http1x_if.h" 255392f7a3SLiteSpeed Tech#include "lsquic_qdec_hdl.h" 265392f7a3SLiteSpeed Tech#include "lsquic_mm.h" 275392f7a3SLiteSpeed Tech#include "lsquic_engine_public.h" 285392f7a3SLiteSpeed Tech#include "lsquic_headers.h" 295392f7a3SLiteSpeed Tech#include "lsquic_conn.h" 30fbc6cc04SDmitri Tikhonov#include "lsquic_conn_flow.h" 31fbc6cc04SDmitri Tikhonov#include "lsquic_rtt.h" 32fbc6cc04SDmitri Tikhonov#include "lsquic_conn_public.h" 33fbc6cc04SDmitri Tikhonov#include "lsquic_hq.h" 34fbc6cc04SDmitri Tikhonov#include "lsquic_parse.h" 35758aff32SDmitri Tikhonov#include "lsquic_qpack_exp.h" 36758aff32SDmitri Tikhonov#include "lsquic_util.h" 375392f7a3SLiteSpeed Tech 385392f7a3SLiteSpeed Tech#define LSQUIC_LOGGER_MODULE LSQLM_QDEC_HDL 395392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(qdh->qdh_conn) 405392f7a3SLiteSpeed Tech#include "lsquic_logger.h" 415392f7a3SLiteSpeed Tech 4255613f44SDmitri Tikhonovstatic const struct lsqpack_dec_hset_if dhi_if; 4355613f44SDmitri Tikhonov 4455613f44SDmitri Tikhonov 4555613f44SDmitri Tikhonovstruct header_ctx 4655613f44SDmitri Tikhonov{ 4755613f44SDmitri Tikhonov void *hset; 4855613f44SDmitri Tikhonov struct qpack_dec_hdl *qdh; 49fbc6cc04SDmitri Tikhonov enum ppc_flags ppc_flags; 50fbc6cc04SDmitri Tikhonov struct lsquic_ext_http_prio ehp; 5155613f44SDmitri Tikhonov}; 5255613f44SDmitri Tikhonov 5355613f44SDmitri Tikhonov 5455613f44SDmitri Tikhonov/* We need to allocate struct uncompressed_headers anyway when header set 5555613f44SDmitri Tikhonov * is complete and we give it to the stream using lsquic_stream_uh_in(). 5655613f44SDmitri Tikhonov * To save a malloc, we reuse context after we're done with it. 5755613f44SDmitri Tikhonov */ 5855613f44SDmitri Tikhonovunion hblock_ctx 5955613f44SDmitri Tikhonov{ 604580fab7SDmitri Tikhonov struct header_ctx ctx; 614580fab7SDmitri Tikhonov unsigned char space_for_uh[sizeof(struct uncompressed_headers)]; 6255613f44SDmitri Tikhonov}; 635392f7a3SLiteSpeed Tech 645392f7a3SLiteSpeed Tech 655392f7a3SLiteSpeed Techstatic int 665392f7a3SLiteSpeed Techqdh_write_decoder (struct qpack_dec_hdl *qdh, const unsigned char *buf, 675392f7a3SLiteSpeed Tech size_t sz) 685392f7a3SLiteSpeed Tech{ 695392f7a3SLiteSpeed Tech ssize_t nw; 705392f7a3SLiteSpeed Tech 715392f7a3SLiteSpeed Tech if (!(qdh->qdh_dec_sm_out && lsquic_frab_list_empty(&qdh->qdh_fral))) 725392f7a3SLiteSpeed Tech { 735392f7a3SLiteSpeed Tech write_to_frab: 745392f7a3SLiteSpeed Tech if (0 == lsquic_frab_list_write(&qdh->qdh_fral, 755392f7a3SLiteSpeed Tech (unsigned char *) buf, sz)) 765392f7a3SLiteSpeed Tech { 775392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zu bytes to frab list", sz); 785392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 795392f7a3SLiteSpeed Tech return 0; 805392f7a3SLiteSpeed Tech } 815392f7a3SLiteSpeed Tech else 825392f7a3SLiteSpeed Tech { 835392f7a3SLiteSpeed Tech LSQ_INFO("error writing to frab list"); 845392f7a3SLiteSpeed Tech return -1; 855392f7a3SLiteSpeed Tech } 865392f7a3SLiteSpeed Tech } 875392f7a3SLiteSpeed Tech 885392f7a3SLiteSpeed Tech nw = lsquic_stream_write(qdh->qdh_dec_sm_out, buf, sz); 895392f7a3SLiteSpeed Tech if (nw < 0) 905392f7a3SLiteSpeed Tech { 915392f7a3SLiteSpeed Tech LSQ_INFO("error writing to outgoing QPACK decoder stream: %s", 925392f7a3SLiteSpeed Tech strerror(errno)); 935392f7a3SLiteSpeed Tech return -1; 945392f7a3SLiteSpeed Tech } 955392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zd bytes to outgoing QPACK decoder stream", nw); 965392f7a3SLiteSpeed Tech 975392f7a3SLiteSpeed Tech if ((size_t) nw == sz) 985392f7a3SLiteSpeed Tech return 0; 995392f7a3SLiteSpeed Tech 1005392f7a3SLiteSpeed Tech buf = buf + nw; 1015392f7a3SLiteSpeed Tech sz -= (size_t) nw; 1025392f7a3SLiteSpeed Tech goto write_to_frab; 1035392f7a3SLiteSpeed Tech} 1045392f7a3SLiteSpeed Tech 1055392f7a3SLiteSpeed Tech 1065392f7a3SLiteSpeed Techstatic int 1075392f7a3SLiteSpeed Techqdh_write_type (struct qpack_dec_hdl *qdh) 1085392f7a3SLiteSpeed Tech{ 1095392f7a3SLiteSpeed Tech int s; 1105392f7a3SLiteSpeed Tech 1115392f7a3SLiteSpeed Tech#ifndef NDEBUG 1125392f7a3SLiteSpeed Tech const char *env = getenv("LSQUIC_RND_VARINT_LEN"); 1135392f7a3SLiteSpeed Tech if (env && atoi(env)) 1145392f7a3SLiteSpeed Tech { 1155392f7a3SLiteSpeed Tech s = rand() & 3; 1165392f7a3SLiteSpeed Tech LSQ_DEBUG("writing %d-byte stream type", 1 << s); 1175392f7a3SLiteSpeed Tech } 1185392f7a3SLiteSpeed Tech else 1195392f7a3SLiteSpeed Tech#endif 1205392f7a3SLiteSpeed Tech s = 0; 1215392f7a3SLiteSpeed Tech 1225392f7a3SLiteSpeed Tech switch (s) 1235392f7a3SLiteSpeed Tech { 1245392f7a3SLiteSpeed Tech case 0: 1255392f7a3SLiteSpeed Tech return qdh_write_decoder(qdh, 1265392f7a3SLiteSpeed Tech (unsigned char []) { HQUST_QPACK_DEC }, 1); 1275392f7a3SLiteSpeed Tech case 1: 1285392f7a3SLiteSpeed Tech return qdh_write_decoder(qdh, 1295392f7a3SLiteSpeed Tech (unsigned char []) { 0x40, HQUST_QPACK_DEC }, 2); 1305392f7a3SLiteSpeed Tech case 2: 1315392f7a3SLiteSpeed Tech return qdh_write_decoder(qdh, 1325392f7a3SLiteSpeed Tech (unsigned char []) { 0x80, 0x00, 0x00, HQUST_QPACK_DEC }, 4); 1335392f7a3SLiteSpeed Tech default: 1345392f7a3SLiteSpeed Tech return qdh_write_decoder(qdh, 1355392f7a3SLiteSpeed Tech (unsigned char []) { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 1365392f7a3SLiteSpeed Tech HQUST_QPACK_DEC }, 8); 1375392f7a3SLiteSpeed Tech } 1385392f7a3SLiteSpeed Tech} 1395392f7a3SLiteSpeed Tech 1405392f7a3SLiteSpeed Tech 1415392f7a3SLiteSpeed Techstatic void 1425392f7a3SLiteSpeed Techqdh_begin_out (struct qpack_dec_hdl *qdh) 1435392f7a3SLiteSpeed Tech{ 1445392f7a3SLiteSpeed Tech if (0 != qdh_write_type(qdh)) 1455392f7a3SLiteSpeed Tech { 1465392f7a3SLiteSpeed Tech LSQ_WARN("%s: could not write to decoder", __func__); 1475392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 1485392f7a3SLiteSpeed Tech "cannot write to decoder stream"); 1495392f7a3SLiteSpeed Tech } 1505392f7a3SLiteSpeed Tech} 1515392f7a3SLiteSpeed Tech 1525392f7a3SLiteSpeed Tech 1535392f7a3SLiteSpeed Techint 1545392f7a3SLiteSpeed Techlsquic_qdh_init (struct qpack_dec_hdl *qdh, struct lsquic_conn *conn, 1555392f7a3SLiteSpeed Tech int is_server, const struct lsquic_engine_public *enpub, 1565392f7a3SLiteSpeed Tech unsigned dyn_table_size, unsigned max_risked_streams) 1575392f7a3SLiteSpeed Tech{ 15855613f44SDmitri Tikhonov enum lsqpack_dec_opts dec_opts; 15955613f44SDmitri Tikhonov 16055613f44SDmitri Tikhonov dec_opts = 0; 16155613f44SDmitri Tikhonov if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HTTP1X) 16255613f44SDmitri Tikhonov dec_opts |= LSQPACK_DEC_OPT_HTTP1X; 16355613f44SDmitri Tikhonov if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAME) 16455613f44SDmitri Tikhonov dec_opts |= LSQPACK_DEC_OPT_HASH_NAME; 16555613f44SDmitri Tikhonov if (enpub->enp_hsi_if->hsi_flags & LSQUIC_HSI_HASH_NAMEVAL) 16655613f44SDmitri Tikhonov dec_opts |= LSQPACK_DEC_OPT_HASH_NAMEVAL; 16755613f44SDmitri Tikhonov 1684429f8eaSDmitri Tikhonov if (conn->cn_flags & LSCONN_SERVER) 1694429f8eaSDmitri Tikhonov qdh->qdh_flags |= QDH_SERVER; 170758aff32SDmitri Tikhonov if (enpub->enp_settings.es_qpack_experiment) 171758aff32SDmitri Tikhonov { 172758aff32SDmitri Tikhonov qdh->qdh_exp_rec = lsquic_qpack_exp_new(); 173758aff32SDmitri Tikhonov if (qdh->qdh_exp_rec) 174758aff32SDmitri Tikhonov { 175758aff32SDmitri Tikhonov if (conn->cn_flags & LSCONN_SERVER) 176758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_flags |= QER_SERVER; 177758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_used_max_size = dyn_table_size; 178758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_used_max_blocked = max_risked_streams; 179758aff32SDmitri Tikhonov } 180758aff32SDmitri Tikhonov } 1814429f8eaSDmitri Tikhonov if (!qdh->qdh_exp_rec && LSQ_LOG_ENABLED_EXT(LSQ_LOG_NOTICE, LSQLM_CONN)) 1824429f8eaSDmitri Tikhonov qdh->qdh_flags |= QDH_SAVE_UA; 183758aff32SDmitri Tikhonov 1845392f7a3SLiteSpeed Tech qdh->qdh_conn = conn; 1855392f7a3SLiteSpeed Tech lsquic_frab_list_init(&qdh->qdh_fral, 0x400, NULL, NULL, NULL); 1865392f7a3SLiteSpeed Tech lsqpack_dec_init(&qdh->qdh_decoder, (void *) conn, dyn_table_size, 18755613f44SDmitri Tikhonov max_risked_streams, &dhi_if, dec_opts); 1885392f7a3SLiteSpeed Tech qdh->qdh_flags |= QDH_INITIALIZED; 1895392f7a3SLiteSpeed Tech qdh->qdh_enpub = enpub; 1905392f7a3SLiteSpeed Tech if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 1915392f7a3SLiteSpeed Tech { 1925392f7a3SLiteSpeed Tech qdh->qdh_h1x_ctor_ctx = (struct http1x_ctor_ctx) { 1935392f7a3SLiteSpeed Tech .conn = conn, 194a4f5dac3SDmitri Tikhonov .max_headers_sz = MAX_HTTP1X_HEADERS_SIZE, 1955392f7a3SLiteSpeed Tech .is_server = is_server, 1965392f7a3SLiteSpeed Tech }; 1975392f7a3SLiteSpeed Tech qdh->qdh_hsi_ctx = &qdh->qdh_h1x_ctor_ctx; 1985392f7a3SLiteSpeed Tech } 1995392f7a3SLiteSpeed Tech else 2005392f7a3SLiteSpeed Tech qdh->qdh_hsi_ctx = qdh->qdh_enpub->enp_hsi_ctx; 2015392f7a3SLiteSpeed Tech if (qdh->qdh_dec_sm_out) 2025392f7a3SLiteSpeed Tech qdh_begin_out(qdh); 2035392f7a3SLiteSpeed Tech if (qdh->qdh_enc_sm_in) 2045392f7a3SLiteSpeed Tech lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1); 2055392f7a3SLiteSpeed Tech LSQ_DEBUG("initialized"); 2065392f7a3SLiteSpeed Tech return 0; 2075392f7a3SLiteSpeed Tech} 2085392f7a3SLiteSpeed Tech 2095392f7a3SLiteSpeed Tech 210758aff32SDmitri Tikhonovstatic void 211758aff32SDmitri Tikhonovqdh_log_and_clean_exp_rec (struct qpack_dec_hdl *qdh) 212758aff32SDmitri Tikhonov{ 213758aff32SDmitri Tikhonov char buf[0x400]; 214758aff32SDmitri Tikhonov 215758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_comp_ratio = lsqpack_dec_ratio(&qdh->qdh_decoder); 216758aff32SDmitri Tikhonov /* Naughty: poking inside the decoder, it's not exposed. (Should it be?) */ 217758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_peer_max_size = qdh->qdh_decoder.qpd_cur_max_capacity; 218758aff32SDmitri Tikhonov (void) lsquic_qpack_exp_to_xml(qdh->qdh_exp_rec, buf, sizeof(buf)); 219758aff32SDmitri Tikhonov LSQ_NOTICE("%s", buf); 220758aff32SDmitri Tikhonov lsquic_qpack_exp_destroy(qdh->qdh_exp_rec); 221758aff32SDmitri Tikhonov qdh->qdh_exp_rec = NULL; 222758aff32SDmitri Tikhonov} 223758aff32SDmitri Tikhonov 224758aff32SDmitri Tikhonov 2255392f7a3SLiteSpeed Techvoid 2265392f7a3SLiteSpeed Techlsquic_qdh_cleanup (struct qpack_dec_hdl *qdh) 2275392f7a3SLiteSpeed Tech{ 2285392f7a3SLiteSpeed Tech if (qdh->qdh_flags & QDH_INITIALIZED) 2295392f7a3SLiteSpeed Tech { 2305392f7a3SLiteSpeed Tech LSQ_DEBUG("cleanup"); 231758aff32SDmitri Tikhonov if (qdh->qdh_exp_rec) 232758aff32SDmitri Tikhonov qdh_log_and_clean_exp_rec(qdh); 2334429f8eaSDmitri Tikhonov if (qdh->qdh_ua) 2344429f8eaSDmitri Tikhonov { 2354429f8eaSDmitri Tikhonov free(qdh->qdh_ua); 2364429f8eaSDmitri Tikhonov qdh->qdh_ua = NULL; 2374429f8eaSDmitri Tikhonov } 2385392f7a3SLiteSpeed Tech lsqpack_dec_cleanup(&qdh->qdh_decoder); 2395392f7a3SLiteSpeed Tech lsquic_frab_list_cleanup(&qdh->qdh_fral); 2405392f7a3SLiteSpeed Tech qdh->qdh_flags &= ~QDH_INITIALIZED; 2415392f7a3SLiteSpeed Tech } 2425392f7a3SLiteSpeed Tech} 2435392f7a3SLiteSpeed Tech 2445392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t * 2455392f7a3SLiteSpeed Techqdh_out_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 2465392f7a3SLiteSpeed Tech{ 2475392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = stream_if_ctx; 2485392f7a3SLiteSpeed Tech qdh->qdh_dec_sm_out = stream; 2495392f7a3SLiteSpeed Tech if (qdh->qdh_flags & QDH_INITIALIZED) 2505392f7a3SLiteSpeed Tech qdh_begin_out(qdh); 2515392f7a3SLiteSpeed Tech LSQ_DEBUG("initialized outgoing decoder stream"); 2525392f7a3SLiteSpeed Tech return (void *) qdh; 2535392f7a3SLiteSpeed Tech} 2545392f7a3SLiteSpeed Tech 2555392f7a3SLiteSpeed Tech 2565392f7a3SLiteSpeed Techstatic void 2575392f7a3SLiteSpeed Techqdh_out_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 2585392f7a3SLiteSpeed Tech{ 2595392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 2605392f7a3SLiteSpeed Tech struct lsquic_reader reader; 2615392f7a3SLiteSpeed Tech ssize_t nw; 2625392f7a3SLiteSpeed Tech unsigned char buf[LSQPACK_LONGEST_ICI]; 2635392f7a3SLiteSpeed Tech 2645392f7a3SLiteSpeed Tech if (lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 2655392f7a3SLiteSpeed Tech { 2665392f7a3SLiteSpeed Tech nw = lsqpack_dec_write_ici(&qdh->qdh_decoder, buf, sizeof(buf)); 2675392f7a3SLiteSpeed Tech if (nw > 0) 2685392f7a3SLiteSpeed Tech { 2695392f7a3SLiteSpeed Tech if (0 == qdh_write_decoder(qdh, buf, nw)) 2705392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zd-byte TSS instruction", nw); 2715392f7a3SLiteSpeed Tech else 2725392f7a3SLiteSpeed Tech goto err; 2735392f7a3SLiteSpeed Tech } 2745392f7a3SLiteSpeed Tech else if (nw < 0) 2755392f7a3SLiteSpeed Tech { 2765392f7a3SLiteSpeed Tech LSQ_WARN("could not generate TSS instruction"); 2775392f7a3SLiteSpeed Tech goto err; 2785392f7a3SLiteSpeed Tech } 2795392f7a3SLiteSpeed Tech } 2805392f7a3SLiteSpeed Tech 2815392f7a3SLiteSpeed Tech if (lsquic_frab_list_empty(&qdh->qdh_fral)) 2825392f7a3SLiteSpeed Tech { 2835392f7a3SLiteSpeed Tech LSQ_DEBUG("%s: nothing to write", __func__); 2845392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 2855392f7a3SLiteSpeed Tech return; 2865392f7a3SLiteSpeed Tech } 2875392f7a3SLiteSpeed Tech 2885392f7a3SLiteSpeed Tech reader = (struct lsquic_reader) { 2895392f7a3SLiteSpeed Tech .lsqr_read = lsquic_frab_list_read, 2905392f7a3SLiteSpeed Tech .lsqr_size = lsquic_frab_list_size, 2915392f7a3SLiteSpeed Tech .lsqr_ctx = &qdh->qdh_fral, 2925392f7a3SLiteSpeed Tech }; 2935392f7a3SLiteSpeed Tech 2945392f7a3SLiteSpeed Tech nw = lsquic_stream_writef(stream, &reader); 2955392f7a3SLiteSpeed Tech if (nw >= 0) 2965392f7a3SLiteSpeed Tech { 2975392f7a3SLiteSpeed Tech LSQ_DEBUG("wrote %zd bytes to stream", nw); 2985392f7a3SLiteSpeed Tech (void) lsquic_stream_flush(stream); 2995392f7a3SLiteSpeed Tech if (lsquic_frab_list_empty(&qdh->qdh_fral)) 300747be414SDmitri Tikhonov { 3015392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 302747be414SDmitri Tikhonov if (qdh->qdh_on_dec_sent_func) 303747be414SDmitri Tikhonov { 304747be414SDmitri Tikhonov LSQ_DEBUG("buffered data written: call callback"); 305747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_func(qdh->qdh_on_dec_sent_ctx); 306747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_func = NULL; 307747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_ctx = NULL; 308747be414SDmitri Tikhonov } 309747be414SDmitri Tikhonov } 3105392f7a3SLiteSpeed Tech } 3115392f7a3SLiteSpeed Tech else 3125392f7a3SLiteSpeed Tech { 3135392f7a3SLiteSpeed Tech LSQ_WARN("cannot write to stream: %s", strerror(errno)); 3145392f7a3SLiteSpeed Tech err: 3155392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(stream, 0); 3165392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 3175392f7a3SLiteSpeed Tech "cannot write to stream"); 3185392f7a3SLiteSpeed Tech } 3195392f7a3SLiteSpeed Tech} 3205392f7a3SLiteSpeed Tech 3215392f7a3SLiteSpeed Tech 3225392f7a3SLiteSpeed Techstatic void 3235392f7a3SLiteSpeed Techqdh_out_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3245392f7a3SLiteSpeed Tech{ 3255392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 3265392f7a3SLiteSpeed Tech qdh->qdh_dec_sm_out = NULL; 3275392f7a3SLiteSpeed Tech LSQ_DEBUG("closed outgoing decoder stream"); 3285392f7a3SLiteSpeed Tech} 3295392f7a3SLiteSpeed Tech 3305392f7a3SLiteSpeed Tech 3315392f7a3SLiteSpeed Techstatic void 3325392f7a3SLiteSpeed Techqdh_out_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 3335392f7a3SLiteSpeed Tech{ 3345392f7a3SLiteSpeed Tech assert(0); 3355392f7a3SLiteSpeed Tech} 3365392f7a3SLiteSpeed Tech 3375392f7a3SLiteSpeed Tech 3385392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qdh_dec_sm_out_if = 3395392f7a3SLiteSpeed Tech{ 3405392f7a3SLiteSpeed Tech .on_new_stream = qdh_out_on_new, 3415392f7a3SLiteSpeed Tech .on_read = qdh_out_on_read, 3425392f7a3SLiteSpeed Tech .on_write = qdh_out_on_write, 3435392f7a3SLiteSpeed Tech .on_close = qdh_out_on_close, 3445392f7a3SLiteSpeed Tech}; 3455392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qdh_dec_sm_out_if = 3465392f7a3SLiteSpeed Tech &qdh_dec_sm_out_if; 3475392f7a3SLiteSpeed Tech 3485392f7a3SLiteSpeed Tech 3495392f7a3SLiteSpeed Techstatic lsquic_stream_ctx_t * 3505392f7a3SLiteSpeed Techqdh_in_on_new (void *stream_if_ctx, struct lsquic_stream *stream) 3515392f7a3SLiteSpeed Tech{ 3525392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = stream_if_ctx; 3535392f7a3SLiteSpeed Tech qdh->qdh_enc_sm_in = stream; 3545392f7a3SLiteSpeed Tech if (qdh->qdh_flags & QDH_INITIALIZED) 3555392f7a3SLiteSpeed Tech lsquic_stream_wantread(qdh->qdh_enc_sm_in, 1); 3565392f7a3SLiteSpeed Tech LSQ_DEBUG("initialized incoming encoder stream"); 3575392f7a3SLiteSpeed Tech return (void *) qdh; 3585392f7a3SLiteSpeed Tech} 3595392f7a3SLiteSpeed Tech 3605392f7a3SLiteSpeed Tech 3615392f7a3SLiteSpeed Techstatic size_t 3625392f7a3SLiteSpeed Techqdh_read_encoder_stream (void *ctx, const unsigned char *buf, size_t sz, 3635392f7a3SLiteSpeed Tech int fin) 3645392f7a3SLiteSpeed Tech{ 3655392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 3665392f7a3SLiteSpeed Tech const struct lsqpack_dec_err *qerr; 3675392f7a3SLiteSpeed Tech int s; 3685392f7a3SLiteSpeed Tech 3695392f7a3SLiteSpeed Tech if (fin) 3705392f7a3SLiteSpeed Tech { 3715392f7a3SLiteSpeed Tech LSQ_INFO("encoder stream is closed"); 3725392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 3735392f7a3SLiteSpeed Tech HEC_CLOSED_CRITICAL_STREAM, "Peer closed QPACK encoder stream"); 3745392f7a3SLiteSpeed Tech goto end; 3755392f7a3SLiteSpeed Tech } 3765392f7a3SLiteSpeed Tech 3775392f7a3SLiteSpeed Tech s = lsqpack_dec_enc_in(&qdh->qdh_decoder, buf, sz); 3785392f7a3SLiteSpeed Tech if (s != 0) 3795392f7a3SLiteSpeed Tech { 380747be414SDmitri Tikhonov LSQ_INFO("error reading encoder stream"); 3815392f7a3SLiteSpeed Tech qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 3825392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 38310e0dad8SGeorge Wang HEC_QPACK_ENCODER_STREAM_ERROR, "Error interpreting QPACK encoder " 3845392f7a3SLiteSpeed Tech "stream; offset %"PRIu64", line %d", qerr->off, qerr->line); 3855392f7a3SLiteSpeed Tech goto end; 3865392f7a3SLiteSpeed Tech } 3875392f7a3SLiteSpeed Tech if (qdh->qdh_dec_sm_out 3885392f7a3SLiteSpeed Tech && lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 3895392f7a3SLiteSpeed Tech lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 3905392f7a3SLiteSpeed Tech 3915392f7a3SLiteSpeed Tech LSQ_DEBUG("successfully fed %zu bytes to QPACK decoder", sz); 3925392f7a3SLiteSpeed Tech 3935392f7a3SLiteSpeed Tech end: 3945392f7a3SLiteSpeed Tech return sz; 3955392f7a3SLiteSpeed Tech} 3965392f7a3SLiteSpeed Tech 3975392f7a3SLiteSpeed Tech 3985392f7a3SLiteSpeed Techstatic void 3995392f7a3SLiteSpeed Techqdh_in_on_read (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 4005392f7a3SLiteSpeed Tech{ 4015392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 4025392f7a3SLiteSpeed Tech ssize_t nread; 4035392f7a3SLiteSpeed Tech 4045392f7a3SLiteSpeed Tech nread = lsquic_stream_readf(stream, qdh_read_encoder_stream, qdh); 4055392f7a3SLiteSpeed Tech if (nread <= 0) 4065392f7a3SLiteSpeed Tech { 4075392f7a3SLiteSpeed Tech if (nread < 0) 4085392f7a3SLiteSpeed Tech { 4095392f7a3SLiteSpeed Tech LSQ_WARN("cannot read from encoder stream: %s", strerror(errno)); 4105392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_internal_error(qdh->qdh_conn, 4115392f7a3SLiteSpeed Tech "cannot read from encoder stream"); 4125392f7a3SLiteSpeed Tech } 4135392f7a3SLiteSpeed Tech else 4145392f7a3SLiteSpeed Tech { 4155392f7a3SLiteSpeed Tech LSQ_INFO("encoder stream closed by peer: abort connection"); 4165392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 4175392f7a3SLiteSpeed Tech HEC_CLOSED_CRITICAL_STREAM, "encoder stream closed"); 4185392f7a3SLiteSpeed Tech } 4195392f7a3SLiteSpeed Tech lsquic_stream_wantread(stream, 0); 4205392f7a3SLiteSpeed Tech } 4215392f7a3SLiteSpeed Tech} 4225392f7a3SLiteSpeed Tech 4235392f7a3SLiteSpeed Tech 4245392f7a3SLiteSpeed Techstatic void 4255392f7a3SLiteSpeed Techqdh_in_on_close (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 4265392f7a3SLiteSpeed Tech{ 4275392f7a3SLiteSpeed Tech struct qpack_dec_hdl *const qdh = (void *) ctx; 4285392f7a3SLiteSpeed Tech LSQ_DEBUG("closed incoming encoder stream"); 4295392f7a3SLiteSpeed Tech qdh->qdh_enc_sm_in = NULL; 4305392f7a3SLiteSpeed Tech} 4315392f7a3SLiteSpeed Tech 4325392f7a3SLiteSpeed Tech 4335392f7a3SLiteSpeed Techstatic void 4345392f7a3SLiteSpeed Techqdh_in_on_write (struct lsquic_stream *stream, lsquic_stream_ctx_t *ctx) 4355392f7a3SLiteSpeed Tech{ 4365392f7a3SLiteSpeed Tech assert(0); 4375392f7a3SLiteSpeed Tech} 4385392f7a3SLiteSpeed Tech 4395392f7a3SLiteSpeed Tech 4405392f7a3SLiteSpeed Techstatic const struct lsquic_stream_if qdh_enc_sm_in_if = 4415392f7a3SLiteSpeed Tech{ 4425392f7a3SLiteSpeed Tech .on_new_stream = qdh_in_on_new, 4435392f7a3SLiteSpeed Tech .on_read = qdh_in_on_read, 4445392f7a3SLiteSpeed Tech .on_write = qdh_in_on_write, 4455392f7a3SLiteSpeed Tech .on_close = qdh_in_on_close, 4465392f7a3SLiteSpeed Tech}; 4475392f7a3SLiteSpeed Techconst struct lsquic_stream_if *const lsquic_qdh_enc_sm_in_if = 4485392f7a3SLiteSpeed Tech &qdh_enc_sm_in_if; 4495392f7a3SLiteSpeed Tech 4505392f7a3SLiteSpeed Tech 4515392f7a3SLiteSpeed Techstatic void 4525392f7a3SLiteSpeed Techqdh_hblock_unblocked (void *stream_p) 4535392f7a3SLiteSpeed Tech{ 4545392f7a3SLiteSpeed Tech struct lsquic_stream *const stream = stream_p; 4555392f7a3SLiteSpeed Tech lsquic_stream_qdec_unblocked(stream); 4565392f7a3SLiteSpeed Tech} 4575392f7a3SLiteSpeed Tech 4585392f7a3SLiteSpeed Tech 459747be414SDmitri Tikhonovstruct cont_len 460747be414SDmitri Tikhonov{ 461747be414SDmitri Tikhonov unsigned long long value; 462747be414SDmitri Tikhonov int has; /* 1: set, 0: not set, -1: invalid */ 463747be414SDmitri Tikhonov}; 464747be414SDmitri Tikhonov 465747be414SDmitri Tikhonov 466747be414SDmitri Tikhonovstatic void 467747be414SDmitri Tikhonovprocess_content_length (const struct qpack_dec_hdl *qdh /* for logging */, 468747be414SDmitri Tikhonov struct cont_len *cl, const char *val /* not NUL-terminated */, 469747be414SDmitri Tikhonov unsigned len) 470747be414SDmitri Tikhonov{ 471747be414SDmitri Tikhonov char *endcl, cont_len_buf[30]; 472747be414SDmitri Tikhonov 473747be414SDmitri Tikhonov if (0 == cl->has) 474747be414SDmitri Tikhonov { 475747be414SDmitri Tikhonov if (len >= sizeof(cont_len_buf)) 476747be414SDmitri Tikhonov { 477747be414SDmitri Tikhonov LSQ_DEBUG("content-length has invalid value `%.*s'", 478747be414SDmitri Tikhonov (int) len, val); 479747be414SDmitri Tikhonov cl->has = -1; 480747be414SDmitri Tikhonov return; 481747be414SDmitri Tikhonov } 482747be414SDmitri Tikhonov memcpy(cont_len_buf, val, len); 483747be414SDmitri Tikhonov cont_len_buf[len] = '\0'; 484747be414SDmitri Tikhonov cl->value = strtoull(cont_len_buf, &endcl, 10); 485747be414SDmitri Tikhonov if (*endcl == '\0' && !(ULLONG_MAX == cl->value && ERANGE == errno)) 486747be414SDmitri Tikhonov { 487747be414SDmitri Tikhonov cl->has = 1; 488747be414SDmitri Tikhonov LSQ_DEBUG("content length is %llu", cl->value); 489747be414SDmitri Tikhonov } 490747be414SDmitri Tikhonov else 491747be414SDmitri Tikhonov { 492747be414SDmitri Tikhonov cl->has = -1; 493747be414SDmitri Tikhonov LSQ_DEBUG("content-length has invalid value `%.*s'", 494747be414SDmitri Tikhonov (int) len, val); 495747be414SDmitri Tikhonov } 496747be414SDmitri Tikhonov } 497747be414SDmitri Tikhonov else if (cl->has > 0) 498747be414SDmitri Tikhonov { 499747be414SDmitri Tikhonov LSQ_DEBUG("header set has two content-length: ambiguous, " 500747be414SDmitri Tikhonov "turn off checking"); 501747be414SDmitri Tikhonov cl->has = -1; 502747be414SDmitri Tikhonov } 503747be414SDmitri Tikhonov} 504747be414SDmitri Tikhonov 505747be414SDmitri Tikhonov 506747be414SDmitri Tikhonovstatic int 50755613f44SDmitri Tikhonovis_content_length (const struct lsxpack_header *xhdr) 508747be414SDmitri Tikhonov{ 50955613f44SDmitri Tikhonov return ((xhdr->flags & LSXPACK_QPACK_IDX) 51055613f44SDmitri Tikhonov && xhdr->qpack_index == LSQPACK_TNV_CONTENT_LENGTH_0) 51155613f44SDmitri Tikhonov || (xhdr->name_len == 14 && 0 == memcmp(lsxpack_header_get_name(xhdr), 51255613f44SDmitri Tikhonov "content-length", 13)) 513747be414SDmitri Tikhonov ; 514747be414SDmitri Tikhonov} 515747be414SDmitri Tikhonov 516747be414SDmitri Tikhonov 517fbc6cc04SDmitri Tikhonovstatic int 518fbc6cc04SDmitri Tikhonovis_priority (const struct lsxpack_header *xhdr) 519fbc6cc04SDmitri Tikhonov{ 520fbc6cc04SDmitri Tikhonov return xhdr->name_len == 8 521fbc6cc04SDmitri Tikhonov && 0 == memcmp(lsxpack_header_get_name(xhdr), "priority", 8); 522fbc6cc04SDmitri Tikhonov} 523fbc6cc04SDmitri Tikhonov 524fbc6cc04SDmitri Tikhonov 52555613f44SDmitri Tikhonovstatic struct lsxpack_header * 52655613f44SDmitri Tikhonovqdh_prepare_decode (void *stream_p, struct lsxpack_header *xhdr, size_t space) 5275392f7a3SLiteSpeed Tech{ 52855613f44SDmitri Tikhonov struct lsquic_stream *const stream = stream_p; 52955613f44SDmitri Tikhonov union hblock_ctx *const u = stream->sm_hblock_ctx; 53055613f44SDmitri Tikhonov struct qpack_dec_hdl *const qdh = u->ctx.qdh; 53155613f44SDmitri Tikhonov 53255613f44SDmitri Tikhonov return qdh->qdh_enpub->enp_hsi_if->hsi_prepare_decode( 53355613f44SDmitri Tikhonov u->ctx.hset, xhdr, space); 53455613f44SDmitri Tikhonov} 5355392f7a3SLiteSpeed Tech 5365392f7a3SLiteSpeed Tech 537758aff32SDmitri Tikhonovstatic void 538758aff32SDmitri Tikhonovqdh_maybe_set_user_agent (struct qpack_dec_hdl *qdh, 5394429f8eaSDmitri Tikhonov const struct lsxpack_header *xhdr, char **ua) 540758aff32SDmitri Tikhonov{ 541758aff32SDmitri Tikhonov /* Flipped: we are the *decoder* */ 5424429f8eaSDmitri Tikhonov const char *const name = qdh->qdh_flags & QDH_SERVER ? 543758aff32SDmitri Tikhonov "user-agent" : "server"; 5444429f8eaSDmitri Tikhonov const size_t len = qdh->qdh_flags & QDH_SERVER ? 10 : 6; 545758aff32SDmitri Tikhonov 546758aff32SDmitri Tikhonov if (len == xhdr->name_len 547758aff32SDmitri Tikhonov && 0 == memcmp(name, lsxpack_header_get_name(xhdr), len)) 5484429f8eaSDmitri Tikhonov *ua = strndup(lsxpack_header_get_value(xhdr), xhdr->val_len); 549758aff32SDmitri Tikhonov} 550758aff32SDmitri Tikhonov 551758aff32SDmitri Tikhonov 552eea99896SDmitri Tikhonov/* Intercept header errors so that upper-layer errors do not get 553eea99896SDmitri Tikhonov * misinterpreted as QPACK errors. 554eea99896SDmitri Tikhonov */ 555eea99896SDmitri Tikhonovstatic int 556eea99896SDmitri Tikhonovqdh_hsi_process_wrapper (struct qpack_dec_hdl *qdh, void *hset, 557eea99896SDmitri Tikhonov struct lsxpack_header *xhdr) 558eea99896SDmitri Tikhonov{ 559eea99896SDmitri Tikhonov int retval; 560eea99896SDmitri Tikhonov 561eea99896SDmitri Tikhonov retval = qdh->qdh_enpub->enp_hsi_if->hsi_process_header(hset, xhdr); 562eea99896SDmitri Tikhonov if (0 != retval) 563eea99896SDmitri Tikhonov qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 56455d69529SGeorge Wang HEC_MESSAGE_ERROR, 565eea99896SDmitri Tikhonov "error processing headers"); 566eea99896SDmitri Tikhonov 567eea99896SDmitri Tikhonov return retval; 568eea99896SDmitri Tikhonov} 569eea99896SDmitri Tikhonov 570eea99896SDmitri Tikhonov 57155613f44SDmitri Tikhonovstatic int 57255613f44SDmitri Tikhonovqdh_process_header (void *stream_p, struct lsxpack_header *xhdr) 57355613f44SDmitri Tikhonov{ 57455613f44SDmitri Tikhonov struct lsquic_stream *const stream = stream_p; 57555613f44SDmitri Tikhonov union hblock_ctx *const u = stream->sm_hblock_ctx; 57655613f44SDmitri Tikhonov struct qpack_dec_hdl *const qdh = u->ctx.qdh; 57755613f44SDmitri Tikhonov struct cont_len cl; 5785392f7a3SLiteSpeed Tech 57955613f44SDmitri Tikhonov if (is_content_length(xhdr)) 5805392f7a3SLiteSpeed Tech { 58155613f44SDmitri Tikhonov cl.has = 0; 58255613f44SDmitri Tikhonov process_content_length(qdh, &cl, lsxpack_header_get_value(xhdr), 58355613f44SDmitri Tikhonov xhdr->val_len); 58455613f44SDmitri Tikhonov if (cl.has > 0) 58555613f44SDmitri Tikhonov (void) lsquic_stream_verify_len(stream, cl.value); 5865392f7a3SLiteSpeed Tech } 587fbc6cc04SDmitri Tikhonov else if ((stream->sm_bflags & (SMBF_HTTP_PRIO|SMBF_HPRIO_SET)) 588fbc6cc04SDmitri Tikhonov == SMBF_HTTP_PRIO 589fbc6cc04SDmitri Tikhonov && is_priority(xhdr)) 590fbc6cc04SDmitri Tikhonov { 591fbc6cc04SDmitri Tikhonov u->ctx.ppc_flags &= ~(PPC_INC_NAME|PPC_URG_NAME); 592fbc6cc04SDmitri Tikhonov (void) lsquic_http_parse_pfv(lsxpack_header_get_value(xhdr), 593fbc6cc04SDmitri Tikhonov xhdr->val_len, &u->ctx.ppc_flags, &u->ctx.ehp, 594fbc6cc04SDmitri Tikhonov (char *) stream->conn_pub->mm->acki, 595fbc6cc04SDmitri Tikhonov sizeof(*stream->conn_pub->mm->acki)); 596fbc6cc04SDmitri Tikhonov } 597758aff32SDmitri Tikhonov else if (qdh->qdh_exp_rec && !qdh->qdh_exp_rec->qer_user_agent) 5984429f8eaSDmitri Tikhonov qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_exp_rec->qer_user_agent); 5994429f8eaSDmitri Tikhonov else if ((qdh->qdh_flags & QDH_SAVE_UA) && !qdh->qdh_ua) 6004429f8eaSDmitri Tikhonov qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_ua); 6015392f7a3SLiteSpeed Tech 602eea99896SDmitri Tikhonov return qdh_hsi_process_wrapper(qdh, u->ctx.hset, xhdr); 6035392f7a3SLiteSpeed Tech} 6045392f7a3SLiteSpeed Tech 6055392f7a3SLiteSpeed Tech 60655613f44SDmitri Tikhonovstatic const struct lsqpack_dec_hset_if dhi_if = 60702b6086dSDmitri Tikhonov{ 60855613f44SDmitri Tikhonov .dhi_unblocked = qdh_hblock_unblocked, 60955613f44SDmitri Tikhonov .dhi_prepare_decode = qdh_prepare_decode, 61055613f44SDmitri Tikhonov .dhi_process_header = qdh_process_header, 61155613f44SDmitri Tikhonov}; 61202b6086dSDmitri Tikhonov 61302b6086dSDmitri Tikhonov 6144580fab7SDmitri Tikhonovstatic void 6154580fab7SDmitri Tikhonovqdh_maybe_destroy_hblock_ctx (struct qpack_dec_hdl *qdh, 6164580fab7SDmitri Tikhonov struct lsquic_stream *stream) 6174580fab7SDmitri Tikhonov{ 6184580fab7SDmitri Tikhonov if (stream->sm_hblock_ctx) 6194580fab7SDmitri Tikhonov { 6204580fab7SDmitri Tikhonov LSQ_DEBUG("destroy hblock_ctx of stream %"PRIu64, stream->id); 6214580fab7SDmitri Tikhonov qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set( 6224580fab7SDmitri Tikhonov stream->sm_hblock_ctx->ctx.hset); 6234580fab7SDmitri Tikhonov free(stream->sm_hblock_ctx); 6244580fab7SDmitri Tikhonov stream->sm_hblock_ctx = NULL; 6254580fab7SDmitri Tikhonov } 6264580fab7SDmitri Tikhonov} 6274580fab7SDmitri Tikhonov 6284580fab7SDmitri Tikhonov 6295392f7a3SLiteSpeed Techstatic enum lsqpack_read_header_status 6305392f7a3SLiteSpeed Techqdh_header_read_results (struct qpack_dec_hdl *qdh, 6315392f7a3SLiteSpeed Tech struct lsquic_stream *stream, enum lsqpack_read_header_status rhs, 63255613f44SDmitri Tikhonov const unsigned char *dec_buf, size_t dec_buf_sz) 6335392f7a3SLiteSpeed Tech{ 6345392f7a3SLiteSpeed Tech const struct lsqpack_dec_err *qerr; 63555613f44SDmitri Tikhonov struct uncompressed_headers *uh; 63655613f44SDmitri Tikhonov void *hset; 6375392f7a3SLiteSpeed Tech 6385392f7a3SLiteSpeed Tech if (rhs == LQRHS_DONE) 6395392f7a3SLiteSpeed Tech { 640293df8d6SGeorge Wang if (1) //!lsquic_stream_header_is_trailer(stream)) 6415392f7a3SLiteSpeed Tech { 642fbc6cc04SDmitri Tikhonov if (stream->sm_hblock_ctx->ctx.ppc_flags 643fbc6cc04SDmitri Tikhonov & (PPC_INC_SET|PPC_URG_SET)) 644fbc6cc04SDmitri Tikhonov { 645fbc6cc04SDmitri Tikhonov assert(stream->sm_bflags & SMBF_HTTP_PRIO); 646fbc6cc04SDmitri Tikhonov LSQ_DEBUG("Apply Priority from headers to stream %"PRIu64, 647fbc6cc04SDmitri Tikhonov stream->id); 648fbc6cc04SDmitri Tikhonov (void) lsquic_stream_set_http_prio(stream, 649fbc6cc04SDmitri Tikhonov &stream->sm_hblock_ctx->ctx.ehp); 650fbc6cc04SDmitri Tikhonov } 65155613f44SDmitri Tikhonov hset = stream->sm_hblock_ctx->ctx.hset; 6524580fab7SDmitri Tikhonov uh = (void *) stream->sm_hblock_ctx; 65355613f44SDmitri Tikhonov stream->sm_hblock_ctx = NULL; 65455613f44SDmitri Tikhonov memset(uh, 0, sizeof(*uh)); 65555613f44SDmitri Tikhonov uh->uh_stream_id = stream->id; 65655613f44SDmitri Tikhonov uh->uh_oth_stream_id = 0; 65755613f44SDmitri Tikhonov uh->uh_weight = 0; 65855613f44SDmitri Tikhonov uh->uh_exclusive = -1; 65955613f44SDmitri Tikhonov if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if) 66055613f44SDmitri Tikhonov uh->uh_flags |= UH_H1H; 661eea99896SDmitri Tikhonov if (0 != qdh_hsi_process_wrapper(qdh, hset, NULL)) 66255613f44SDmitri Tikhonov { 6634580fab7SDmitri Tikhonov LSQ_DEBUG("finishing hset failed"); 66455613f44SDmitri Tikhonov free(uh); 6654580fab7SDmitri Tikhonov qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(hset); 6665392f7a3SLiteSpeed Tech return LQRHS_ERROR; 66755613f44SDmitri Tikhonov } 66855613f44SDmitri Tikhonov uh->uh_hset = hset; 66955613f44SDmitri Tikhonov if (0 == lsquic_stream_uh_in(stream, uh)) 67055613f44SDmitri Tikhonov LSQ_DEBUG("gave hset to stream %"PRIu64, stream->id); 67155613f44SDmitri Tikhonov else 6725392f7a3SLiteSpeed Tech { 67355613f44SDmitri Tikhonov LSQ_DEBUG("could not give hset to stream %"PRIu64, stream->id); 67455613f44SDmitri Tikhonov free(uh); 6754580fab7SDmitri Tikhonov qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(hset); 67655613f44SDmitri Tikhonov return LQRHS_ERROR; 6775392f7a3SLiteSpeed Tech } 6785392f7a3SLiteSpeed Tech } 6795392f7a3SLiteSpeed Tech else 6805392f7a3SLiteSpeed Tech { 68155613f44SDmitri Tikhonov LSQ_DEBUG("discard trailer header set"); 6824580fab7SDmitri Tikhonov qdh_maybe_destroy_hblock_ctx(qdh, stream); 68355613f44SDmitri Tikhonov } 68455613f44SDmitri Tikhonov if (qdh->qdh_dec_sm_out) 68555613f44SDmitri Tikhonov { 68655613f44SDmitri Tikhonov if (dec_buf_sz 68755613f44SDmitri Tikhonov && 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz)) 68855613f44SDmitri Tikhonov { 68955613f44SDmitri Tikhonov return LQRHS_ERROR; 69055613f44SDmitri Tikhonov } 69155613f44SDmitri Tikhonov if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder)) 69255613f44SDmitri Tikhonov lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1); 6935392f7a3SLiteSpeed Tech } 6945392f7a3SLiteSpeed Tech } 6955392f7a3SLiteSpeed Tech else if (rhs == LQRHS_ERROR) 6965392f7a3SLiteSpeed Tech { 6974580fab7SDmitri Tikhonov qdh_maybe_destroy_hblock_ctx(qdh, stream); 6985392f7a3SLiteSpeed Tech qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder); 6995392f7a3SLiteSpeed Tech qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1, 7005392f7a3SLiteSpeed Tech HEC_QPACK_DECOMPRESSION_FAILED, "QPACK decompression error; " 7015392f7a3SLiteSpeed Tech "stream %"PRIu64", offset %"PRIu64", line %d", qerr->stream_id, 7025392f7a3SLiteSpeed Tech qerr->off, qerr->line); 7035392f7a3SLiteSpeed Tech } 7045392f7a3SLiteSpeed Tech 7055392f7a3SLiteSpeed Tech return rhs; 7065392f7a3SLiteSpeed Tech} 7075392f7a3SLiteSpeed Tech 7085392f7a3SLiteSpeed Tech 7095392f7a3SLiteSpeed Techenum lsqpack_read_header_status 7105392f7a3SLiteSpeed Techlsquic_qdh_header_in_begin (struct qpack_dec_hdl *qdh, 7115392f7a3SLiteSpeed Tech struct lsquic_stream *stream, uint64_t header_size, 7125392f7a3SLiteSpeed Tech const unsigned char **buf, size_t bufsz) 7135392f7a3SLiteSpeed Tech{ 7145392f7a3SLiteSpeed Tech enum lsqpack_read_header_status rhs; 71555613f44SDmitri Tikhonov void *hset; 71655613f44SDmitri Tikhonov int is_pp; 7175392f7a3SLiteSpeed Tech size_t dec_buf_sz; 71855613f44SDmitri Tikhonov union hblock_ctx *u; 7195392f7a3SLiteSpeed Tech unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 7205392f7a3SLiteSpeed Tech 7211c105cf2SDmitri Tikhonov assert(!(stream->stream_flags & STREAM_U_READ_DONE)); 7221c105cf2SDmitri Tikhonov 72355613f44SDmitri Tikhonov if (!(qdh->qdh_flags & QDH_INITIALIZED)) 7245392f7a3SLiteSpeed Tech { 72555613f44SDmitri Tikhonov LSQ_WARN("not initialized: cannot process header block"); 72655613f44SDmitri Tikhonov return LQRHS_ERROR; 7275392f7a3SLiteSpeed Tech } 72855613f44SDmitri Tikhonov 72955613f44SDmitri Tikhonov u = malloc(sizeof(*u)); 73055613f44SDmitri Tikhonov if (!u) 7315392f7a3SLiteSpeed Tech { 73255613f44SDmitri Tikhonov LSQ_INFO("cannot allocate hblock_ctx"); 73355613f44SDmitri Tikhonov return LQRHS_ERROR; 73455613f44SDmitri Tikhonov } 73555613f44SDmitri Tikhonov 73655613f44SDmitri Tikhonov is_pp = lsquic_stream_header_is_pp(stream); 73755613f44SDmitri Tikhonov hset = qdh->qdh_enpub->enp_hsi_if->hsi_create_header_set( 73855613f44SDmitri Tikhonov qdh->qdh_hsi_ctx, stream, is_pp); 73955613f44SDmitri Tikhonov if (!hset) 74055613f44SDmitri Tikhonov { 74155613f44SDmitri Tikhonov free(u); 74255613f44SDmitri Tikhonov LSQ_DEBUG("hsi_create_header_set failure"); 7435392f7a3SLiteSpeed Tech return LQRHS_ERROR; 7445392f7a3SLiteSpeed Tech } 7455392f7a3SLiteSpeed Tech 74655613f44SDmitri Tikhonov u->ctx.hset = hset; 74755613f44SDmitri Tikhonov u->ctx.qdh = qdh; 748fbc6cc04SDmitri Tikhonov u->ctx.ppc_flags = 0; 749fbc6cc04SDmitri Tikhonov u->ctx.ehp = (struct lsquic_ext_http_prio) { 750fbc6cc04SDmitri Tikhonov .urgency = LSQUIC_DEF_HTTP_URGENCY, 751fbc6cc04SDmitri Tikhonov .incremental = LSQUIC_DEF_HTTP_INCREMENTAL, 752fbc6cc04SDmitri Tikhonov }; 75355613f44SDmitri Tikhonov stream->sm_hblock_ctx = u; 75455613f44SDmitri Tikhonov 755758aff32SDmitri Tikhonov if (qdh->qdh_exp_rec) 756758aff32SDmitri Tikhonov { 757758aff32SDmitri Tikhonov const lsquic_time_t now = lsquic_time_now(); 758758aff32SDmitri Tikhonov if (0 == qdh->qdh_exp_rec->qer_hblock_count) 759758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_first_req = now; 760758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_last_req = now; 761758aff32SDmitri Tikhonov ++qdh->qdh_exp_rec->qer_hblock_count; 762758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_hblock_size += bufsz; 763758aff32SDmitri Tikhonov } 764758aff32SDmitri Tikhonov 76555613f44SDmitri Tikhonov dec_buf_sz = sizeof(dec_buf); 76655613f44SDmitri Tikhonov rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id, 76755613f44SDmitri Tikhonov header_size, buf, bufsz, dec_buf, &dec_buf_sz); 768758aff32SDmitri Tikhonov if (qdh->qdh_exp_rec) 769758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_peer_max_blocked += rhs == LQRHS_BLOCKED; 77055613f44SDmitri Tikhonov return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 7715392f7a3SLiteSpeed Tech} 7725392f7a3SLiteSpeed Tech 7735392f7a3SLiteSpeed Tech 7745392f7a3SLiteSpeed Techenum lsqpack_read_header_status 7755392f7a3SLiteSpeed Techlsquic_qdh_header_in_continue (struct qpack_dec_hdl *qdh, 7765392f7a3SLiteSpeed Tech struct lsquic_stream *stream, const unsigned char **buf, size_t bufsz) 7775392f7a3SLiteSpeed Tech{ 7785392f7a3SLiteSpeed Tech enum lsqpack_read_header_status rhs; 7795392f7a3SLiteSpeed Tech size_t dec_buf_sz; 7805392f7a3SLiteSpeed Tech unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK]; 7815392f7a3SLiteSpeed Tech 7821c105cf2SDmitri Tikhonov assert(!(stream->stream_flags & STREAM_U_READ_DONE)); 7831c105cf2SDmitri Tikhonov 7845392f7a3SLiteSpeed Tech if (qdh->qdh_flags & QDH_INITIALIZED) 7855392f7a3SLiteSpeed Tech { 786758aff32SDmitri Tikhonov if (qdh->qdh_exp_rec) 787758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_hblock_size += bufsz; 7885392f7a3SLiteSpeed Tech dec_buf_sz = sizeof(dec_buf); 7895392f7a3SLiteSpeed Tech rhs = lsqpack_dec_header_read(&qdh->qdh_decoder, stream, 79055613f44SDmitri Tikhonov buf, bufsz, dec_buf, &dec_buf_sz); 791758aff32SDmitri Tikhonov if (qdh->qdh_exp_rec) 792758aff32SDmitri Tikhonov qdh->qdh_exp_rec->qer_peer_max_blocked += rhs == LQRHS_BLOCKED; 79355613f44SDmitri Tikhonov return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz); 7945392f7a3SLiteSpeed Tech } 7955392f7a3SLiteSpeed Tech else 7965392f7a3SLiteSpeed Tech { 7975392f7a3SLiteSpeed Tech LSQ_WARN("not initialized: cannot process header block"); 7985392f7a3SLiteSpeed Tech return LQRHS_ERROR; 7995392f7a3SLiteSpeed Tech } 8005392f7a3SLiteSpeed Tech} 8015392f7a3SLiteSpeed Tech 8025392f7a3SLiteSpeed Tech 8031c105cf2SDmitri Tikhonovstatic void 8045392f7a3SLiteSpeed Techlsquic_qdh_unref_stream (struct qpack_dec_hdl *qdh, 8055392f7a3SLiteSpeed Tech struct lsquic_stream *stream) 8065392f7a3SLiteSpeed Tech{ 8075392f7a3SLiteSpeed Tech if (0 == lsqpack_dec_unref_stream(&qdh->qdh_decoder, stream)) 8085392f7a3SLiteSpeed Tech LSQ_DEBUG("unreffed stream %"PRIu64, stream->id); 8095392f7a3SLiteSpeed Tech else 8105392f7a3SLiteSpeed Tech LSQ_WARN("cannot unref stream %"PRIu64, stream->id); 8115392f7a3SLiteSpeed Tech} 8125392f7a3SLiteSpeed Tech 8135392f7a3SLiteSpeed Tech 8145392f7a3SLiteSpeed Techvoid 8155392f7a3SLiteSpeed Techlsquic_qdh_cancel_stream (struct qpack_dec_hdl *qdh, 8165392f7a3SLiteSpeed Tech struct lsquic_stream *stream) 8175392f7a3SLiteSpeed Tech{ 8185392f7a3SLiteSpeed Tech ssize_t nw; 8195392f7a3SLiteSpeed Tech unsigned char buf[LSQPACK_LONGEST_CANCEL]; 8205392f7a3SLiteSpeed Tech 8214580fab7SDmitri Tikhonov qdh_maybe_destroy_hblock_ctx(qdh, stream); 8224580fab7SDmitri Tikhonov 8231c105cf2SDmitri Tikhonov if (!qdh->qdh_dec_sm_out) 8241c105cf2SDmitri Tikhonov return; 8251c105cf2SDmitri Tikhonov 8265392f7a3SLiteSpeed Tech nw = lsqpack_dec_cancel_stream(&qdh->qdh_decoder, stream, buf, sizeof(buf)); 8275392f7a3SLiteSpeed Tech if (nw > 0) 8285392f7a3SLiteSpeed Tech { 8295392f7a3SLiteSpeed Tech if (0 == qdh_write_decoder(qdh, buf, nw)) 8305392f7a3SLiteSpeed Tech LSQ_DEBUG("cancelled stream %"PRIu64" and wrote %zd-byte Cancel " 8315392f7a3SLiteSpeed Tech "Stream instruction to the decoder stream", stream->id, nw); 8325392f7a3SLiteSpeed Tech } 8335392f7a3SLiteSpeed Tech else if (nw == 0) 8345392f7a3SLiteSpeed Tech LSQ_WARN("cannot cancel stream %"PRIu64" -- not found", stream->id); 8355392f7a3SLiteSpeed Tech else 8365392f7a3SLiteSpeed Tech { 8375392f7a3SLiteSpeed Tech LSQ_WARN("cannot cancel stream %"PRIu64" -- not enough buffer space " 8385392f7a3SLiteSpeed Tech "to encode Cancel Stream instructin", stream->id); 8395392f7a3SLiteSpeed Tech lsquic_qdh_unref_stream(qdh, stream); 8405392f7a3SLiteSpeed Tech } 8415392f7a3SLiteSpeed Tech} 842747be414SDmitri Tikhonov 843747be414SDmitri Tikhonov 8441c105cf2SDmitri Tikhonovvoid 8451c105cf2SDmitri Tikhonovlsquic_qdh_cancel_stream_id (struct qpack_dec_hdl *qdh, 8461c105cf2SDmitri Tikhonov lsquic_stream_id_t stream_id) 8471c105cf2SDmitri Tikhonov{ 8481c105cf2SDmitri Tikhonov ssize_t nw; 8491c105cf2SDmitri Tikhonov unsigned char buf[LSQPACK_LONGEST_CANCEL]; 8501c105cf2SDmitri Tikhonov 8511c105cf2SDmitri Tikhonov if (!qdh->qdh_dec_sm_out) 8521c105cf2SDmitri Tikhonov return; 8531c105cf2SDmitri Tikhonov 8541c105cf2SDmitri Tikhonov nw = lsqpack_dec_cancel_stream_id(&qdh->qdh_decoder, stream_id, buf, 8551c105cf2SDmitri Tikhonov sizeof(buf)); 8561c105cf2SDmitri Tikhonov if (nw > 0) 8571c105cf2SDmitri Tikhonov { 8581c105cf2SDmitri Tikhonov if (0 == qdh_write_decoder(qdh, buf, nw)) 8598dc2321bSDarrin Smart LSQ_DEBUG("wrote %zd-byte Cancel Stream instruction for " 8608dc2321bSDarrin Smart "stream %"PRIu64" to the decoder stream", nw, stream_id); 8611c105cf2SDmitri Tikhonov } 8621c105cf2SDmitri Tikhonov else if (nw == 0) 8631c105cf2SDmitri Tikhonov LSQ_DEBUG("not generating Cancel Stream instruction for " 8641c105cf2SDmitri Tikhonov "stream %"PRIu64, stream_id); 8651c105cf2SDmitri Tikhonov else 8661c105cf2SDmitri Tikhonov LSQ_WARN("cannot generate Cancel Stream instruction for " 8671c105cf2SDmitri Tikhonov "stream %"PRIu64" -- not enough buffer space", stream_id); 8681c105cf2SDmitri Tikhonov} 8691c105cf2SDmitri Tikhonov 8701c105cf2SDmitri Tikhonov 871747be414SDmitri Tikhonovint 872747be414SDmitri Tikhonovlsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *qdh, void (*func)(void *), 873747be414SDmitri Tikhonov void *ctx) 874747be414SDmitri Tikhonov{ 875747be414SDmitri Tikhonov size_t bytes; 876747be414SDmitri Tikhonov 877747be414SDmitri Tikhonov /* Use size of a single frab list buffer as an arbitrary threshold */ 878747be414SDmitri Tikhonov bytes = lsquic_frab_list_size(&qdh->qdh_fral); 879747be414SDmitri Tikhonov if (bytes <= qdh->qdh_fral.fl_buf_size) 880747be414SDmitri Tikhonov return 0; 881747be414SDmitri Tikhonov else 882747be414SDmitri Tikhonov { 883747be414SDmitri Tikhonov LSQ_DEBUG("have %zu bytes of unsent QPACK decoder stream data: set " 884747be414SDmitri Tikhonov "up callback", bytes); 885747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_func = func; 886747be414SDmitri Tikhonov qdh->qdh_on_dec_sent_ctx = ctx; 887747be414SDmitri Tikhonov return 1; 888747be414SDmitri Tikhonov } 889747be414SDmitri Tikhonov} 8904429f8eaSDmitri Tikhonov 8914429f8eaSDmitri Tikhonov 8924429f8eaSDmitri Tikhonovconst char * 8934429f8eaSDmitri Tikhonovlsquic_qdh_get_ua (const struct qpack_dec_hdl *qdh) 8944429f8eaSDmitri Tikhonov{ 8954429f8eaSDmitri Tikhonov if (qdh->qdh_ua) 8964429f8eaSDmitri Tikhonov return qdh->qdh_ua; 8974429f8eaSDmitri Tikhonov else if (qdh->qdh_exp_rec && qdh->qdh_exp_rec->qer_user_agent) 8984429f8eaSDmitri Tikhonov return qdh->qdh_exp_rec->qer_user_agent; 8994429f8eaSDmitri Tikhonov else 9004429f8eaSDmitri Tikhonov return NULL; 9014429f8eaSDmitri Tikhonov} 902