From 5e205524ad24003ecc4dbb435066aebe7ed58d95 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 17 Dec 2011 16:34:27 +0100 Subject: BUG: http: re-enable TCP quick-ack upon incomplete HTTP requests By default we disable TCP quick-acking on HTTP requests so that we avoid sending a pure ACK immediately followed by the HTTP response. However, if the client sends an incomplete request in a short packet, its TCP stack might wait for this packet to be ACKed before sending the rest of the request, delaying incoming requests by up to 40-200ms. We can detect this undesirable situation when parsing the request : - if an incomplete request is received - if a full request is received and uses chunked encoding or advertises a content-length larger than the data available in the buffer In these situations, we re-enable TCP quick-ack if we had previously disabled it. --- src/proto_http.c | 25 ++++++++++++++++++++++++- 1 files changed, 24 insertions(+), 1 deletions(-) diff --git a/src/proto_http.c b/src/proto_http.c index 87115d2..14dc24b 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -2582,6 +2584,15 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit) buffer_dont_connect(req); req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */ s->rep->flags &= ~BF_EXPECT_MORE; /* speed up sending a previous response */ +#ifdef TCP_QUICKACK + if (s->listener->options & LI_O_NOQUICKACK) { + /* We need more data, we have to re-enable quick-ack in case we + * previously disabled it, otherwise we might cause the client + * to delay next data. + */ + setsockopt(s->si[0].fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); + } +#endif if ((msg->msg_state != HTTP_MSG_RQBEFORE) && (txn->flags & TX_WAIT_NEXT_RQ)) { /* If the client starts to talk, let's fall back to @@ -3692,8 +3703,20 @@ int http_process_request(struct session *s, struct buffer *req, int an_bit) req->analysers |= AN_REQ_HTTP_BODY; } - if (txn->flags & TX_REQ_XFER_LEN) + if (txn->flags & TX_REQ_XFER_LEN) { req->analysers |= AN_REQ_HTTP_XFER_BODY; +#ifdef TCP_QUICKACK + /* We expect some data from the client. Unless we know for sure + * we already have a full request, we have to re-enable quick-ack + * in case we previously disabled it, otherwise we might cause + * the client to delay further data. + */ + if ((s->listener->options & LI_O_NOQUICKACK) && + ((txn->flags & TX_REQ_TE_CHNK) || + (msg->body_len > req->l - txn->req.eoh - 2))) + setsockopt(s->si[0].fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); +#endif + } /************************************************************* * OK, that's finished for the headers. We have done what we * -- 1.7.2.3