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.
This commit is contained in:
Amaury Denoyelle 2022-02-14 17:13:55 +01:00
parent 0484f92656
commit 7b0f1220d4

185
src/h3.c
View File

@ -93,6 +93,102 @@ static inline size_t h3_decode_frm_header(uint64_t *ftype, uint64_t *flen,
return hlen;
}
/* Parse from buffer <buf> a H3 HEADERS frame of length <len>. Data are copied
* in a local HTX buffer and transfer to the conn-stream layer. <fin> must be
* set if this is the last data to transfer from this stream.
*
* Returns 0 on success else non-zero.
*/
static int h3_headers_to_htx(struct qcs *qcs, struct buffer *buf, uint64_t len,
char fin)
{
struct buffer htx_buf = BUF_NULL;
struct buffer *tmp = get_trash_chunk();
struct htx *htx = NULL;
struct htx_sl *sl;
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 <qcs> remotely initiated bidi-stream. <fin> must be set to indicate
* that we received the last data of the stream.
* Returns <0 on error else 0.
@ -100,13 +196,6 @@ static inline size_t h3_decode_frm_header(uint64_t *ftype, uint64_t *flen,
static int h3_decode_qcs(struct qcs *qcs, int fin, void *ctx)
{
struct buffer *rxbuf = &qcs->rx.buf;
struct h3 *h3 = ctx;
struct htx *htx = NULL;
struct htx_sl *sl;
struct conn_stream *cs;
struct http_hdr list[global.tune.max_http_hdr];
unsigned int flags = HTX_SL_F_NONE;
int hdr_idx;
h3_debug_printf(stderr, "%s: STREAM ID: %llu\n", __func__, qcs->by_id.key);
if (!b_data(rxbuf))
@ -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;