lsquic_qdec_hdl.c revision 06b2a236
106b2a236SDmitri Tikhonov/* Copyright (c) 2017 - 2021 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,
3835392f7a3SLiteSpeed Tech            HEC_QPACK_DECODER_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;
45555613f44SDmitri Tikhonov    union hblock_ctx *const u = stream->sm_hblock_ctx;
45655613f44SDmitri Tikhonov    struct qpack_dec_hdl *qdh = u->ctx.qdh;
4575392f7a3SLiteSpeed Tech
4585392f7a3SLiteSpeed Tech    LSQ_DEBUG("header block for stream %"PRIu64" unblocked", stream->id);
4595392f7a3SLiteSpeed Tech    lsquic_stream_qdec_unblocked(stream);
4605392f7a3SLiteSpeed Tech}
4615392f7a3SLiteSpeed Tech
4625392f7a3SLiteSpeed Tech
463747be414SDmitri Tikhonovstruct cont_len
464747be414SDmitri Tikhonov{
465747be414SDmitri Tikhonov    unsigned long long      value;
466747be414SDmitri Tikhonov    int                     has;    /* 1: set, 0: not set, -1: invalid */
467747be414SDmitri Tikhonov};
468747be414SDmitri Tikhonov
469747be414SDmitri Tikhonov
470747be414SDmitri Tikhonovstatic void
471747be414SDmitri Tikhonovprocess_content_length (const struct qpack_dec_hdl *qdh /* for logging */,
472747be414SDmitri Tikhonov            struct cont_len *cl, const char *val /* not NUL-terminated */,
473747be414SDmitri Tikhonov                                                                unsigned len)
474747be414SDmitri Tikhonov{
475747be414SDmitri Tikhonov    char *endcl, cont_len_buf[30];
476747be414SDmitri Tikhonov
477747be414SDmitri Tikhonov    if (0 == cl->has)
478747be414SDmitri Tikhonov    {
479747be414SDmitri Tikhonov        if (len >= sizeof(cont_len_buf))
480747be414SDmitri Tikhonov        {
481747be414SDmitri Tikhonov            LSQ_DEBUG("content-length has invalid value `%.*s'",
482747be414SDmitri Tikhonov                                                            (int) len, val);
483747be414SDmitri Tikhonov            cl->has = -1;
484747be414SDmitri Tikhonov            return;
485747be414SDmitri Tikhonov        }
486747be414SDmitri Tikhonov        memcpy(cont_len_buf, val, len);
487747be414SDmitri Tikhonov        cont_len_buf[len] = '\0';
488747be414SDmitri Tikhonov        cl->value = strtoull(cont_len_buf, &endcl, 10);
489747be414SDmitri Tikhonov        if (*endcl == '\0' && !(ULLONG_MAX == cl->value && ERANGE == errno))
490747be414SDmitri Tikhonov        {
491747be414SDmitri Tikhonov            cl->has = 1;
492747be414SDmitri Tikhonov            LSQ_DEBUG("content length is %llu", cl->value);
493747be414SDmitri Tikhonov        }
494747be414SDmitri Tikhonov        else
495747be414SDmitri Tikhonov        {
496747be414SDmitri Tikhonov            cl->has = -1;
497747be414SDmitri Tikhonov            LSQ_DEBUG("content-length has invalid value `%.*s'",
498747be414SDmitri Tikhonov                (int) len, val);
499747be414SDmitri Tikhonov        }
500747be414SDmitri Tikhonov    }
501747be414SDmitri Tikhonov    else if (cl->has > 0)
502747be414SDmitri Tikhonov    {
503747be414SDmitri Tikhonov        LSQ_DEBUG("header set has two content-length: ambiguous, "
504747be414SDmitri Tikhonov            "turn off checking");
505747be414SDmitri Tikhonov        cl->has = -1;
506747be414SDmitri Tikhonov    }
507747be414SDmitri Tikhonov}
508747be414SDmitri Tikhonov
509747be414SDmitri Tikhonov
510747be414SDmitri Tikhonovstatic int
51155613f44SDmitri Tikhonovis_content_length (const struct lsxpack_header *xhdr)
512747be414SDmitri Tikhonov{
51355613f44SDmitri Tikhonov    return ((xhdr->flags & LSXPACK_QPACK_IDX)
51455613f44SDmitri Tikhonov                        && xhdr->qpack_index == LSQPACK_TNV_CONTENT_LENGTH_0)
51555613f44SDmitri Tikhonov        || (xhdr->name_len == 14 && 0 == memcmp(lsxpack_header_get_name(xhdr),
51655613f44SDmitri Tikhonov                                                        "content-length", 13))
517747be414SDmitri Tikhonov        ;
518747be414SDmitri Tikhonov}
519747be414SDmitri Tikhonov
520747be414SDmitri Tikhonov
521fbc6cc04SDmitri Tikhonovstatic int
522fbc6cc04SDmitri Tikhonovis_priority (const struct lsxpack_header *xhdr)
523fbc6cc04SDmitri Tikhonov{
524fbc6cc04SDmitri Tikhonov    return xhdr->name_len == 8
525fbc6cc04SDmitri Tikhonov        && 0 == memcmp(lsxpack_header_get_name(xhdr), "priority", 8);
526fbc6cc04SDmitri Tikhonov}
527fbc6cc04SDmitri Tikhonov
528fbc6cc04SDmitri Tikhonov
52955613f44SDmitri Tikhonovstatic struct lsxpack_header *
53055613f44SDmitri Tikhonovqdh_prepare_decode (void *stream_p, struct lsxpack_header *xhdr, size_t space)
5315392f7a3SLiteSpeed Tech{
53255613f44SDmitri Tikhonov    struct lsquic_stream *const stream = stream_p;
53355613f44SDmitri Tikhonov    union hblock_ctx *const u = stream->sm_hblock_ctx;
53455613f44SDmitri Tikhonov    struct qpack_dec_hdl *const qdh = u->ctx.qdh;
53555613f44SDmitri Tikhonov
53655613f44SDmitri Tikhonov    return qdh->qdh_enpub->enp_hsi_if->hsi_prepare_decode(
53755613f44SDmitri Tikhonov                                                u->ctx.hset, xhdr, space);
53855613f44SDmitri Tikhonov}
5395392f7a3SLiteSpeed Tech
5405392f7a3SLiteSpeed Tech
541758aff32SDmitri Tikhonovstatic void
542758aff32SDmitri Tikhonovqdh_maybe_set_user_agent (struct qpack_dec_hdl *qdh,
5434429f8eaSDmitri Tikhonov                                const struct lsxpack_header *xhdr, char **ua)
544758aff32SDmitri Tikhonov{
545758aff32SDmitri Tikhonov    /* Flipped: we are the *decoder* */
5464429f8eaSDmitri Tikhonov    const char *const name = qdh->qdh_flags & QDH_SERVER ?
547758aff32SDmitri Tikhonov                                    "user-agent" : "server";
5484429f8eaSDmitri Tikhonov    const size_t len = qdh->qdh_flags & QDH_SERVER ? 10 : 6;
549758aff32SDmitri Tikhonov
550758aff32SDmitri Tikhonov    if (len == xhdr->name_len
551758aff32SDmitri Tikhonov                && 0 == memcmp(name, lsxpack_header_get_name(xhdr), len))
5524429f8eaSDmitri Tikhonov        *ua = strndup(lsxpack_header_get_value(xhdr), xhdr->val_len);
553758aff32SDmitri Tikhonov}
554758aff32SDmitri Tikhonov
555758aff32SDmitri Tikhonov
55655613f44SDmitri Tikhonovstatic int
55755613f44SDmitri Tikhonovqdh_process_header (void *stream_p, struct lsxpack_header *xhdr)
55855613f44SDmitri Tikhonov{
55955613f44SDmitri Tikhonov    struct lsquic_stream *const stream = stream_p;
56055613f44SDmitri Tikhonov    union hblock_ctx *const u = stream->sm_hblock_ctx;
56155613f44SDmitri Tikhonov    struct qpack_dec_hdl *const qdh = u->ctx.qdh;
56255613f44SDmitri Tikhonov    struct cont_len cl;
5635392f7a3SLiteSpeed Tech
56455613f44SDmitri Tikhonov    if (is_content_length(xhdr))
5655392f7a3SLiteSpeed Tech    {
56655613f44SDmitri Tikhonov        cl.has = 0;
56755613f44SDmitri Tikhonov        process_content_length(qdh, &cl, lsxpack_header_get_value(xhdr),
56855613f44SDmitri Tikhonov                                                            xhdr->val_len);
56955613f44SDmitri Tikhonov        if (cl.has > 0)
57055613f44SDmitri Tikhonov            (void) lsquic_stream_verify_len(stream, cl.value);
5715392f7a3SLiteSpeed Tech    }
572fbc6cc04SDmitri Tikhonov    else if ((stream->sm_bflags & (SMBF_HTTP_PRIO|SMBF_HPRIO_SET))
573fbc6cc04SDmitri Tikhonov                                                            == SMBF_HTTP_PRIO
574fbc6cc04SDmitri Tikhonov            && is_priority(xhdr))
575fbc6cc04SDmitri Tikhonov    {
576fbc6cc04SDmitri Tikhonov        u->ctx.ppc_flags &= ~(PPC_INC_NAME|PPC_URG_NAME);
577fbc6cc04SDmitri Tikhonov        (void) lsquic_http_parse_pfv(lsxpack_header_get_value(xhdr),
578fbc6cc04SDmitri Tikhonov                        xhdr->val_len, &u->ctx.ppc_flags, &u->ctx.ehp,
579fbc6cc04SDmitri Tikhonov                        (char *) stream->conn_pub->mm->acki,
580fbc6cc04SDmitri Tikhonov                        sizeof(*stream->conn_pub->mm->acki));
581fbc6cc04SDmitri Tikhonov    }
582758aff32SDmitri Tikhonov    else if (qdh->qdh_exp_rec && !qdh->qdh_exp_rec->qer_user_agent)
5834429f8eaSDmitri Tikhonov        qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_exp_rec->qer_user_agent);
5844429f8eaSDmitri Tikhonov    else if ((qdh->qdh_flags & QDH_SAVE_UA) && !qdh->qdh_ua)
5854429f8eaSDmitri Tikhonov        qdh_maybe_set_user_agent(qdh, xhdr, &qdh->qdh_ua);
5865392f7a3SLiteSpeed Tech
58755613f44SDmitri Tikhonov    return qdh->qdh_enpub->enp_hsi_if->hsi_process_header(u->ctx.hset, xhdr);
5885392f7a3SLiteSpeed Tech}
5895392f7a3SLiteSpeed Tech
5905392f7a3SLiteSpeed Tech
59155613f44SDmitri Tikhonovstatic const struct lsqpack_dec_hset_if dhi_if =
59202b6086dSDmitri Tikhonov{
59355613f44SDmitri Tikhonov    .dhi_unblocked      = qdh_hblock_unblocked,
59455613f44SDmitri Tikhonov    .dhi_prepare_decode = qdh_prepare_decode,
59555613f44SDmitri Tikhonov    .dhi_process_header = qdh_process_header,
59655613f44SDmitri Tikhonov};
59702b6086dSDmitri Tikhonov
59802b6086dSDmitri Tikhonov
5994580fab7SDmitri Tikhonovstatic void
6004580fab7SDmitri Tikhonovqdh_maybe_destroy_hblock_ctx (struct qpack_dec_hdl *qdh,
6014580fab7SDmitri Tikhonov                                                struct lsquic_stream *stream)
6024580fab7SDmitri Tikhonov{
6034580fab7SDmitri Tikhonov    if (stream->sm_hblock_ctx)
6044580fab7SDmitri Tikhonov    {
6054580fab7SDmitri Tikhonov        LSQ_DEBUG("destroy hblock_ctx of stream %"PRIu64, stream->id);
6064580fab7SDmitri Tikhonov        qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(
6074580fab7SDmitri Tikhonov                                            stream->sm_hblock_ctx->ctx.hset);
6084580fab7SDmitri Tikhonov        free(stream->sm_hblock_ctx);
6094580fab7SDmitri Tikhonov        stream->sm_hblock_ctx = NULL;
6104580fab7SDmitri Tikhonov    }
6114580fab7SDmitri Tikhonov}
6124580fab7SDmitri Tikhonov
6134580fab7SDmitri Tikhonov
6145392f7a3SLiteSpeed Techstatic enum lsqpack_read_header_status
6155392f7a3SLiteSpeed Techqdh_header_read_results (struct qpack_dec_hdl *qdh,
6165392f7a3SLiteSpeed Tech        struct lsquic_stream *stream, enum lsqpack_read_header_status rhs,
61755613f44SDmitri Tikhonov        const unsigned char *dec_buf, size_t dec_buf_sz)
6185392f7a3SLiteSpeed Tech{
6195392f7a3SLiteSpeed Tech    const struct lsqpack_dec_err *qerr;
62055613f44SDmitri Tikhonov    struct uncompressed_headers *uh;
62155613f44SDmitri Tikhonov    void *hset;
6225392f7a3SLiteSpeed Tech
6235392f7a3SLiteSpeed Tech    if (rhs == LQRHS_DONE)
6245392f7a3SLiteSpeed Tech    {
62555613f44SDmitri Tikhonov        if (!lsquic_stream_header_is_trailer(stream))
6265392f7a3SLiteSpeed Tech        {
627fbc6cc04SDmitri Tikhonov            if (stream->sm_hblock_ctx->ctx.ppc_flags
628fbc6cc04SDmitri Tikhonov                                                & (PPC_INC_SET|PPC_URG_SET))
629fbc6cc04SDmitri Tikhonov            {
630fbc6cc04SDmitri Tikhonov                assert(stream->sm_bflags & SMBF_HTTP_PRIO);
631fbc6cc04SDmitri Tikhonov                LSQ_DEBUG("Apply Priority from headers to stream %"PRIu64,
632fbc6cc04SDmitri Tikhonov                                                                stream->id);
633fbc6cc04SDmitri Tikhonov                (void) lsquic_stream_set_http_prio(stream,
634fbc6cc04SDmitri Tikhonov                                            &stream->sm_hblock_ctx->ctx.ehp);
635fbc6cc04SDmitri Tikhonov            }
63655613f44SDmitri Tikhonov            hset = stream->sm_hblock_ctx->ctx.hset;
6374580fab7SDmitri Tikhonov            uh = (void *) stream->sm_hblock_ctx;
63855613f44SDmitri Tikhonov            stream->sm_hblock_ctx = NULL;
63955613f44SDmitri Tikhonov            memset(uh, 0, sizeof(*uh));
64055613f44SDmitri Tikhonov            uh->uh_stream_id = stream->id;
64155613f44SDmitri Tikhonov            uh->uh_oth_stream_id = 0;
64255613f44SDmitri Tikhonov            uh->uh_weight = 0;
64355613f44SDmitri Tikhonov            uh->uh_exclusive = -1;
64455613f44SDmitri Tikhonov            if (qdh->qdh_enpub->enp_hsi_if == lsquic_http1x_if)
64555613f44SDmitri Tikhonov                uh->uh_flags    |= UH_H1H;
64655613f44SDmitri Tikhonov            if (0 != qdh->qdh_enpub->enp_hsi_if
64755613f44SDmitri Tikhonov                                        ->hsi_process_header(hset, NULL))
64855613f44SDmitri Tikhonov            {
6494580fab7SDmitri Tikhonov                LSQ_DEBUG("finishing hset failed");
65055613f44SDmitri Tikhonov                free(uh);
6514580fab7SDmitri Tikhonov                qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(hset);
6525392f7a3SLiteSpeed Tech                return LQRHS_ERROR;
65355613f44SDmitri Tikhonov            }
65455613f44SDmitri Tikhonov            uh->uh_hset = hset;
65555613f44SDmitri Tikhonov            if (0 == lsquic_stream_uh_in(stream, uh))
65655613f44SDmitri Tikhonov                LSQ_DEBUG("gave hset to stream %"PRIu64, stream->id);
65755613f44SDmitri Tikhonov            else
6585392f7a3SLiteSpeed Tech            {
65955613f44SDmitri Tikhonov                LSQ_DEBUG("could not give hset to stream %"PRIu64, stream->id);
66055613f44SDmitri Tikhonov                free(uh);
6614580fab7SDmitri Tikhonov                qdh->qdh_enpub->enp_hsi_if->hsi_discard_header_set(hset);
66255613f44SDmitri Tikhonov                return LQRHS_ERROR;
6635392f7a3SLiteSpeed Tech            }
6645392f7a3SLiteSpeed Tech        }
6655392f7a3SLiteSpeed Tech        else
6665392f7a3SLiteSpeed Tech        {
66755613f44SDmitri Tikhonov            LSQ_DEBUG("discard trailer header set");
6684580fab7SDmitri Tikhonov            qdh_maybe_destroy_hblock_ctx(qdh, stream);
66955613f44SDmitri Tikhonov        }
67055613f44SDmitri Tikhonov        if (qdh->qdh_dec_sm_out)
67155613f44SDmitri Tikhonov        {
67255613f44SDmitri Tikhonov            if (dec_buf_sz
67355613f44SDmitri Tikhonov                && 0 != qdh_write_decoder(qdh, dec_buf, dec_buf_sz))
67455613f44SDmitri Tikhonov            {
67555613f44SDmitri Tikhonov                return LQRHS_ERROR;
67655613f44SDmitri Tikhonov            }
67755613f44SDmitri Tikhonov            if (dec_buf_sz || lsqpack_dec_ici_pending(&qdh->qdh_decoder))
67855613f44SDmitri Tikhonov                lsquic_stream_wantwrite(qdh->qdh_dec_sm_out, 1);
6795392f7a3SLiteSpeed Tech        }
6805392f7a3SLiteSpeed Tech    }
6815392f7a3SLiteSpeed Tech    else if (rhs == LQRHS_ERROR)
6825392f7a3SLiteSpeed Tech    {
6834580fab7SDmitri Tikhonov        qdh_maybe_destroy_hblock_ctx(qdh, stream);
6845392f7a3SLiteSpeed Tech        qerr = lsqpack_dec_get_err_info(&qdh->qdh_decoder);
6855392f7a3SLiteSpeed Tech        qdh->qdh_conn->cn_if->ci_abort_error(qdh->qdh_conn, 1,
6865392f7a3SLiteSpeed Tech            HEC_QPACK_DECOMPRESSION_FAILED, "QPACK decompression error; "
6875392f7a3SLiteSpeed Tech            "stream %"PRIu64", offset %"PRIu64", line %d", qerr->stream_id,
6885392f7a3SLiteSpeed Tech            qerr->off, qerr->line);
6895392f7a3SLiteSpeed Tech    }
6905392f7a3SLiteSpeed Tech
6915392f7a3SLiteSpeed Tech    return rhs;
6925392f7a3SLiteSpeed Tech}
6935392f7a3SLiteSpeed Tech
6945392f7a3SLiteSpeed Tech
6955392f7a3SLiteSpeed Techenum lsqpack_read_header_status
6965392f7a3SLiteSpeed Techlsquic_qdh_header_in_begin (struct qpack_dec_hdl *qdh,
6975392f7a3SLiteSpeed Tech                        struct lsquic_stream *stream, uint64_t header_size,
6985392f7a3SLiteSpeed Tech                        const unsigned char **buf, size_t bufsz)
6995392f7a3SLiteSpeed Tech{
7005392f7a3SLiteSpeed Tech    enum lsqpack_read_header_status rhs;
70155613f44SDmitri Tikhonov    void *hset;
70255613f44SDmitri Tikhonov    int is_pp;
7035392f7a3SLiteSpeed Tech    size_t dec_buf_sz;
70455613f44SDmitri Tikhonov    union hblock_ctx *u;
7055392f7a3SLiteSpeed Tech    unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK];
7065392f7a3SLiteSpeed Tech
7071c105cf2SDmitri Tikhonov    assert(!(stream->stream_flags & STREAM_U_READ_DONE));
7081c105cf2SDmitri Tikhonov
70955613f44SDmitri Tikhonov    if (!(qdh->qdh_flags & QDH_INITIALIZED))
7105392f7a3SLiteSpeed Tech    {
71155613f44SDmitri Tikhonov        LSQ_WARN("not initialized: cannot process header block");
71255613f44SDmitri Tikhonov        return LQRHS_ERROR;
7135392f7a3SLiteSpeed Tech    }
71455613f44SDmitri Tikhonov
71555613f44SDmitri Tikhonov    u = malloc(sizeof(*u));
71655613f44SDmitri Tikhonov    if (!u)
7175392f7a3SLiteSpeed Tech    {
71855613f44SDmitri Tikhonov        LSQ_INFO("cannot allocate hblock_ctx");
71955613f44SDmitri Tikhonov        return LQRHS_ERROR;
72055613f44SDmitri Tikhonov    }
72155613f44SDmitri Tikhonov
72255613f44SDmitri Tikhonov    is_pp = lsquic_stream_header_is_pp(stream);
72355613f44SDmitri Tikhonov    hset = qdh->qdh_enpub->enp_hsi_if->hsi_create_header_set(
72455613f44SDmitri Tikhonov                                          qdh->qdh_hsi_ctx, stream, is_pp);
72555613f44SDmitri Tikhonov    if (!hset)
72655613f44SDmitri Tikhonov    {
72755613f44SDmitri Tikhonov        free(u);
72855613f44SDmitri Tikhonov        LSQ_DEBUG("hsi_create_header_set failure");
7295392f7a3SLiteSpeed Tech        return LQRHS_ERROR;
7305392f7a3SLiteSpeed Tech    }
7315392f7a3SLiteSpeed Tech
73255613f44SDmitri Tikhonov    u->ctx.hset   = hset;
73355613f44SDmitri Tikhonov    u->ctx.qdh    = qdh;
734fbc6cc04SDmitri Tikhonov    u->ctx.ppc_flags = 0;
735fbc6cc04SDmitri Tikhonov    u->ctx.ehp       = (struct lsquic_ext_http_prio) {
736fbc6cc04SDmitri Tikhonov                            .urgency     = LSQUIC_DEF_HTTP_URGENCY,
737fbc6cc04SDmitri Tikhonov                            .incremental = LSQUIC_DEF_HTTP_INCREMENTAL,
738fbc6cc04SDmitri Tikhonov    };
73955613f44SDmitri Tikhonov    stream->sm_hblock_ctx = u;
74055613f44SDmitri Tikhonov
741758aff32SDmitri Tikhonov    if (qdh->qdh_exp_rec)
742758aff32SDmitri Tikhonov    {
743758aff32SDmitri Tikhonov        const lsquic_time_t now = lsquic_time_now();
744758aff32SDmitri Tikhonov        if (0 == qdh->qdh_exp_rec->qer_hblock_count)
745758aff32SDmitri Tikhonov            qdh->qdh_exp_rec->qer_first_req = now;
746758aff32SDmitri Tikhonov        qdh->qdh_exp_rec->qer_last_req = now;
747758aff32SDmitri Tikhonov        ++qdh->qdh_exp_rec->qer_hblock_count;
748758aff32SDmitri Tikhonov        qdh->qdh_exp_rec->qer_hblock_size += bufsz;
749758aff32SDmitri Tikhonov    }
750758aff32SDmitri Tikhonov
75155613f44SDmitri Tikhonov    dec_buf_sz = sizeof(dec_buf);
75255613f44SDmitri Tikhonov    rhs = lsqpack_dec_header_in(&qdh->qdh_decoder, stream, stream->id,
75355613f44SDmitri Tikhonov                    header_size, buf, bufsz, dec_buf, &dec_buf_sz);
754758aff32SDmitri Tikhonov    if (qdh->qdh_exp_rec)
755758aff32SDmitri Tikhonov        qdh->qdh_exp_rec->qer_peer_max_blocked += rhs == LQRHS_BLOCKED;
75655613f44SDmitri Tikhonov    return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz);
7575392f7a3SLiteSpeed Tech}
7585392f7a3SLiteSpeed Tech
7595392f7a3SLiteSpeed Tech
7605392f7a3SLiteSpeed Techenum lsqpack_read_header_status
7615392f7a3SLiteSpeed Techlsquic_qdh_header_in_continue (struct qpack_dec_hdl *qdh,
7625392f7a3SLiteSpeed Tech        struct lsquic_stream *stream, const unsigned char **buf, size_t bufsz)
7635392f7a3SLiteSpeed Tech{
7645392f7a3SLiteSpeed Tech    enum lsqpack_read_header_status rhs;
7655392f7a3SLiteSpeed Tech    size_t dec_buf_sz;
7665392f7a3SLiteSpeed Tech    unsigned char dec_buf[LSQPACK_LONGEST_HEADER_ACK];
7675392f7a3SLiteSpeed Tech
7681c105cf2SDmitri Tikhonov    assert(!(stream->stream_flags & STREAM_U_READ_DONE));
7691c105cf2SDmitri Tikhonov
7705392f7a3SLiteSpeed Tech    if (qdh->qdh_flags & QDH_INITIALIZED)
7715392f7a3SLiteSpeed Tech    {
772758aff32SDmitri Tikhonov        if (qdh->qdh_exp_rec)
773758aff32SDmitri Tikhonov            qdh->qdh_exp_rec->qer_hblock_size += bufsz;
7745392f7a3SLiteSpeed Tech        dec_buf_sz = sizeof(dec_buf);
7755392f7a3SLiteSpeed Tech        rhs = lsqpack_dec_header_read(&qdh->qdh_decoder, stream,
77655613f44SDmitri Tikhonov                                    buf, bufsz, dec_buf, &dec_buf_sz);
777758aff32SDmitri Tikhonov        if (qdh->qdh_exp_rec)
778758aff32SDmitri Tikhonov            qdh->qdh_exp_rec->qer_peer_max_blocked += rhs == LQRHS_BLOCKED;
77955613f44SDmitri Tikhonov        return qdh_header_read_results(qdh, stream, rhs, dec_buf, dec_buf_sz);
7805392f7a3SLiteSpeed Tech    }
7815392f7a3SLiteSpeed Tech    else
7825392f7a3SLiteSpeed Tech    {
7835392f7a3SLiteSpeed Tech        LSQ_WARN("not initialized: cannot process header block");
7845392f7a3SLiteSpeed Tech        return LQRHS_ERROR;
7855392f7a3SLiteSpeed Tech    }
7865392f7a3SLiteSpeed Tech}
7875392f7a3SLiteSpeed Tech
7885392f7a3SLiteSpeed Tech
7891c105cf2SDmitri Tikhonovstatic void
7905392f7a3SLiteSpeed Techlsquic_qdh_unref_stream (struct qpack_dec_hdl *qdh,
7915392f7a3SLiteSpeed Tech                                                struct lsquic_stream *stream)
7925392f7a3SLiteSpeed Tech{
7935392f7a3SLiteSpeed Tech    if (0 == lsqpack_dec_unref_stream(&qdh->qdh_decoder, stream))
7945392f7a3SLiteSpeed Tech        LSQ_DEBUG("unreffed stream %"PRIu64, stream->id);
7955392f7a3SLiteSpeed Tech    else
7965392f7a3SLiteSpeed Tech        LSQ_WARN("cannot unref stream %"PRIu64, stream->id);
7975392f7a3SLiteSpeed Tech}
7985392f7a3SLiteSpeed Tech
7995392f7a3SLiteSpeed Tech
8005392f7a3SLiteSpeed Techvoid
8015392f7a3SLiteSpeed Techlsquic_qdh_cancel_stream (struct qpack_dec_hdl *qdh,
8025392f7a3SLiteSpeed Tech                                                struct lsquic_stream *stream)
8035392f7a3SLiteSpeed Tech{
8045392f7a3SLiteSpeed Tech    ssize_t nw;
8055392f7a3SLiteSpeed Tech    unsigned char buf[LSQPACK_LONGEST_CANCEL];
8065392f7a3SLiteSpeed Tech
8074580fab7SDmitri Tikhonov    qdh_maybe_destroy_hblock_ctx(qdh, stream);
8084580fab7SDmitri Tikhonov
8091c105cf2SDmitri Tikhonov    if (!qdh->qdh_dec_sm_out)
8101c105cf2SDmitri Tikhonov        return;
8111c105cf2SDmitri Tikhonov
8125392f7a3SLiteSpeed Tech    nw = lsqpack_dec_cancel_stream(&qdh->qdh_decoder, stream, buf, sizeof(buf));
8135392f7a3SLiteSpeed Tech    if (nw > 0)
8145392f7a3SLiteSpeed Tech    {
8155392f7a3SLiteSpeed Tech        if (0 == qdh_write_decoder(qdh, buf, nw))
8165392f7a3SLiteSpeed Tech            LSQ_DEBUG("cancelled stream %"PRIu64" and wrote %zd-byte Cancel "
8175392f7a3SLiteSpeed Tech                "Stream instruction to the decoder stream", stream->id, nw);
8185392f7a3SLiteSpeed Tech    }
8195392f7a3SLiteSpeed Tech    else if (nw == 0)
8205392f7a3SLiteSpeed Tech        LSQ_WARN("cannot cancel stream %"PRIu64" -- not found", stream->id);
8215392f7a3SLiteSpeed Tech    else
8225392f7a3SLiteSpeed Tech    {
8235392f7a3SLiteSpeed Tech        LSQ_WARN("cannot cancel stream %"PRIu64" -- not enough buffer space "
8245392f7a3SLiteSpeed Tech            "to encode Cancel Stream instructin", stream->id);
8255392f7a3SLiteSpeed Tech        lsquic_qdh_unref_stream(qdh, stream);
8265392f7a3SLiteSpeed Tech    }
8275392f7a3SLiteSpeed Tech}
828747be414SDmitri Tikhonov
829747be414SDmitri Tikhonov
8301c105cf2SDmitri Tikhonovvoid
8311c105cf2SDmitri Tikhonovlsquic_qdh_cancel_stream_id (struct qpack_dec_hdl *qdh,
8321c105cf2SDmitri Tikhonov                                                lsquic_stream_id_t stream_id)
8331c105cf2SDmitri Tikhonov{
8341c105cf2SDmitri Tikhonov    ssize_t nw;
8351c105cf2SDmitri Tikhonov    unsigned char buf[LSQPACK_LONGEST_CANCEL];
8361c105cf2SDmitri Tikhonov
8371c105cf2SDmitri Tikhonov    if (!qdh->qdh_dec_sm_out)
8381c105cf2SDmitri Tikhonov        return;
8391c105cf2SDmitri Tikhonov
8401c105cf2SDmitri Tikhonov    nw = lsqpack_dec_cancel_stream_id(&qdh->qdh_decoder, stream_id, buf,
8411c105cf2SDmitri Tikhonov                                                                sizeof(buf));
8421c105cf2SDmitri Tikhonov    if (nw > 0)
8431c105cf2SDmitri Tikhonov    {
8441c105cf2SDmitri Tikhonov        if (0 == qdh_write_decoder(qdh, buf, nw))
8458dc2321bSDarrin Smart            LSQ_DEBUG("wrote %zd-byte Cancel Stream instruction for "
8468dc2321bSDarrin Smart                "stream %"PRIu64" to the decoder stream", nw, stream_id);
8471c105cf2SDmitri Tikhonov    }
8481c105cf2SDmitri Tikhonov    else if (nw == 0)
8491c105cf2SDmitri Tikhonov        LSQ_DEBUG("not generating Cancel Stream instruction for "
8501c105cf2SDmitri Tikhonov            "stream %"PRIu64, stream_id);
8511c105cf2SDmitri Tikhonov    else
8521c105cf2SDmitri Tikhonov        LSQ_WARN("cannot generate Cancel Stream instruction for "
8531c105cf2SDmitri Tikhonov            "stream %"PRIu64" -- not enough buffer space", stream_id);
8541c105cf2SDmitri Tikhonov}
8551c105cf2SDmitri Tikhonov
8561c105cf2SDmitri Tikhonov
857747be414SDmitri Tikhonovint
858747be414SDmitri Tikhonovlsquic_qdh_arm_if_unsent (struct qpack_dec_hdl *qdh, void (*func)(void *),
859747be414SDmitri Tikhonov                                                                    void *ctx)
860747be414SDmitri Tikhonov{
861747be414SDmitri Tikhonov    size_t bytes;
862747be414SDmitri Tikhonov
863747be414SDmitri Tikhonov    /* Use size of a single frab list buffer as an arbitrary threshold */
864747be414SDmitri Tikhonov    bytes = lsquic_frab_list_size(&qdh->qdh_fral);
865747be414SDmitri Tikhonov    if (bytes <= qdh->qdh_fral.fl_buf_size)
866747be414SDmitri Tikhonov        return 0;
867747be414SDmitri Tikhonov    else
868747be414SDmitri Tikhonov    {
869747be414SDmitri Tikhonov        LSQ_DEBUG("have %zu bytes of unsent QPACK decoder stream data: set "
870747be414SDmitri Tikhonov            "up callback", bytes);
871747be414SDmitri Tikhonov        qdh->qdh_on_dec_sent_func = func;
872747be414SDmitri Tikhonov        qdh->qdh_on_dec_sent_ctx  = ctx;
873747be414SDmitri Tikhonov        return 1;
874747be414SDmitri Tikhonov    }
875747be414SDmitri Tikhonov}
8764429f8eaSDmitri Tikhonov
8774429f8eaSDmitri Tikhonov
8784429f8eaSDmitri Tikhonovconst char *
8794429f8eaSDmitri Tikhonovlsquic_qdh_get_ua (const struct qpack_dec_hdl *qdh)
8804429f8eaSDmitri Tikhonov{
8814429f8eaSDmitri Tikhonov    if (qdh->qdh_ua)
8824429f8eaSDmitri Tikhonov        return qdh->qdh_ua;
8834429f8eaSDmitri Tikhonov    else if (qdh->qdh_exp_rec && qdh->qdh_exp_rec->qer_user_agent)
8844429f8eaSDmitri Tikhonov        return qdh->qdh_exp_rec->qer_user_agent;
8854429f8eaSDmitri Tikhonov    else
8864429f8eaSDmitri Tikhonov        return NULL;
8874429f8eaSDmitri Tikhonov}
888