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