diff --git a/include/proto/channel.h b/include/proto/channel.h index 44cb89012..49a68b26b 100644 --- a/include/proto/channel.h +++ b/include/proto/channel.h @@ -102,10 +102,28 @@ static inline unsigned int channel_is_empty(struct channel *c) return !(c->buf->o | (long)c->pipe); } -/* Returns non-zero if the buffer input is considered full. The reserved space - * is taken into account if ->to_forward indicates that an end of transfer is - * close to happen. The test is optimized to avoid as many operations as - * possible for the fast case and to be used as an "if" condition. +/* Returns non-zero if the buffer input has all of its reserve available. This + * is used to decide when a request or response may be parsed when some data + * from a previous exchange might still be present. + */ +static inline int channel_reserved(const struct channel *chn) +{ + int rem = chn->buf->size; + + rem -= chn->buf->o; + rem -= chn->buf->i; + rem -= global.tune.maxrewrite; + return rem >= 0; +} + +/* Returns non-zero if the buffer input is considered full. This is used to + * decide when to stop reading into a buffer when we want to ensure that we + * leave the reserve untouched after all pending outgoing data are forwarded. + * The reserved space is taken into account if ->to_forward indicates that an + * end of transfer is close to happen. Note that both ->buf->o and ->to_forward + * are considered as available since they're supposed to leave the buffer. The + * test is optimized to avoid as many operations as possible for the fast case + * and to be used as an "if" condition. */ static inline int channel_full(const struct channel *chn) { diff --git a/src/proto_http.c b/src/proto_http.c index d1bf51ead..d4e93e592 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2219,11 +2219,8 @@ int http_wait_for_request(struct session *s, struct channel *req, int an_bit) * data later, which is much more complicated. */ if (buffer_not_empty(req->buf) && msg->msg_state < HTTP_MSG_ERROR) { - if ((txn->flags & TX_NOT_FIRST) && - unlikely(channel_full(req) || - bi_end(req->buf) < b_ptr(req->buf, msg->next) || - bi_end(req->buf) > req->buf->data + req->buf->size - global.tune.maxrewrite)) { - if (req->buf->o) { + if (txn->flags & TX_NOT_FIRST) { + if (unlikely(!channel_reserved(req))) { if (req->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) goto failed_keep_alive; /* some data has still not left the buffer, wake us once that's done */ @@ -2231,9 +2228,9 @@ int http_wait_for_request(struct session *s, struct channel *req, int an_bit) req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */ return 0; } - if (bi_end(req->buf) < b_ptr(req->buf, msg->next) || - bi_end(req->buf) > req->buf->data + req->buf->size - global.tune.maxrewrite) - buffer_slow_realign(msg->chn->buf); + if (unlikely(bi_end(req->buf) < b_ptr(req->buf, msg->next) || + bi_end(req->buf) > req->buf->data + req->buf->size - global.tune.maxrewrite)) + buffer_slow_realign(req->buf); } /* Note that we have the same problem with the response ; we @@ -2244,7 +2241,7 @@ int http_wait_for_request(struct session *s, struct channel *req, int an_bit) * keep-alive requests. */ if ((txn->flags & TX_NOT_FIRST) && - unlikely(channel_full(s->rep) || + unlikely(!channel_reserved(s->rep) || bi_end(s->rep->buf) < b_ptr(s->rep->buf, txn->rsp.next) || bi_end(s->rep->buf) > s->rep->buf->data + s->rep->buf->size - global.tune.maxrewrite)) { if (s->rep->buf->o) { @@ -5004,21 +5001,19 @@ int http_wait_for_response(struct session *s, struct channel *rep, int an_bit) * data later, which is much more complicated. */ if (buffer_not_empty(rep->buf) && msg->msg_state < HTTP_MSG_ERROR) { - if (unlikely(channel_full(rep) || - bi_end(rep->buf) < b_ptr(rep->buf, msg->next) || - bi_end(rep->buf) > rep->buf->data + rep->buf->size - global.tune.maxrewrite)) { - if (rep->buf->o) { - /* some data has still not left the buffer, wake us once that's done */ - if (rep->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) - goto abort_response; - channel_dont_close(rep); - rep->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */ - return 0; - } - if (rep->buf->i <= rep->buf->size - global.tune.maxrewrite) - buffer_slow_realign(msg->chn->buf); + if (unlikely(!channel_reserved(rep))) { + /* some data has still not left the buffer, wake us once that's done */ + if (rep->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) + goto abort_response; + channel_dont_close(rep); + rep->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */ + return 0; } + if (unlikely(bi_end(rep->buf) < b_ptr(rep->buf, msg->next) || + bi_end(rep->buf) > rep->buf->data + rep->buf->size - global.tune.maxrewrite)) + buffer_slow_realign(rep->buf); + if (likely(msg->next < rep->buf->i)) http_msg_analyzer(msg, &txn->hdr_idx); }