From f1ba18d7b3b8104b42615ee85c7432ec04456be5 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 26 Nov 2018 21:37:08 +0100 Subject: [PATCH] MEDIUM: htx: Don't rely on h1_sl anymore except during H1 header parsing Instead, we now use the htx_sl coming from the HTX message. It avoids to have too H1 specific code in version-agnostic parts. Of course, the concept of the start-line is higly influenced by the H1, but the structure htx_sl can be adapted, if necessary. And many things depend on a start-line during HTTP analyzis. Using the structure htx_sl also avoid boring conversions between HTX version and H1 version. --- include/proto/http_htx.h | 5 +- include/proto/htx.h | 13 +-- src/http_fetch.c | 107 ++++++++++++-------- src/http_htx.c | 211 +++++++++++++++------------------------ src/htx.c | 144 +++++++++----------------- src/mux_h1.c | 56 +++++++++-- src/proto_htx.c | 120 +++++++++++----------- src/stats.c | 25 +++-- 8 files changed, 315 insertions(+), 366 deletions(-) diff --git a/include/proto/http_htx.h b/include/proto/http_htx.h index 7a6d476b57..9afea5c99e 100644 --- a/include/proto/http_htx.h +++ b/include/proto/http_htx.h @@ -28,11 +28,10 @@ #include #include -union h1_sl http_find_stline(const struct htx *htx); +struct htx_sl *http_find_stline(struct htx *htx); int http_find_header(const struct htx *htx, const struct ist name, struct http_hdr_ctx *ctx, int full); int http_add_header(struct htx *htx, const struct ist n, const struct ist v); -int http_replace_reqline(struct htx *htx, const union h1_sl sl); -int http_replace_resline(struct htx *htx, const union h1_sl sl); +int http_replace_stline(struct htx *htx, const struct ist p1, const struct ist p2, const struct ist p3); int http_replace_req_meth(struct htx *htx, const struct ist meth); int http_replace_req_uri(struct htx *htx, const struct ist uri); int http_replace_req_path(struct htx *htx, const struct ist path); diff --git a/include/proto/htx.h b/include/proto/htx.h index 296ff4df55..9ee71e573d 100644 --- a/include/proto/htx.h +++ b/include/proto/htx.h @@ -26,8 +26,6 @@ #include #include #include - -#include #include extern struct htx htx_empty; @@ -41,15 +39,14 @@ struct htx_blk *htx_replace_blk_value(struct htx *htx, struct htx_blk *blk, struct htx_ret htx_xfer_blks(struct htx *dst, struct htx *src, uint32_t count, enum htx_blk_type mark); -struct htx_blk *htx_replace_reqline(struct htx *htx, struct htx_blk *blk, - const union h1_sl sl); -struct htx_blk *htx_replace_resline(struct htx *htx, struct htx_blk *blk, - const union h1_sl sl); +struct htx_sl *htx_add_stline(struct htx *htx, enum htx_blk_type type, unsigned int flags, + const struct ist p1, const struct ist p2, const struct ist p3); +struct htx_sl *htx_replace_stline(struct htx *htx, struct htx_blk *blk, const struct ist p1, + const struct ist p2, const struct ist p3); + struct htx_blk *htx_replace_header(struct htx *htx, struct htx_blk *blk, const struct ist name, const struct ist value); -struct htx_blk *htx_add_reqline(struct htx *htx, const union h1_sl sl); -struct htx_blk *htx_add_resline(struct htx *htx, const union h1_sl sl); struct htx_blk *htx_add_header(struct htx *htx, const struct ist name, const struct ist value); struct htx_blk *htx_add_all_headers(struct htx *htx, const struct http_hdr *hdrs); struct htx_blk *htx_add_pseudo_header(struct htx *htx, enum htx_phdr_type phdr, const struct ist value); diff --git a/src/http_fetch.c b/src/http_fetch.c index 3890509596..884a320497 100644 --- a/src/http_fetch.c +++ b/src/http_fetch.c @@ -173,6 +173,7 @@ struct htx *smp_prefetch_htx(struct sample *smp, const struct arg *args) unsigned int opt = smp->opt; struct http_txn *txn = NULL; struct htx *htx = NULL; + struct htx_sl *sl; /* Note: it is possible that is NULL when called before stream * initialization (eg: tcp-request connection), so this function is the @@ -190,8 +191,6 @@ struct htx *smp_prefetch_htx(struct sample *smp, const struct arg *args) if (px->mode == PR_MODE_HTTP) { if ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) { - union h1_sl sl; - htx = htx_from_buf(&s->req.buf); if (htx_is_empty(htx) || htx_get_tail_type(htx) < HTX_BLK_EOH) { /* Parsing is done by the mux, just wait */ @@ -205,7 +204,7 @@ struct htx *smp_prefetch_htx(struct sample *smp, const struct arg *args) */ if (txn) { sl = http_find_stline(htx); - txn->meth = sl.rq.meth; + txn->meth = sl->info.req.meth; if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD) s->flags |= SF_REDIRECTABLE; } @@ -226,7 +225,8 @@ struct htx *smp_prefetch_htx(struct sample *smp, const struct arg *args) struct buffer *buf; struct h1m h1m; struct http_hdr hdrs[MAX_HTTP_HDR]; - union h1_sl sl; + union h1_sl h1sl; + unsigned int flags = HTX_FL_NONE; int ret; buf = &s->req.buf; @@ -235,7 +235,7 @@ struct htx *smp_prefetch_htx(struct sample *smp, const struct arg *args) h1m_init_req(&h1m); ret = h1_headers_to_hdr_list(b_head(buf), b_stop(buf), - hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &h1m, &sl); + hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &h1m, &h1sl); if (ret <= 0) { /* Invalid or too big*/ if (ret < 0 || channel_full(&s->req, global.tune.maxrewrite)) @@ -249,18 +249,39 @@ struct htx *smp_prefetch_htx(struct sample *smp, const struct arg *args) /* OK we just got a valid HTTP request. We have to * convert it into an HTX message. */ - if (unlikely(sl.rq.v.len == 0)) { + if (unlikely(h1sl.rq.v.len == 0)) { /* try to convert HTTP/0.9 requests to HTTP/1.0 */ - if (sl.rq.meth != HTTP_METH_GET || !sl.rq.u.len) + if (h1sl.rq.meth != HTTP_METH_GET || !h1sl.rq.u.len) return NULL; - sl.rq.v = ist("HTTP/1.0"); + h1sl.rq.v = ist("HTTP/1.0"); + } + else if ((h1sl.rq.v.len == 8) && + ((*(h1sl.rq.v.ptr + 5) > '1') || + ((*(h1sl.rq.v.ptr + 5) == '1') && (*(h1sl.rq.v.ptr + 7) >= '1')))) + h1m.flags |= H1_MF_VER_11; + + + /* Set HTX start-line flags */ + if (h1m.flags & H1_MF_VER_11) + flags |= HTX_SL_F_VER_11; + if (h1m.flags & H1_MF_XFER_ENC) + flags |= HTX_SL_F_XFER_ENC; + if (h1m.flags & H1_MF_XFER_LEN) { + flags |= HTX_SL_F_XFER_LEN; + if (h1m.flags & H1_MF_CHNK) + flags |= HTX_SL_F_CHNK; + else if (h1m.flags & H1_MF_CLEN) + flags |= HTX_SL_F_CLEN; } + htx = htx_from_buf(get_trash_chunk()); - if (!htx_add_reqline(htx, sl) || !htx_add_all_headers(htx, hdrs)) + sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, h1sl.rq.m, h1sl.rq.u, h1sl.rq.v); + if (!sl || !htx_add_all_headers(htx, hdrs)) return NULL; + sl->info.req.meth = h1sl.rq.meth; if (txn) { - txn->meth = sl.rq.meth; + txn->meth = h1sl.rq.meth; if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD) s->flags |= SF_REDIRECTABLE; } @@ -411,7 +432,7 @@ static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char smp->data.type = SMP_T_METH; smp->data.u.meth.meth = meth; if (meth == HTTP_METH_OTHER) { - union h1_sl sl; + struct htx_sl *sl; if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE) /* ensure the indexes are not affected */ @@ -419,8 +440,8 @@ static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char sl = http_find_stline(htx); smp->flags |= SMP_F_CONST; - smp->data.u.meth.str.area = sl.rq.m.ptr; - smp->data.u.meth.str.data = sl.rq.m.len; + smp->data.u.meth.str.area = HTX_SL_REQ_MPTR(sl); + smp->data.u.meth.str.data = HTX_SL_REQ_MLEN(sl); } smp->flags |= SMP_F_VOL_1ST; } @@ -454,14 +475,14 @@ static int smp_fetch_rqver(const struct arg *args, struct sample *smp, const cha if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; if (!htx) return 0; sl = http_find_stline(htx); - len = sl.rq.v.len; - ptr = sl.rq.v.ptr; + len = HTX_SL_REQ_VLEN(sl); + ptr = HTX_SL_REQ_VPTR(sl); } else { /* LEGACY version */ @@ -493,14 +514,14 @@ static int smp_fetch_stver(const struct arg *args, struct sample *smp, const cha if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; if (!htx) return 0; sl = http_find_stline(htx); - len = sl.st.v.len; - ptr = sl.st.v.ptr; + len = HTX_SL_RES_VLEN(sl); + ptr = HTX_SL_RES_VPTR(sl); } else { /* LEGACY version */ @@ -536,14 +557,14 @@ static int smp_fetch_stcode(const struct arg *args, struct sample *smp, const ch if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; if (!htx) return 0; sl = http_find_stline(htx); - len = sl.st.c.len; - ptr = sl.st.c.ptr; + len = HTX_SL_RES_CLEN(sl); + ptr = HTX_SL_RES_CPTR(sl); } else { /* LEGACY version */ @@ -955,14 +976,14 @@ static int smp_fetch_url(const struct arg *args, struct sample *smp, const char if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; if (!htx) return 0; sl = http_find_stline(htx); smp->data.type = SMP_T_STR; - smp->data.u.str.area = sl.rq.u.ptr; - smp->data.u.str.data = sl.rq.u.len; + smp->data.u.str.area = HTX_SL_REQ_UPTR(sl); + smp->data.u.str.data = HTX_SL_REQ_ULEN(sl); smp->flags = SMP_F_VOL_1ST | SMP_F_CONST; } else { @@ -986,12 +1007,12 @@ static int smp_fetch_url_ip(const struct arg *args, struct sample *smp, const ch if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; if (!htx) return 0; sl = http_find_stline(htx); - url2sa(sl.rq.u.ptr, sl.rq.u.len, &addr, NULL); + url2sa(HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl), &addr, NULL); } else { /* LEGACY version */ @@ -1018,12 +1039,12 @@ static int smp_fetch_url_port(const struct arg *args, struct sample *smp, const if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; if (!htx) return 0; sl = http_find_stline(htx); - url2sa(sl.rq.u.ptr, sl.rq.u.len, &addr, NULL); + url2sa(HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl), &addr, NULL); } else { /* LEGACY version */ @@ -1492,7 +1513,7 @@ static int smp_fetch_path(const struct arg *args, struct sample *smp, const char if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; struct ist path; size_t len; @@ -1500,7 +1521,7 @@ static int smp_fetch_path(const struct arg *args, struct sample *smp, const char return 0; sl = http_find_stline(htx); - path = http_get_path(sl.rq.u); + path = http_get_path(htx_sl_req_uri(sl)); if (!path.ptr) return 0; @@ -1551,7 +1572,7 @@ static int smp_fetch_base(const struct arg *args, struct sample *smp, const char if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; struct http_hdr_ctx ctx; struct ist path; @@ -1568,7 +1589,7 @@ static int smp_fetch_base(const struct arg *args, struct sample *smp, const char /* now retrieve the path */ sl = http_find_stline(htx); - path = http_get_path(sl.rq.u); + path = http_get_path(htx_sl_req_uri(sl)); if (path.ptr) { size_t len; @@ -1634,7 +1655,7 @@ static int smp_fetch_base32(const struct arg *args, struct sample *smp, const ch if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; struct http_hdr_ctx ctx; struct ist path; @@ -1650,7 +1671,7 @@ static int smp_fetch_base32(const struct arg *args, struct sample *smp, const ch /* now retrieve the path */ sl = http_find_stline(htx); - path = http_get_path(sl.rq.u); + path = http_get_path(htx_sl_req_uri(sl)); if (path.ptr) { size_t len; @@ -1757,14 +1778,14 @@ static int smp_fetch_query(const struct arg *args, struct sample *smp, const cha if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; if (!htx) return 0; sl = http_find_stline(htx); - ptr = sl.rq.u.ptr; - end = sl.rq.u.ptr + sl.rq.u.len; + ptr = HTX_SL_REQ_UPTR(sl); + end = HTX_SL_REQ_UPTR(sl) + HTX_SL_REQ_ULEN(sl); } else { /* LEGACY version */ @@ -2432,17 +2453,17 @@ static int smp_fetch_url_param(const struct arg *args, struct sample *smp, const if (IS_HTX_SMP(smp) || (smp->px->mode == PR_MODE_TCP)) { /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); - union h1_sl sl; + struct htx_sl *sl; if (!htx) return 0; sl = http_find_stline(htx); - smp->ctx.a[0] = http_find_param_list(sl.rq.u.ptr, sl.rq.u.len, delim); + smp->ctx.a[0] = http_find_param_list(HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl), delim); if (!smp->ctx.a[0]) return 0; - smp->ctx.a[1] = sl.rq.u.ptr + sl.rq.u.len; + smp->ctx.a[1] = HTX_SL_REQ_UPTR(sl) + HTX_SL_REQ_ULEN(sl); } else { /* LEGACY version */ @@ -2603,7 +2624,7 @@ static int smp_fetch_url32(const struct arg *args, struct sample *smp, const cha /* HTX version */ struct htx *htx = smp_prefetch_htx(smp, args); struct http_hdr_ctx ctx; - union h1_sl sl; + struct htx_sl *sl; struct ist path; if (!htx) @@ -2618,7 +2639,7 @@ static int smp_fetch_url32(const struct arg *args, struct sample *smp, const cha /* now retrieve the path */ sl = http_find_stline(htx); - path = http_get_path(sl.rq.u); + path = http_get_path(htx_sl_req_uri(sl)); while (path.len > 0 && *(path.ptr) != '?') { path.ptr++; path.len--; diff --git a/src/http_htx.c b/src/http_htx.c index 1a8e5bb9e9..82f9497d95 100644 --- a/src/http_htx.c +++ b/src/http_htx.c @@ -17,44 +17,33 @@ #include /* Finds the start line in the HTX message stopping at the first - * end-of-message. It returns an empty start line when not found, otherwise, it - * returns the corresponding . + * end-of-message. It returns NULL when not found, otherwise, it returns the + * pointer on the htx_sl structure. The HTX message may be updated if the + * start-line is returned following a lookup. */ -union h1_sl http_find_stline(const struct htx *htx) +struct htx_sl *http_find_stline(struct htx *htx) { - struct htx_sl *htx_sl; - union h1_sl sl; + struct htx_sl *sl = NULL; int32_t pos; + sl = htx_get_stline(htx); + if (sl) + return sl; + for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) { struct htx_blk *blk = htx_get_blk(htx, pos); enum htx_blk_type type = htx_get_blk_type(blk); - if (type == HTX_BLK_REQ_SL) { - htx_sl = htx_get_blk_ptr(htx, blk); - sl.rq.meth = htx_sl->info.req.meth; - sl.rq.m = htx_sl_req_meth(htx_sl); - sl.rq.u = htx_sl_req_uri(htx_sl); - sl.rq.v = htx_sl_req_vsn(htx_sl); - return sl; - } - - if (type == HTX_BLK_RES_SL) { - htx_sl = htx_get_blk_ptr(htx, blk); - sl.st.status = htx_sl->info.res.status; - sl.st.v = htx_sl_res_vsn(htx_sl); - sl.st.c = htx_sl_res_code(htx_sl); - sl.st.r = htx_sl_res_reason(htx_sl); - return sl; + if (type == HTX_BLK_REQ_SL || type == HTX_BLK_RES_SL) { + sl = htx_get_blk_ptr(htx, blk); + htx->sl_off = blk->addr; + break; } if (type == HTX_BLK_EOH || type == HTX_BLK_EOM) break; } - sl.rq.m = ist(""); - sl.rq.u = ist(""); - sl.rq.v = ist(""); return sl; } @@ -193,50 +182,24 @@ int http_add_header(struct htx *htx, const struct ist n, const struct ist v) return 1; } -/* Replaces the request start line of the HTX message by . It returns - * 1 on success, otherwise it returns 0. The start line must be found in the +/* Replaces parts of the start-line of the HTX message . It returns 1 on + * success, otherwise it returns 0. The right block is search in the HTX * message. */ -int http_replace_reqline(struct htx *htx, const union h1_sl sl) +int http_replace_stline(struct htx *htx, const struct ist p1, const struct ist p2, const struct ist p3) { int32_t pos; for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) { - struct htx_blk *blk = htx_get_blk(htx, pos); - enum htx_blk_type type = htx_get_blk_type(blk); + struct htx_blk *blk = htx_get_blk(htx, pos); + enum htx_blk_type type = htx_get_blk_type(blk); - if (type == HTX_BLK_REQ_SL) { - blk = htx_replace_reqline(htx, blk, sl); - if (!blk) + if (htx->sl_off == blk->addr) { + if (!htx_replace_stline(htx, blk, p1, p2, p3)) return 0; return 1; } - if (type == HTX_BLK_EOM) - break; - } - - return 0; -} - - -/* Replaces the response start line of the HTX message by . It returns - * 1 on success, otherwise it returns 0. The start line must be found in the - * message. - */ -int http_replace_resline(struct htx *htx, const union h1_sl sl) -{ - int32_t pos; - for (pos = htx_get_head(htx); pos != -1; pos = htx_get_next(htx, pos)) { - struct htx_blk *blk = htx_get_blk(htx, pos); - enum htx_blk_type type = htx_get_blk_type(blk); - - if (type == HTX_BLK_RES_SL) { - blk = htx_replace_resline(htx, blk, sl); - if (!blk) - return 0; - return 1; - } if (type == HTX_BLK_EOM) break; } @@ -250,20 +213,19 @@ int http_replace_resline(struct htx *htx, const union h1_sl sl) int http_replace_req_meth(struct htx *htx, const struct ist meth) { struct buffer *temp = get_trash_chunk(); - union h1_sl sl = http_find_stline(htx); - union h1_sl new_sl; + struct htx_sl *sl = http_find_stline(htx); + struct ist uri, vsn; /* Start by copying old uri and version */ - chunk_memcat(temp, sl.rq.u.ptr, sl.rq.u.len); /* uri */ - chunk_memcat(temp, sl.rq.v.ptr, sl.rq.v.len); /* vsn */ + chunk_memcat(temp, HTX_SL_REQ_UPTR(sl), HTX_SL_REQ_ULEN(sl)); /* uri */ + uri = ist2(temp->area, HTX_SL_REQ_ULEN(sl)); - /* create the new start line */ - new_sl.rq.meth = find_http_meth(meth.ptr, meth.len); - new_sl.rq.m = meth; - new_sl.rq.u = ist2(temp->area, sl.rq.u.len); - new_sl.rq.v = ist2(temp->area + sl.rq.u.len, sl.rq.v.len); + chunk_memcat(temp, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)); /* vsn */ + vsn = ist2(temp->area + uri.len, HTX_SL_REQ_VLEN(sl)); - return http_replace_reqline(htx, new_sl); + /* create the new start line */ + sl->info.req.meth = find_http_meth(meth.ptr, meth.len); + return http_replace_stline(htx, meth, uri, vsn); } /* Replace the request uri in the HTX message by . It returns 1 on @@ -272,20 +234,18 @@ int http_replace_req_meth(struct htx *htx, const struct ist meth) int http_replace_req_uri(struct htx *htx, const struct ist uri) { struct buffer *temp = get_trash_chunk(); - union h1_sl sl = http_find_stline(htx); - union h1_sl new_sl; + struct htx_sl *sl = http_find_stline(htx); + struct ist meth, vsn; /* Start by copying old method and version */ - chunk_memcat(temp, sl.rq.m.ptr, sl.rq.m.len); /* meth */ - chunk_memcat(temp, sl.rq.v.ptr, sl.rq.v.len); /* vsn */ + chunk_memcat(temp, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)); /* meth */ + meth = ist2(temp->area, HTX_SL_REQ_MLEN(sl)); - /* create the new start line */ - new_sl.rq.meth = sl.rq.meth; - new_sl.rq.m = ist2(temp->area, sl.rq.m.len); - new_sl.rq.u = uri; - new_sl.rq.v = ist2(temp->area + sl.rq.m.len, sl.rq.v.len); + chunk_memcat(temp, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)); /* vsn */ + vsn = ist2(temp->area + meth.len, HTX_SL_REQ_VLEN(sl)); - return http_replace_reqline(htx, new_sl); + /* create the new start line */ + return http_replace_stline(htx, meth, uri, vsn); } /* Replace the request path in the HTX message by . The host part @@ -294,36 +254,31 @@ int http_replace_req_uri(struct htx *htx, const struct ist uri) int http_replace_req_path(struct htx *htx, const struct ist path) { struct buffer *temp = get_trash_chunk(); - union h1_sl sl = http_find_stline(htx); - union h1_sl new_sl; - struct ist p, uri; + struct htx_sl *sl = http_find_stline(htx); + struct ist meth, uri, vsn, p; size_t plen = 0; - p = http_get_path(sl.rq.u); + uri = htx_sl_req_uri(sl); + p = http_get_path(uri); if (!p.ptr) - p = sl.rq.u; + p = uri; while (plen < p.len && *(p.ptr + plen) != '?') plen++; /* Start by copying old method and version and create the new uri */ - chunk_memcat(temp, sl.rq.m.ptr, sl.rq.m.len); /* meth */ - chunk_memcat(temp, sl.rq.v.ptr, sl.rq.v.len); /* vsn */ + chunk_memcat(temp, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)); /* meth */ + meth = ist2(temp->area, HTX_SL_REQ_MLEN(sl)); + + chunk_memcat(temp, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)); /* vsn */ + vsn = ist2(temp->area + meth.len, HTX_SL_REQ_VLEN(sl)); - chunk_memcat(temp, sl.rq.u.ptr, p.ptr - sl.rq.u.ptr); /* uri: host part */ + chunk_memcat(temp, uri.ptr, p.ptr - uri.ptr); /* uri: host part */ chunk_memcat(temp, path.ptr, path.len); /* uri: new path */ chunk_memcat(temp, p.ptr + plen, p.len - plen); /* uri: QS part */ - - /* Get uri ptr and len */ - uri.ptr = temp->area + sl.rq.m.len + sl.rq.v.len; - uri.len = sl.rq.u.len - plen + path.len; + uri = ist2(temp->area + meth.len + vsn.len, uri.len - plen + path.len); /* create the new start line */ - new_sl.rq.meth = sl.rq.meth; - new_sl.rq.m = ist2(temp->area, sl.rq.m.len); - new_sl.rq.u = uri; - new_sl.rq.v = ist2(temp->area + sl.rq.m.len, sl.rq.v.len); - - return http_replace_reqline(htx, new_sl); + return http_replace_stline(htx, meth, uri, vsn); } /* Replace the request query-string in the HTX message by . The @@ -333,12 +288,12 @@ int http_replace_req_path(struct htx *htx, const struct ist path) int http_replace_req_query(struct htx *htx, const struct ist query) { struct buffer *temp = get_trash_chunk(); - union h1_sl sl = http_find_stline(htx); - union h1_sl new_sl; - struct ist q, uri; + struct htx_sl *sl = http_find_stline(htx); + struct ist meth, uri, vsn, q; int offset = 1; - q = sl.rq.u; + uri = htx_sl_req_uri(sl); + q = uri; while (q.len > 0 && *(q.ptr) != '?') { q.ptr++; q.len--; @@ -355,23 +310,18 @@ int http_replace_req_query(struct htx *htx, const struct ist query) offset = 0; /* Start by copying old method and version and create the new uri */ - chunk_memcat(temp, sl.rq.m.ptr, sl.rq.m.len); /* meth */ - chunk_memcat(temp, sl.rq.v.ptr, sl.rq.v.len); /* vsn */ + chunk_memcat(temp, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)); /* meth */ + meth = ist2(temp->area, HTX_SL_REQ_MLEN(sl)); - chunk_memcat(temp, sl.rq.u.ptr, q.ptr - sl.rq.u.ptr); /* uri: host + path part */ - chunk_memcat(temp, query.ptr + offset, query.len - offset); /* uri: new QS */ + chunk_memcat(temp, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)); /* vsn */ + vsn = ist2(temp->area + meth.len, HTX_SL_REQ_VLEN(sl)); - /* Get uri ptr and len */ - uri.ptr = temp->area + sl.rq.m.len + sl.rq.v.len; - uri.len = sl.rq.u.len - q.len + query.len - offset; + chunk_memcat(temp, uri.ptr, q.ptr - uri.ptr); /* uri: host + path part */ + chunk_memcat(temp, query.ptr + offset, query.len - offset); /* uri: new QS */ + uri = ist2(temp->area + meth.len + vsn.len, uri.len - q.len + query.len - offset); /* create the new start line */ - new_sl.rq.meth = sl.rq.meth; - new_sl.rq.m = ist2(temp->area, sl.rq.m.len); - new_sl.rq.u = uri; - new_sl.rq.v = ist2(temp->area + sl.rq.m.len, sl.rq.v.len); - - return http_replace_reqline(htx, new_sl); + return http_replace_stline(htx, meth, uri, vsn); } /* Replace the response status in the HTX message by . It returns @@ -380,20 +330,19 @@ int http_replace_req_query(struct htx *htx, const struct ist query) int http_replace_res_status(struct htx *htx, const struct ist status) { struct buffer *temp = get_trash_chunk(); - union h1_sl sl = http_find_stline(htx); - union h1_sl new_sl; + struct htx_sl *sl = http_find_stline(htx); + struct ist vsn, reason; /* Start by copying old uri and version */ - chunk_memcat(temp, sl.st.v.ptr, sl.st.v.len); /* vsn */ - chunk_memcat(temp, sl.st.r.ptr, sl.st.r.len); /* reason */ + chunk_memcat(temp, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl)); /* vsn */ + vsn = ist2(temp->area, HTX_SL_RES_VLEN(sl)); - /* create the new start line */ - new_sl.st.status = strl2ui(status.ptr, status.len); - new_sl.st.v = ist2(temp->area, sl.st.v.len); - new_sl.st.c = status; - new_sl.st.r = ist2(temp->area + sl.st.v.len, sl.st.r.len); + chunk_memcat(temp, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl)); /* reason */ + reason = ist2(temp->area + vsn.len, HTX_SL_RES_RLEN(sl)); - return http_replace_resline(htx, new_sl); + /* create the new start line */ + sl->info.res.status = strl2ui(status.ptr, status.len); + return http_replace_stline(htx, vsn, status, reason); } /* Replace the response reason in the HTX message by . It returns @@ -402,20 +351,18 @@ int http_replace_res_status(struct htx *htx, const struct ist status) int http_replace_res_reason(struct htx *htx, const struct ist reason) { struct buffer *temp = get_trash_chunk(); - union h1_sl sl = http_find_stline(htx); - union h1_sl new_sl; + struct htx_sl *sl = http_find_stline(htx); + struct ist vsn, status; /* Start by copying old uri and version */ - chunk_memcat(temp, sl.st.v.ptr, sl.st.v.len); /* vsn */ - chunk_memcat(temp, sl.st.c.ptr, sl.st.c.len); /* code */ + chunk_memcat(temp, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl)); /* vsn */ + vsn = ist2(temp->area, HTX_SL_RES_VLEN(sl)); - /* create the new start line */ - new_sl.st.status = sl.st.status; - new_sl.st.v = ist2(temp->area, sl.st.v.len); - new_sl.st.c = ist2(temp->area + sl.st.v.len, sl.st.c.len); - new_sl.st.r = reason; + chunk_memcat(temp, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl)); /* code */ + status = ist2(temp->area + vsn.len, HTX_SL_RES_CLEN(sl)); - return http_replace_resline(htx, new_sl); + /* create the new start line */ + return http_replace_stline(htx, vsn, status, reason); } /* Replaces a part of a header value referenced in the context by diff --git a/src/htx.c b/src/htx.c index a57e1e8e78..a57c57d15f 100644 --- a/src/htx.c +++ b/src/htx.c @@ -586,136 +586,90 @@ struct htx_blk *htx_replace_header(struct htx *htx, struct htx_blk *blk, return blk; } -static void htx_set_blk_reqline(struct htx *htx, struct htx_blk *blk, const union h1_sl sl) -{ - struct htx_sl *htx_sl; - - htx_sl = htx_get_blk_ptr(htx, blk); - htx_sl->info.req.meth = sl.rq.meth; - - if (htx->sl_off == -1) - htx->sl_off = blk->addr; - - HTX_SL_REQ_MLEN(htx_sl) = sl.rq.m.len; - HTX_SL_REQ_ULEN(htx_sl) = sl.rq.u.len; - HTX_SL_REQ_VLEN(htx_sl) = sl.rq.v.len; - - memcpy(HTX_SL_REQ_MPTR(htx_sl), sl.rq.m.ptr, sl.rq.m.len); - memcpy(HTX_SL_REQ_UPTR(htx_sl), sl.rq.u.ptr, sl.rq.u.len); - memcpy(HTX_SL_REQ_VPTR(htx_sl), sl.rq.v.ptr, sl.rq.v.len); -} - - -static void htx_set_blk_resline(struct htx *htx, struct htx_blk *blk, const union h1_sl sl) -{ - struct htx_sl *htx_sl; - - htx_sl = htx_get_blk_ptr(htx, blk); - htx_sl->info.res.status = sl.st.status; - - if (htx->sl_off == -1) - htx->sl_off = blk->addr; - - HTX_SL_RES_VLEN(htx_sl) = sl.st.v.len; - HTX_SL_RES_CLEN(htx_sl) = sl.st.c.len; - HTX_SL_RES_RLEN(htx_sl) = sl.st.r.len; - - memcpy(HTX_SL_RES_VPTR(htx_sl), sl.st.v.ptr, sl.st.v.len); - memcpy(HTX_SL_RES_CPTR(htx_sl), sl.st.c.ptr, sl.st.c.len); - memcpy(HTX_SL_RES_RPTR(htx_sl), sl.st.r.ptr, sl.st.r.len); -} - -/* Replaces the request start line a new one. It returns the new block on - * success, otherwise it returns NULL. +/* Replaces the parts of the start-line. It returns the new start-line on + * success, otherwise it returns NULL. It is the caller responsibility to update + * sl->info, if necessary. */ -struct htx_blk *htx_replace_reqline(struct htx *htx, struct htx_blk *blk, - const union h1_sl sl) +struct htx_sl *htx_replace_stline(struct htx *htx, struct htx_blk *blk, const struct ist p1, + const struct ist p2, const struct ist p3) { + struct htx_sl *sl; + struct htx_sl tmp; /* used to save sl->info and sl->flags */ enum htx_blk_type type; uint32_t size; type = htx_get_blk_type(blk); - if (type != HTX_BLK_REQ_SL) + if (type != HTX_BLK_REQ_SL || HTX_BLK_RES_SL) return NULL; + /* Save start-line info and flags */ + sl = htx_get_blk_ptr(htx, blk); + tmp.info = sl->info; + tmp.flags = sl->flags; if (htx->sl_off == blk->addr) htx->sl_off = -1; - size = sizeof(struct htx_sl) + sl.rq.m.len + sl.rq.u.len + sl.rq.v.len; + + size = sizeof(*sl) + p1.len + p2.len + p3.len; blk = htx_new_blk_value(htx, blk, size); if (!blk) return NULL; - blk->info = (type << 28) + size; - htx_set_blk_reqline(htx, blk, sl); - return blk; -} -/* Replaces the response start line a new one. It returns the new block on - * success, otherwise it returns NULL. - */ -struct htx_blk *htx_replace_resline(struct htx *htx, struct htx_blk *blk, - const union h1_sl sl) -{ - enum htx_blk_type type; - uint32_t size; - - type = htx_get_blk_type(blk); - if (type != HTX_BLK_RES_SL) - return NULL; + /* Restore start-line info and flags*/ + sl = htx_get_blk_ptr(htx, blk); + sl->info = tmp.info; + sl->flags = tmp.flags; + if (htx->sl_off == -1) + htx->sl_off = blk->addr; - if (htx->sl_off == blk->addr) - htx->sl_off = -1; + HTX_SL_P1_LEN(sl) = p1.len; + HTX_SL_P2_LEN(sl) = p2.len; + HTX_SL_P3_LEN(sl) = p3.len; - size = sizeof(struct htx_sl) + sl.rq.m.len + sl.rq.u.len + sl.rq.v.len; - blk = htx_new_blk_value(htx, blk, size); - if (!blk) - return NULL; + memcpy(HTX_SL_P1_PTR(sl), p1.ptr, p1.len); + memcpy(HTX_SL_P2_PTR(sl), p2.ptr, p2.len); + memcpy(HTX_SL_P3_PTR(sl), p3.ptr, p3.len); - blk->info = (type << 28) + size; - htx_set_blk_resline(htx, blk, sl); - return blk; + return sl; } - -/* Adds an HTX block of type SL in . It returns the new block on - * success. Otherwise, it returns NULL. +/* Add a new start-line. It returns it on success, otherwise it returns NULL. It + * is the caller responsibility to set sl->info, if necessary. */ -struct htx_blk *htx_add_reqline(struct htx *htx, const union h1_sl sl) +struct htx_sl *htx_add_stline(struct htx *htx, enum htx_blk_type type, unsigned int flags, + const struct ist p1, const struct ist p2, const struct ist p3) { struct htx_blk *blk; + struct htx_sl *sl; uint32_t size; - size = sizeof(struct htx_sl) + sl.rq.m.len + sl.rq.u.len + sl.rq.v.len; + if (type != HTX_BLK_REQ_SL && type != HTX_BLK_RES_SL) + return NULL; + + size = sizeof(*sl) + p1.len + p2.len + p3.len; /* FIXME: check size (< 256MB) */ - blk = htx_add_blk(htx, HTX_BLK_REQ_SL, size); + blk = htx_add_blk(htx, type, size); if (!blk) return NULL; - blk->info += size; - htx_set_blk_reqline(htx, blk, sl); - return blk; -} -/* Adds an HTX block of type SL in . It returns the new block on - * success. Otherwise, it returns NULL. - */ -struct htx_blk *htx_add_resline(struct htx *htx, const union h1_sl sl) -{ - struct htx_blk *blk; - uint32_t size; + sl = htx_get_blk_ptr(htx, blk); + if (htx->sl_off == -1) + htx->sl_off = blk->addr; - size = sizeof(struct htx_sl) + sl.st.v.len + sl.st.c.len + sl.st.r.len; + sl->flags = flags; - /* FIXME: check size (< 256MB) */ - blk = htx_add_blk(htx, HTX_BLK_RES_SL, size); - if (!blk) - return NULL; + HTX_SL_P1_LEN(sl) = p1.len; + HTX_SL_P2_LEN(sl) = p2.len; + HTX_SL_P3_LEN(sl) = p3.len; - blk->info += size; - htx_set_blk_resline(htx, blk, sl); - return blk; + memcpy(HTX_SL_P1_PTR(sl), p1.ptr, p1.len); + memcpy(HTX_SL_P2_PTR(sl), p2.ptr, p2.len); + memcpy(HTX_SL_P3_PTR(sl), p3.ptr, p3.len); + + return sl; } /* Adds an HTX block of type HDR in . It returns the new block on diff --git a/src/mux_h1.c b/src/mux_h1.c index 37c0f8883b..47293618c0 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -490,7 +490,13 @@ static int h1_process_req_vsn(struct h1s *h1s, struct h1m *h1m, union h1_sl sl) /* Add HTTP version */ sl.rq.v = ist("HTTP/1.0"); + return 1; } + + if ((sl.rq.v.len == 8) && + ((*(sl.rq.v.ptr + 5) > '1') || + ((*(sl.rq.v.ptr + 5) == '1') && (*(sl.rq.v.ptr + 7) >= '1')))) + h1m->flags |= H1_MF_VER_11; return 1; } @@ -516,6 +522,12 @@ static int h1_process_res_vsn(struct h1s *h1s, struct h1m *h1m, union h1_sl sl) !isdigit((unsigned char)*(sl.st.v.ptr + 7))) return 0; } + + if ((sl.st.v.len == 8) && + ((*(sl.st.v.ptr + 5) > '1') || + ((*(sl.st.v.ptr + 5) == '1') && (*(sl.st.v.ptr + 7) >= '1')))) + h1m->flags |= H1_MF_VER_11; + return 1; } /* Remove all "Connection:" headers from the HTX message */ @@ -752,7 +764,8 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h struct buffer *buf, size_t *ofs, size_t max) { struct http_hdr hdrs[MAX_HTTP_HDR]; - union h1_sl sl; + union h1_sl h1sl; + unsigned int flags = HTX_SL_F_NONE; int ret = 0; if (!max) @@ -763,7 +776,7 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h b_slow_realign(buf, trash.area, 0); ret = h1_headers_to_hdr_list(b_peek(buf, *ofs), b_peek(buf, *ofs) + max, - hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, &sl); + hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, &h1sl); if (ret <= 0) { /* Incomplete or invalid message. If the buffer is full, it's an * error because headers are too large to be handled by the @@ -784,21 +797,21 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h /* Save the request's method or the response's status, check if the body * length is known and check the VSN validity */ if (!(h1m->flags & H1_MF_RESP)) { - h1s->meth = sl.rq.meth; + h1s->meth = h1sl.rq.meth; /* Request have always a known length */ h1m->flags |= H1_MF_XFER_LEN; if (!(h1m->flags & H1_MF_CHNK) && !h1m->body_len) h1m->state = H1_MSG_DONE; - if (!h1_process_req_vsn(h1s, h1m, sl)) { - h1m->err_pos = sl.rq.v.ptr - b_head(buf); + if (!h1_process_req_vsn(h1s, h1m, h1sl)) { + h1m->err_pos = h1sl.rq.v.ptr - b_head(buf); h1m->err_state = h1m->state; goto vsn_error; } } else { - h1s->status = sl.st.status; + h1s->status = h1sl.st.status; if ((h1s->meth == HTTP_METH_HEAD) || (h1s->status >= 100 && h1s->status < 200) || @@ -817,21 +830,44 @@ static size_t h1_process_headers(struct h1s *h1s, struct h1m *h1m, struct htx *h else h1m->state = H1_MSG_TUNNEL; - if (!h1_process_res_vsn(h1s, h1m, sl)) { - h1m->err_pos = sl.st.v.ptr - b_head(buf); + if (!h1_process_res_vsn(h1s, h1m, h1sl)) { + h1m->err_pos = h1sl.st.v.ptr - b_head(buf); h1m->err_state = h1m->state; goto vsn_error; } } + /* Set HTX start-line flags */ + if (h1m->flags & H1_MF_VER_11) + flags |= HTX_SL_F_VER_11; + if (h1m->flags & H1_MF_XFER_ENC) + flags |= HTX_SL_F_XFER_ENC; + if (h1m->flags & H1_MF_XFER_LEN) { + flags |= HTX_SL_F_XFER_LEN; + if (h1m->flags & H1_MF_CHNK) + flags |= HTX_SL_F_CHNK; + else if (h1m->flags & H1_MF_CLEN) + flags |= HTX_SL_F_CLEN; + } + if (!(h1m->flags & H1_MF_RESP)) { - if (!htx_add_reqline(htx, sl) || !htx_add_all_headers(htx, hdrs)) + struct htx_sl *sl; + + sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, h1sl.rq.m, h1sl.rq.u, h1sl.rq.v); + if (!sl || !htx_add_all_headers(htx, hdrs)) goto error; + sl->info.req.meth = h1s->meth; } else { - if (!htx_add_resline(htx, sl) || !htx_add_all_headers(htx, hdrs)) + struct htx_sl *sl; + + flags |= HTX_SL_F_IS_RESP; + sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, h1sl.st.v, h1sl.st.c, h1sl.st.r); + if (!sl || !htx_add_all_headers(htx, hdrs)) goto error; + sl->info.res.status = h1s->status; } + if (h1m->state == H1_MSG_DONE) if (!htx_add_endof(htx, HTX_BLK_EOM)) goto error; diff --git a/src/proto_htx.c b/src/proto_htx.c index 0e1abb6b7d..693ea901f0 100644 --- a/src/proto_htx.c +++ b/src/proto_htx.c @@ -43,9 +43,9 @@ static void htx_end_response(struct stream *s); static void htx_capture_headers(struct htx *htx, char **cap, struct cap_hdr *cap_hdr); static int htx_del_hdr_value(char *start, char *end, char **from, char *next); -static size_t htx_fmt_req_line(const union h1_sl sl, char *str, size_t len); -static size_t htx_fmt_res_line(const union h1_sl sl, char *str, size_t len); -static void htx_debug_stline(const char *dir, struct stream *s, const union h1_sl sl); +static size_t htx_fmt_req_line(const struct htx_sl *sl, char *str, size_t len); +static size_t htx_fmt_res_line(const struct htx_sl *sl, char *str, size_t len); +static void htx_debug_stline(const char *dir, struct stream *s, const struct htx_sl *sl); static void htx_debug_hdr(const char *dir, struct stream *s, const struct ist n, const struct ist v); static enum rule_result htx_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream *s, int *deny_status); @@ -81,7 +81,7 @@ int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit) struct http_txn *txn = s->txn; struct http_msg *msg = &txn->req; struct htx *htx; - union h1_sl sl; + struct htx_sl *sl; DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%lu analysers=%02x\n", now_ms, __FUNCTION__, @@ -301,19 +301,19 @@ int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit) * 1: identify the method */ sl = http_find_stline(htx); - txn->meth = sl.rq.meth; + txn->meth = sl->info.req.meth; msg->flags |= HTTP_MSGF_XFER_LEN; /* ... and check if the request is HTTP/1.1 or above */ - if ((sl.rq.v.len == 8) && - ((*(sl.rq.v.ptr + 5) > '1') || - ((*(sl.rq.v.ptr + 5) == '1') && (*(sl.rq.v.ptr + 7) >= '1')))) + if ((HTX_SL_REQ_VLEN(sl) == 8) && + ((*(HTX_SL_REQ_VPTR(sl) + 5) > '1') || + ((*(HTX_SL_REQ_VPTR(sl) + 5) == '1') && (*(HTX_SL_REQ_VPTR(sl) + 7) >= '1')))) msg->flags |= HTTP_MSGF_VER_11; /* we can make use of server redirect on GET and HEAD */ if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD) s->flags |= SF_REDIRECTABLE; - else if (txn->meth == HTTP_METH_OTHER && isteqi(sl.rq.m, ist("PRI"))) { + else if (txn->meth == HTTP_METH_OTHER && isteqi(htx_sl_req_meth(sl), ist("PRI"))) { /* PRI is reserved for the HTTP/2 preface */ goto return_bad_req; } @@ -324,7 +324,7 @@ int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit) * the monitor-uri is defined by the frontend. */ if (unlikely((sess->fe->monitor_uri_len != 0) && - isteqi(sl.rq.u, ist2(sess->fe->monitor_uri, sess->fe->monitor_uri_len)))) { + isteqi(htx_sl_req_uri(sl), ist2(sess->fe->monitor_uri, sess->fe->monitor_uri_len)))) { /* * We have found the monitor URI */ @@ -389,7 +389,7 @@ int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit) * CONNECT ip:port. */ if ((sess->fe->options2 & PR_O2_USE_PXHDR) && - *(sl.rq.u.ptr) != '/' && *(sl.rq.u.ptr) != '*') + *HTX_SL_REQ_UPTR(sl) != '/' && *HTX_SL_REQ_UPTR(sl) != '*') txn->flags |= TX_USE_PX_CONN; /* 5: we may need to capture headers */ @@ -777,8 +777,8 @@ int htx_process_request(struct stream *s, struct channel *req, int an_bit) */ if ((s->be->options & PR_O_HTTP_PROXY) && !(s->flags & SF_ADDR_SET)) { struct connection *conn; - union h1_sl sl; - struct ist path; + struct htx_sl *sl; + struct ist uri, path; /* Note that for now we don't reuse existing proxy connections */ if (unlikely((conn = cs_conn(si_alloc_cs(&s->si[1], NULL))) == NULL)) { @@ -796,8 +796,9 @@ int htx_process_request(struct stream *s, struct channel *req, int an_bit) return 0; } sl = http_find_stline(htx); - path = http_get_path(sl.rq.u); - if (url2sa(sl.rq.u.ptr, sl.rq.u.len - path.len, &conn->addr.to, NULL) == -1) + uri = htx_sl_req_uri(sl); + path = http_get_path(uri); + if (url2sa(uri.ptr, uri.len - path.len, &conn->addr.to, NULL) == -1) goto return_bad_req; /* if the path was found, we have to remove everything between @@ -805,13 +806,10 @@ int htx_process_request(struct stream *s, struct channel *req, int an_bit) * to replace from all the uri by a single "/". * * Instead of rewritting the whole start line, we just update - * . Some space will be lost but it should be + * the star-line URI. Some space will be lost but it should be * insignificant. */ - if (path.ptr) - sl.rq.u = path; - else - istcpy(&sl.rq.u, ist("/"), 1); + istcpy(&uri, (path.len ? path : ist("/")), uri.len); } /* @@ -1429,7 +1427,7 @@ int htx_wait_for_response(struct stream *s, struct channel *rep, int an_bit) struct http_msg *msg = &txn->rsp; struct htx *htx; struct connection *srv_conn; - union h1_sl sl; + struct htx_sl *sl; int n; DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%lu analysers=%02x\n", @@ -1612,14 +1610,14 @@ int htx_wait_for_response(struct stream *s, struct channel *rep, int an_bit) /* 1: get the status code */ sl = http_find_stline(htx); - txn->status = sl.st.status; + txn->status = sl->info.res.status; if (htx->extra != ULLONG_MAX) msg->flags |= HTTP_MSGF_XFER_LEN; /* ... and check if the request is HTTP/1.1 or above */ - if ((sl.st.v.len == 8) && - ((*(sl.st.v.ptr + 5) > '1') || - ((*(sl.st.v.ptr + 5) == '1') && (*(sl.st.v.ptr + 7) >= '1')))) + if ((HTX_SL_RES_VLEN(sl) == 8) && + ((*(HTX_SL_RES_VPTR(sl) + 5) > '1') || + ((*(HTX_SL_RES_VPTR(sl) + 5) == '1') && (*(HTX_SL_RES_VPTR(sl) + 7) >= '1')))) msg->flags |= HTTP_MSGF_VER_11; n = txn->status / 100; @@ -2319,7 +2317,7 @@ void htx_adjust_conn_mode(struct stream *s, struct http_txn *txn) int htx_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct http_txn *txn) { struct htx *htx = htx_from_buf(&s->req.buf); - union h1_sl sl; + struct htx_sl *sl; const char *msg_fmt; struct buffer *chunk; int ret = 0; @@ -2362,7 +2360,7 @@ int htx_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct host = ctx.value; sl = http_find_stline(htx); - path = http_get_path(sl.rq.u); + path = http_get_path(htx_sl_req_uri(sl)); /* build message using path */ if (path.ptr) { if (rule->flags & REDIRECT_FLAG_DROP_QS) { @@ -2409,7 +2407,7 @@ int htx_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct struct ist path; sl = http_find_stline(htx); - path = http_get_path(sl.rq.u); + path = http_get_path(htx_sl_req_uri(sl)); /* build message using path */ if (path.ptr) { if (rule->flags & REDIRECT_FLAG_DROP_QS) { @@ -3535,7 +3533,8 @@ static int htx_apply_filter_to_req_line(struct stream *s, struct channel *req, s /* Now we have the request line between cur_ptr and cur_end */ if (regex_exec_match2(exp->preg, reqline->area, reqline->data, MAX_MATCH, pmatch, 0)) { - union h1_sl sl; + struct htx_sl *sl = http_find_stline(htx); + struct ist meth, uri, vsn; int len; switch (exp->action) { @@ -3559,11 +3558,9 @@ static int htx_apply_filter_to_req_line(struct stream *s, struct channel *req, s if (len < 0) return -1; - http_parse_stline(ist2(trash.area, len), - &sl.rq.m, &sl.rq.u, &sl.rq.v); - sl.rq.meth = find_http_meth(sl.rq.m.ptr, sl.rq.m.len); - - if (!http_replace_reqline(htx, sl)) + http_parse_stline(ist2(trash.area, len), &meth, &uri, &vsn); + sl->info.req.meth = find_http_meth(meth.ptr, meth.len); + if (!http_replace_stline(htx, meth, uri, vsn)) return -1; done = 1; break; @@ -3745,7 +3742,8 @@ static int htx_apply_filter_to_sts_line(struct stream *s, struct channel *res, s /* Now we have the status line between cur_ptr and cur_end */ if (regex_exec_match2(exp->preg, resline->area, resline->data, MAX_MATCH, pmatch, 0)) { - union h1_sl sl; + struct htx_sl *sl = http_find_stline(htx); + struct ist vsn, code, reason; int len; switch (exp->action) { @@ -3764,11 +3762,9 @@ static int htx_apply_filter_to_sts_line(struct stream *s, struct channel *res, s if (len < 0) return -1; - http_parse_stline(ist2(trash.area, len), - &sl.st.v, &sl.st.c, &sl.st.r); - sl.st.status = strl2ui(sl.st.c.ptr, sl.st.c.len); - - if (!http_replace_resline(htx, sl)) + http_parse_stline(ist2(trash.area, len), &vsn, &code, &reason); + sl->info.res.status = strl2ui(code.ptr, code.len); + if (!http_replace_stline(htx, vsn, code, reason)) return -1; done = 1; @@ -4729,8 +4725,8 @@ static int htx_stats_check_uri(struct stream *s, struct http_txn *txn, struct pr { struct uri_auth *uri_auth = backend->uri_auth; struct htx *htx; + struct htx_sl *sl; struct ist uri; - union h1_sl sl; if (!uri_auth) return 0; @@ -4740,7 +4736,7 @@ static int htx_stats_check_uri(struct stream *s, struct http_txn *txn, struct pr htx = htx_from_buf(&s->req.buf); sl = http_find_stline(htx); - uri = sl.rq.u; + uri = htx_sl_req_uri(sl); /* check URI size */ if (uri_auth->uri_len > uri.len) @@ -4771,7 +4767,7 @@ static int htx_handle_stats(struct stream *s, struct channel *req) const char *h, *lookup, *end; struct appctx *appctx; struct htx *htx; - union h1_sl sl; + struct htx_sl *sl; appctx = si_appctx(si); memset(&appctx->ctx.stats, 0, sizeof(appctx->ctx.stats)); @@ -4783,8 +4779,8 @@ static int htx_handle_stats(struct stream *s, struct channel *req) htx = htx_from_buf(&req->buf); sl = http_find_stline(htx); - lookup = sl.rq.u.ptr + uri_auth->uri_len; - end = sl.rq.u.ptr + sl.rq.u.len; + lookup = HTX_SL_REQ_UPTR(sl) + uri_auth->uri_len; + end = HTX_SL_REQ_UPTR(sl) + HTX_SL_REQ_ULEN(sl); for (h = lookup; h <= end - 3; h++) { if (memcmp(h, ";up", 3) == 0) { @@ -4913,8 +4909,8 @@ void htx_perform_server_redirect(struct stream *s, struct stream_interface *si) { struct http_txn *txn = s->txn; struct htx *htx; + struct htx_sl *sl; struct server *srv; - union h1_sl sl; struct ist path; /* 1: create the response header */ @@ -4932,7 +4928,7 @@ void htx_perform_server_redirect(struct stream *s, struct stream_interface *si) /* 3: add the request Path */ htx = htx_from_buf(&s->req.buf); sl = http_find_stline(htx); - path = http_get_path(sl.rq.u); + path = http_get_path(htx_sl_req_uri(sl)); if (!path.ptr) return; @@ -5358,23 +5354,23 @@ static int htx_del_hdr_value(char *start, char *end, char **from, char *next) /* Formats the start line of the request (without CRLF) and puts it in and * return the written lenght. The line can be truncated if it exceeds . */ -static size_t htx_fmt_req_line(const union h1_sl sl, char *str, size_t len) +static size_t htx_fmt_req_line(const struct htx_sl *sl, char *str, size_t len) { struct ist dst = ist2(str, 0); - if (istcat(&dst, sl.rq.m, len) == -1) + if (istcat(&dst, htx_sl_req_meth(sl), len) == -1) goto end; if (dst.len + 1 > len) goto end; dst.ptr[dst.len++] = ' '; - if (istcat(&dst, sl.rq.u, len) == -1) + if (istcat(&dst, htx_sl_req_uri(sl), len) == -1) goto end; if (dst.len + 1 > len) goto end; dst.ptr[dst.len++] = ' '; - istcat(&dst, sl.rq.v, len); + istcat(&dst, htx_sl_req_vsn(sl), len); end: return dst.len; } @@ -5382,23 +5378,23 @@ static size_t htx_fmt_req_line(const union h1_sl sl, char *str, size_t len) /* Formats the start line of the response (without CRLF) and puts it in and * return the written lenght. The line can be truncated if it exceeds . */ -static size_t htx_fmt_res_line(const union h1_sl sl, char *str, size_t len) +static size_t htx_fmt_res_line(const struct htx_sl *sl, char *str, size_t len) { struct ist dst = ist2(str, 0); - if (istcat(&dst, sl.st.v, len) == -1) + if (istcat(&dst, htx_sl_res_vsn(sl), len) == -1) goto end; if (dst.len + 1 > len) goto end; dst.ptr[dst.len++] = ' '; - if (istcat(&dst, sl.st.c, len) == -1) + if (istcat(&dst, htx_sl_res_code(sl), len) == -1) goto end; if (dst.len + 1 > len) goto end; dst.ptr[dst.len++] = ' '; - istcat(&dst, sl.st.r, len); + istcat(&dst, htx_sl_res_reason(sl), len); end: return dst.len; } @@ -5407,7 +5403,7 @@ static size_t htx_fmt_res_line(const union h1_sl sl, char *str, size_t len) /* * Print a debug line with a start line. */ -static void htx_debug_stline(const char *dir, struct stream *s, const union h1_sl sl) +static void htx_debug_stline(const char *dir, struct stream *s, const struct htx_sl *sl) { struct session *sess = strm_sess(s); int max; @@ -5417,19 +5413,19 @@ static void htx_debug_stline(const char *dir, struct stream *s, const union h1_s objt_conn(sess->origin) ? (unsigned short)objt_conn(sess->origin)->handle.fd : -1, objt_cs(s->si[1].end) ? (unsigned short)objt_cs(s->si[1].end)->conn->handle.fd : -1); - max = sl.rq.m.len; + max = HTX_SL_P1_LEN(sl); UBOUND(max, trash.size - trash.data - 3); - chunk_memcat(&trash, sl.rq.m.ptr, max); + chunk_memcat(&trash, HTX_SL_P1_PTR(sl), max); trash.area[trash.data++] = ' '; - max = sl.rq.u.len; + max = HTX_SL_P2_LEN(sl); UBOUND(max, trash.size - trash.data - 2); - chunk_memcat(&trash, sl.rq.u.ptr, max); + chunk_memcat(&trash, HTX_SL_P2_PTR(sl), max); trash.area[trash.data++] = ' '; - max = sl.rq.v.len; + max = HTX_SL_P3_LEN(sl); UBOUND(max, trash.size - trash.data - 1); - chunk_memcat(&trash, sl.rq.v.ptr, max); + chunk_memcat(&trash, HTX_SL_P3_PTR(sl), max); trash.area[trash.data++] = '\n'; shut_your_big_mouth_gcc(write(1, trash.area, trash.data)); diff --git a/src/stats.c b/src/stats.c index c0de42961b..57968860fc 100644 --- a/src/stats.c +++ b/src/stats.c @@ -2984,15 +2984,14 @@ static int stats_send_htx_headers(struct stream_interface *si, struct htx *htx) struct stream *s = si_strm(si); struct uri_auth *uri = s->be->uri_auth; struct appctx *appctx = __objt_appctx(si->end); - union h1_sl sl; - - sl.st.status = 200; - sl.st.v = ist("HTTP/1.1"); - sl.st.c = ist("200"); - sl.st.r = ist("OK"); + struct htx_sl *sl; + unsigned int flags; - if (!htx_add_resline(htx, sl)) + flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11|HTX_SL_F_XFER_ENC|HTX_SL_F_XFER_LEN|HTX_SL_F_CHNK); + sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist("200"), ist("OK")); + if (!sl) goto full; + sl->info.res.status = 200; if (!htx_add_header(htx, ist("Cache-Control"), ist("no-cache")) || !htx_add_header(htx, ist("Connection"), ist("close"))) @@ -3035,7 +3034,8 @@ static int stats_send_htx_redirect(struct stream_interface *si, struct htx *htx) struct stream *s = si_strm(si); struct uri_auth *uri = s->be->uri_auth; struct appctx *appctx = __objt_appctx(si->end); - union h1_sl sl; + struct htx_sl *sl; + unsigned int flags; /* scope_txt = search pattern + search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */ scope_txt[0] = 0; @@ -3060,12 +3060,11 @@ static int stats_send_htx_redirect(struct stream_interface *si, struct htx *htx) (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "", scope_txt); - sl.st.status = 303; - sl.st.v = ist("HTTP/1.1"); - sl.st.c = ist("303"); - sl.st.r = ist("See Other"); - if (!htx_add_resline(htx, sl)) + flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11|HTX_SL_F_XFER_LEN|HTX_SL_F_CHNK); + sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/1.1"), ist("303"), ist("See Other")); + if (!sl) goto full; + sl->info.res.status = 303; if (!htx_add_header(htx, ist("Cache-Control"), ist("no-cache")) || !htx_add_header(htx, ist("Connection"), ist("close")) || -- 2.39.5