From 2ab6eb1e24a28c63e52a825e0e1573ca76d7d49f Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Sat, 2 Jan 2010 22:04:45 +0100
Subject: [PATCH] [MEDIUM] http: make the parsers able to wait for a buffer
 flush

When too large a message lies in a buffer before parsing a new
request/response, we can now wait for previous outgoing data to
leave the buffer before attempting to parse again. After that
we can consider the opportunity to realign the buffer if needed.
---
 src/proto_http.c | 49 +++++++++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/src/proto_http.c b/src/proto_http.c
index 4d5d8e8ce..5eec4b6c2 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2106,21 +2106,24 @@ int http_wait_for_request(struct session *s, struct buffer *req, int an_bit)
 	 * protected area is affected, because we may have to move processed
 	 * data later, which is much more complicated.
 	 */
-	if (req->l &&
-	    (req->r <= req->lr || req->r > req->data + req->size - global.tune.maxrewrite)) {
-		if (req->send_max) {
-			/* some data has still not left the buffer, wake us once that's done */
-			buffer_dont_connect(req);
-			req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
-			return 0;
+	if (req->l && msg->msg_state < HTTP_MSG_ERROR) {
+		if (unlikely((req->flags & BF_FULL) ||
+			     req->r < req->lr ||
+			     req->r > req->data + req->size - global.tune.maxrewrite)) {
+			if (req->send_max) {
+				/* some data has still not left the buffer, wake us once that's done */
+				buffer_dont_connect(req);
+				req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
+				return 0;
+			}
+			if (req->l <= req->size - global.tune.maxrewrite)
+				http_buffer_heavy_realign(req, msg);
 		}
 
-		http_buffer_heavy_realign(req, msg);
+		if (likely(req->lr < req->r))
+			http_msg_analyzer(req, msg, &txn->hdr_idx);
 	}
 
-	if (likely(req->lr < req->r))
-		http_msg_analyzer(req, msg, &txn->hdr_idx);
-
 	/* 1: we might have to print this header in debug mode */
 	if (unlikely((global.mode & MODE_DEBUG) &&
 		     (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
@@ -3456,20 +3459,24 @@ int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit)
 	 * protected area is affected, because we may have to move processed
 	 * data later, which is much more complicated.
 	 */
-	if (rep->l &&
-	    (rep->r <= rep->lr || rep->r > rep->data + rep->size - global.tune.maxrewrite)) {
-		if (rep->send_max) {
-			/* some data has still not left the buffer, wake us once that's done */
-			buffer_dont_close(rep);
-			return 0;
+	if (rep->l && msg->msg_state < HTTP_MSG_ERROR) {
+		if (unlikely((rep->flags & BF_FULL) ||
+			     rep->r < rep->lr ||
+			     rep->r > rep->data + rep->size - global.tune.maxrewrite)) {
+			if (rep->send_max) {
+				/* some data has still not left the buffer, wake us once that's done */
+				buffer_dont_close(rep);
+				rep->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
+				return 0;
+			}
+			if (rep->l <= rep->size - global.tune.maxrewrite)
+				http_buffer_heavy_realign(rep, msg);
 		}
 
-		http_buffer_heavy_realign(rep, msg);
+		if (likely(rep->lr < rep->r))
+			http_msg_analyzer(rep, msg, &txn->hdr_idx);
 	}
 
-	if (likely(rep->lr < rep->r))
-		http_msg_analyzer(rep, msg, &txn->hdr_idx);
-
 	/* 1: we might have to print this header in debug mode */
 	if (unlikely((global.mode & MODE_DEBUG) &&
 		     (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&