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.
This commit is contained in:
Christopher Faulet 2018-11-26 21:37:08 +01:00 committed by Willy Tarreau
parent 54483df5ba
commit f1ba18d7b3
8 changed files with 318 additions and 369 deletions

View File

@ -28,11 +28,10 @@
#include <types/h1.h>
#include <types/http_htx.h>
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);

View File

@ -26,8 +26,6 @@
#include <common/config.h>
#include <common/standard.h>
#include <common/http-hdr.h>
#include <types/h1.h>
#include <types/htx.h>
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);

View File

@ -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 <s> 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--;

View File

@ -17,44 +17,33 @@
#include <proto/htx.h>
/* 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 <struct h1_sl>.
* 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 <htx> by <sl>. 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 <htx>. 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 <htx> by <sl>. 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));
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));
/* 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);
return http_replace_reqline(htx, new_sl);
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 <htx> by <uri>. 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));
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));
/* 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 path in the HTX message <htx> by <path>. 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, sl.rq.u.ptr, p.ptr - sl.rq.u.ptr); /* uri: host part */
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, 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 <htx> by <query>. 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, 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, uri.ptr, q.ptr - uri.ptr); /* uri: host + path part */
chunk_memcat(temp, query.ptr + offset, query.len - offset); /* uri: new QS */
/* 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;
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 <htx> by <status>. 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));
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));
/* 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);
return http_replace_resline(htx, new_sl);
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 <htx> by <reason>. 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));
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));
/* 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;
return http_replace_resline(htx, new_sl);
return http_replace_stline(htx, vsn, status, reason);
}
/* Replaces a part of a header value referenced in the context <ctx> by

150
src/htx.c
View File

@ -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;
/* 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;
HTX_SL_P1_LEN(sl) = p1.len;
HTX_SL_P2_LEN(sl) = p2.len;
HTX_SL_P3_LEN(sl) = p3.len;
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;
}
/* Replaces the response start line a new one. 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_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)
{
enum htx_blk_type type;
struct htx_blk *blk;
struct htx_sl *sl;
uint32_t size;
type = htx_get_blk_type(blk);
if (type != HTX_BLK_RES_SL)
return NULL;
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;
blk = htx_new_blk_value(htx, blk, size);
if (!blk)
if (type != HTX_BLK_REQ_SL && type != HTX_BLK_RES_SL)
return NULL;
blk->info = (type << 28) + size;
htx_set_blk_resline(htx, blk, sl);
return blk;
}
/* Adds an HTX block of type SL in <htx>. It returns the new block on
* success. Otherwise, it returns NULL.
*/
struct htx_blk *htx_add_reqline(struct htx *htx, const union h1_sl sl)
{
struct htx_blk *blk;
uint32_t size;
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;
/* 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 <htx>. 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 <htx>. It returns the new block on

View File

@ -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 <htx> */
@ -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;

View File

@ -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
* <sl.rq.u>. 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 <str> and
* return the written lenght. The line can be truncated if it exceeds <len>.
*/
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 <str> and
* return the written lenght. The line can be truncated if it exceeds <len>.
*/
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));

View File

@ -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;
struct htx_sl *sl;
unsigned int flags;
sl.st.status = 200;
sl.st.v = ist("HTTP/1.1");
sl.st.c = ist("200");
sl.st.r = ist("OK");
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")) ||