From: Amaury Denoyelle Date: Mon, 14 Feb 2022 16:13:55 +0000 (+0100) Subject: MINOR: h3: extract HEADERS parsing in a dedicated function X-Git-Tag: v2.6-dev2~142 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7b0f1220d41b405e2248d55ba319c16b2ddf347a;p=thirdparty%2Fhaproxy.git MINOR: h3: extract HEADERS parsing in a dedicated function Move the HEADERS parsing code outside of generic h3_decode_qcs to a new dedicated function h3_headers_to_htx. The benefit will be visible when other H3 frames parsing will be implemented such as DATA. --- diff --git a/src/h3.c b/src/h3.c index e3ee84694b..8832229850 100644 --- a/src/h3.c +++ b/src/h3.c @@ -93,21 +93,110 @@ static inline size_t h3_decode_frm_header(uint64_t *ftype, uint64_t *flen, return hlen; } -/* Decode remotely initiated bidi-stream. must be set to indicate - * that we received the last data of the stream. - * Returns <0 on error else 0. +/* Parse from buffer a H3 HEADERS frame of length . Data are copied + * in a local HTX buffer and transfer to the conn-stream layer. must be + * set if this is the last data to transfer from this stream. + * + * Returns 0 on success else non-zero. */ -static int h3_decode_qcs(struct qcs *qcs, int fin, void *ctx) +static int h3_headers_to_htx(struct qcs *qcs, struct buffer *buf, uint64_t len, + char fin) { - struct buffer *rxbuf = &qcs->rx.buf; - struct h3 *h3 = ctx; + struct buffer htx_buf = BUF_NULL; + struct buffer *tmp = get_trash_chunk(); struct htx *htx = NULL; struct htx_sl *sl; - struct conn_stream *cs; struct http_hdr list[global.tune.max_http_hdr]; + struct conn_stream *cs; unsigned int flags = HTX_SL_F_NONE; + struct ist meth = IST_NULL, path = IST_NULL; + //struct ist scheme = IST_NULL, authority = IST_NULL; + struct ist authority = IST_NULL; int hdr_idx; + if (qpack_decode_fs((const unsigned char *)b_head(buf), len, tmp, list) < 0) + return 1; + + qc_get_buf(qcs, &htx_buf); + BUG_ON(!b_size(&htx_buf)); + htx = htx_from_buf(&htx_buf); + + /* first treat pseudo-header to build the start line */ + hdr_idx = 0; + while (1) { + if (isteq(list[hdr_idx].n, ist(""))) + break; + + if (istmatch(list[hdr_idx].n, ist(":"))) { + /* pseudo-header */ + if (isteq(list[hdr_idx].n, ist(":method"))) + meth = list[hdr_idx].v; + else if (isteq(list[hdr_idx].n, ist(":path"))) + path = list[hdr_idx].v; + //else if (isteq(list[hdr_idx].n, ist(":scheme"))) + // scheme = list[hdr_idx].v; + else if (isteq(list[hdr_idx].n, ist(":authority"))) + authority = list[hdr_idx].v; + } + + ++hdr_idx; + } + + flags |= HTX_SL_F_VER_11; + + sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth, path, ist("HTTP/3.0")); + if (!sl) + return 1; + + if (fin) + sl->flags |= HTX_SL_F_BODYLESS; + + sl->info.req.meth = find_http_meth(meth.ptr, meth.len); + BUG_ON(sl->info.req.meth == HTTP_METH_OTHER); + + if (isttest(authority)) + htx_add_header(htx, ist("host"), authority); + + /* now treat standard headers */ + hdr_idx = 0; + while (1) { + if (isteq(list[hdr_idx].n, ist(""))) + break; + + if (!istmatch(list[hdr_idx].n, ist(":"))) + htx_add_header(htx, list[hdr_idx].n, list[hdr_idx].v); + + ++hdr_idx; + } + + htx_add_endof(htx, HTX_BLK_EOH); + htx_to_buf(htx, &htx_buf); + + if (fin) + htx->flags |= HTX_FL_EOM; + + cs = cs_new(qcs->qcc->conn, qcs->qcc->conn->target); + cs->flags |= CS_FL_NOT_FIRST; + cs->ctx = qcs; + stream_create_from_cs(cs, &htx_buf); + + /* buffer is transferred to conn_stream and set to NULL + * except on stream creation error. + */ + b_free(&htx_buf); + offer_buffers(NULL, 1); + + return 0; +} + +/* Decode remotely initiated bidi-stream. must be set to indicate + * that we received the last data of the stream. + * Returns <0 on error else 0. + */ +static int h3_decode_qcs(struct qcs *qcs, int fin, void *ctx) +{ + struct buffer *rxbuf = &qcs->rx.buf; + h3_debug_printf(stderr, "%s: STREAM ID: %llu\n", __func__, qcs->by_id.key); if (!b_data(rxbuf)) return 0; @@ -139,88 +228,8 @@ static int h3_decode_qcs(struct qcs *qcs, int fin, void *ctx) case H3_FT_DATA: break; case H3_FT_HEADERS: - { - const unsigned char *buf = (const unsigned char *)b_head(rxbuf); - struct buffer htx_buf = BUF_NULL; - struct buffer *tmp = get_trash_chunk(); - struct ist meth = IST_NULL, path = IST_NULL; - //struct ist scheme = IST_NULL, authority = IST_NULL; - struct ist authority = IST_NULL; - - if (qpack_decode_fs(buf, flen, tmp, list) < 0) { - h3->err = QPACK_DECOMPRESSION_FAILED; - return -1; - } - - b_alloc(&htx_buf); - htx = htx_from_buf(&htx_buf); - - /* first treat pseudo-header to build the start line */ - hdr_idx = 0; - while (1) { - if (isteq(list[hdr_idx].n, ist(""))) - break; - - if (istmatch(list[hdr_idx].n, ist(":"))) { - /* pseudo-header */ - if (isteq(list[hdr_idx].n, ist(":method"))) - meth = list[hdr_idx].v; - else if (isteq(list[hdr_idx].n, ist(":path"))) - path = list[hdr_idx].v; - //else if (isteq(list[hdr_idx].n, ist(":scheme"))) - // scheme = list[hdr_idx].v; - else if (isteq(list[hdr_idx].n, ist(":authority"))) - authority = list[hdr_idx].v; - } - - ++hdr_idx; - } - - flags |= HTX_SL_F_VER_11; - - sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth, path, ist("HTTP/3.0")); - if (!sl) - goto fail; - - if (last_stream_frame) - sl->flags |= HTX_SL_F_BODYLESS; - - sl->info.req.meth = find_http_meth(meth.ptr, meth.len); - BUG_ON(sl->info.req.meth == HTTP_METH_OTHER); - - if (isttest(authority)) - htx_add_header(htx, ist("host"), authority); - - /* now treat standard headers */ - hdr_idx = 0; - while (1) { - if (isteq(list[hdr_idx].n, ist(""))) - break; - - if (!istmatch(list[hdr_idx].n, ist(":"))) - htx_add_header(htx, list[hdr_idx].n, list[hdr_idx].v); - - ++hdr_idx; - } - - htx_add_endof(htx, HTX_BLK_EOH); - htx_to_buf(htx, &htx_buf); - - if (last_stream_frame) - htx->flags |= HTX_FL_EOM; - - cs = cs_new(qcs->qcc->conn, qcs->qcc->conn->target); - cs->flags |= CS_FL_NOT_FIRST; - cs->ctx = qcs; - stream_create_from_cs(cs, &htx_buf); - - /* buffer is transferred to conn_stream and set to NULL - * except on stream creation error. - */ - b_free(&htx_buf); - + h3_headers_to_htx(qcs, rxbuf, flen, last_stream_frame); break; - } case H3_FT_PUSH_PROMISE: /* Not supported */ break;