From b2aedea142bba94927c978802134c2289b3098c0 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Wed, 5 Dec 2018 11:56:15 +0100 Subject: [PATCH] MEDIUM: channel/htx: Add functions for forward HTX data To ease the fast forwarding and the infinte forwarding on HTX proxies, 2 functions have been added to let the channel be almost aware of the way data are stored in its buffer. By calling these functions instead of legacy ones, we are sure to forward the right amount of data. --- include/proto/channel.h | 19 +++++++++++++ src/proto_htx.c | 12 +++----- src/stream.c | 62 ++++++++++++++++++++++++++--------------- 3 files changed, 63 insertions(+), 30 deletions(-) diff --git a/include/proto/channel.h b/include/proto/channel.h index 56bf5cf61..dd9b1afa2 100644 --- a/include/proto/channel.h +++ b/include/proto/channel.h @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -360,6 +361,24 @@ static inline void channel_forward_forever(struct channel *chn) chn->to_forward = CHN_INFINITE_FORWARD; } +static inline unsigned long long channel_htx_forward(struct channel *chn, struct htx *htx, unsigned long long bytes) +{ + unsigned long long ret; + + b_set_data(&chn->buf, htx->data); + ret = channel_forward(chn, bytes); + b_set_data(&chn->buf, b_size(&chn->buf)); + return ret; +} + + +static inline void channel_htx_forward_forever(struct channel *chn, struct htx *htx) +{ + b_set_data(&chn->buf, htx->data); + channel_forward_forever(chn); + b_set_data(&chn->buf, b_size(&chn->buf)); +} + /*********************************************************************/ /* These functions are used to compute various channel content sizes */ /*********************************************************************/ diff --git a/src/proto_htx.c b/src/proto_htx.c index 3232d0a2e..c613e72e2 100644 --- a/src/proto_htx.c +++ b/src/proto_htx.c @@ -1245,10 +1245,8 @@ int htx_request_forward_body(struct stream *s, struct channel *req, int an_bit) * right length is then restored. We must do that, because when an HTX * message is stored into a buffer, it appears as full. */ - b_set_data(&req->buf, co_data(req)); - if (msg->flags & HTTP_MSGF_XFER_LEN) - htx->extra -= channel_forward(req, htx->extra); - b_set_data(&req->buf, b_size(&req->buf)); + if ((msg->flags & HTTP_MSGF_XFER_LEN) && htx->extra) + htx->extra -= channel_htx_forward(req, htx, htx->extra); } /* Check if the end-of-message is reached and if so, switch the message @@ -2185,10 +2183,8 @@ int htx_response_forward_body(struct stream *s, struct channel *res, int an_bit) * right length is then restored. We must do that, because when an HTX * message is stored into a buffer, it appears as full. */ - b_set_data(&res->buf, co_data(res)); - if (msg->flags & HTTP_MSGF_XFER_LEN) - htx->extra -= channel_forward(res, htx->extra); - b_set_data(&res->buf, b_size(&res->buf)); + if ((msg->flags & HTTP_MSGF_XFER_LEN) && htx->extra) + htx->extra -= channel_htx_forward(res, htx, htx->extra); } if (!(msg->flags & HTTP_MSGF_XFER_LEN)) { diff --git a/src/stream.c b/src/stream.c index ed913d119..be58e77bd 100644 --- a/src/stream.c +++ b/src/stream.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -2184,19 +2185,27 @@ redo: channel_auto_close(req); c_adv(req, ci_data(req)); - /* We'll let data flow between the producer (if still connected) - * to the consumer (which might possibly not be connected yet). - */ - if (!(req->flags & (CF_SHUTR|CF_SHUTW_NOW))) - channel_forward_forever(req); + if (IS_HTX_STRM(s) && s->txn) { + /* We'll let data flow between the producer (if still connected) + * to the consumer (which might possibly not be connected yet). + */ + if (!(req->flags & (CF_SHUTR|CF_SHUTW_NOW))) + channel_htx_forward_forever(req, htxbuf(&req->buf)); + } + else { + /* We'll let data flow between the producer (if still connected) + * to the consumer (which might possibly not be connected yet). + */ + if (!(req->flags & (CF_SHUTR|CF_SHUTW_NOW))) + channel_forward_forever(req); - /* Just in order to support fetching HTTP contents after start - * of forwarding when the HTTP forwarding analyser is not used, - * we simply reset msg->sov so that HTTP rewinding points to the - * headers. - */ - if (IS_HTX_STRM(s) && s->txn) + /* Just in order to support fetching HTTP contents after start + * of forwarding when the HTTP forwarding analyser is not used, + * we simply reset msg->sov so that HTTP rewinding points to the + * headers. + */ s->txn->req.sov = s->txn->req.eoh + s->txn->req.eol - co_data(req); + } } /* check if it is wise to enable kernel splicing to forward request data */ @@ -2345,19 +2354,28 @@ redo: channel_auto_close(res); c_adv(res, ci_data(res)); - /* We'll let data flow between the producer (if still connected) - * to the consumer. - */ - if (!(res->flags & (CF_SHUTR|CF_SHUTW_NOW))) - channel_forward_forever(res); - /* Just in order to support fetching HTTP contents after start - * of forwarding when the HTTP forwarding analyser is not used, - * we simply reset msg->sov so that HTTP rewinding points to the - * headers. - */ - if (IS_HTX_STRM(s) && s->txn) + if (IS_HTX_STRM(s) && s->txn) { + /* We'll let data flow between the producer (if still connected) + * to the consumer. + */ + if (!(res->flags & (CF_SHUTR|CF_SHUTW_NOW))) + channel_htx_forward_forever(res, htxbuf(&res->buf)); + } + else { + /* We'll let data flow between the producer (if still connected) + * to the consumer. + */ + if (!(res->flags & (CF_SHUTR|CF_SHUTW_NOW))) + channel_forward_forever(res); + + /* Just in order to support fetching HTTP contents after start + * of forwarding when the HTTP forwarding analyser is not used, + * we simply reset msg->sov so that HTTP rewinding points to the + * headers. + */ s->txn->rsp.sov = s->txn->rsp.eoh + s->txn->rsp.eol - co_data(res); + } /* if we have no analyser anymore in any direction and have a * tunnel timeout set, use it now. Note that we must respect