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