From 065e8338e863aae0395fb385eca7eb3dfcb4a945 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 8 Jan 2010 00:30:20 +0100 Subject: [PATCH] [MEDIUM] http: wait for some flush of the response buffer before a new request If we accept a new request and that request produces an immediate response (error, redirect, ...), then we may fail to send it in case of pipelined requests if the response buffer is full. To avoid this, we check the availability of at least maxrewrite bytes in the response buffer before accepting a new pipelined request. --- src/proto_http.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/proto_http.c b/src/proto_http.c index 915abc244..32284fe27 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -2145,7 +2145,8 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit) * data later, which is much more complicated. */ if (req->l && msg->msg_state < HTTP_MSG_ERROR) { - if (unlikely((req->flags & BF_FULL) || + if ((txn->flags & TX_NOT_FIRST) && + unlikely((req->flags & BF_FULL) || req->r < req->lr || req->r > req->data + req->size - global.tune.maxrewrite)) { if (req->send_max) { @@ -2158,6 +2159,24 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit) http_buffer_heavy_realign(req, msg); } + /* Note that we have the same problem with the response ; we + * may want to send a redirect, error or anything which requires + * some spare space. So we'll ensure that we have at least + * maxrewrite bytes available in the response buffer before + * processing that one. This will only affect pipelined + * keep-alive requests. + */ + if ((txn->flags & TX_NOT_FIRST) && + unlikely((s->rep->flags & BF_FULL) || + s->rep->r < s->rep->lr || + s->rep->r > s->rep->data + s->rep->size - global.tune.maxrewrite)) { + if (s->rep->send_max) { + /* don't let a connection request be initiated */ + buffer_dont_connect(req); + return 0; + } + } + if (likely(req->lr < req->r)) http_msg_analyzer(req, msg, &txn->hdr_idx); } @@ -3404,9 +3423,17 @@ void http_end_txn_clean_session(struct session *s) /* if the request buffer is not empty, it means we're * about to process another request, so send pending * data with MSG_MORE to merge TCP packets when possible. + * Just don't do this if the buffer is close to be full, + * because the request will wait for it to flush a little + * bit before proceeding. */ - if (s->req->l > s->req->send_max) - s->rep->flags |= BF_EXPECT_MORE; + if (s->req->l > s->req->send_max) { + if (s->rep->send_max && + !(s->rep->flags & BF_FULL) && + s->rep->lr <= s->rep->r && + s->rep->r <= s->rep->data + s->rep->size - global.tune.maxrewrite) + s->rep->flags |= BF_EXPECT_MORE; + } /* we're removing the analysers, we MUST re-enable events detection */ buffer_auto_read(s->req);