MAJOR: http: move buffer->lr to http_msg->next

The buffer's pointer <lr> was only used by HTTP parsers which also use a
struct http_msg to keep track of the parser's state. We've reached a point
where it makes no sense to keep ->lr in the buffer, as the split between
buffer and msg is only arbitrary for historical reasons.

This change ensures that touching buffers will not impact HTTP messages
anymore, making the buffers more content-agnostic. However, it becomes
very important not to forget to update msg->next when some data get
forwarded or moved (and in general each time buf->p is updated).

The new pointer in http_msg becomes relative to buffer->p so that
parsing multiple messages becomes easier. It is possible that at one
point ->som and ->next will be merged.

Note: http_parse_reqline() and http_parse_stsline() have been temporarily
modified to know the message starting point in the buffer (->p).
diff --git a/include/proto/buffers.h b/include/proto/buffers.h
index 2b2b2ac..a95e5a1 100644
--- a/include/proto/buffers.h
+++ b/include/proto/buffers.h
@@ -62,7 +62,7 @@
 	buf->analysers = 0;
 	buf->cons = NULL;
 	buf->flags = BF_OUT_EMPTY;
-	buf->lr = buf->p = buf->data;
+	buf->p = buf->data;
 }
 
 /*****************************************************************/
@@ -317,7 +317,7 @@
 	buf->o = 0;
 	buf->i = 0;
 	buf->to_forward = 0;
-	buf->lr = buf->p = buf->data;
+	buf->p = buf->data;
 	buf->flags &= ~(BF_FULL | BF_OUT_EMPTY);
 	if (!buf->pipe)
 		buf->flags |= BF_OUT_EMPTY;
@@ -338,7 +338,6 @@
 		return;
 
 	buf->i = 0;
-	buf->lr = buf->p;
 	buf->flags &= ~BF_FULL;
 	if (buffer_len(buf) >= buffer_max_len(buf))
 		buf->flags |= BF_FULL;
@@ -442,7 +441,7 @@
 {
 	if (!(buf->i | buf->o)) {
 		/* let's realign the buffer to optimize I/O */
-		buf->p = buf->lr = buf->data;
+		buf->p = buf->data;
 	}
 	return buffer_contig_space(buf);
 }
@@ -457,7 +456,7 @@
 {
 	buf->o -= len;
 	if (buffer_len(buf) == 0)
-		buf->p = buf->lr = buf->data;
+		buf->p = buf->data;
 
 	if (buffer_len(buf) < buffer_max_len(buf))
 		buf->flags &= ~BF_FULL;
diff --git a/include/proto/proto_http.h b/include/proto/proto_http.h
index 0eed363..e7d1da6 100644
--- a/include/proto/proto_http.h
+++ b/include/proto/proto_http.h
@@ -113,6 +113,7 @@
 /* to be used when contents change in an HTTP message */
 #define http_msg_move_end(msg, bytes) do { \
 		unsigned int _bytes = (bytes);	\
+		(msg)->next += (_bytes);	\
 		(msg)->col += (_bytes);		\
 		(msg)->sov += (_bytes);		\
 		(msg)->eoh += (_bytes);		\
diff --git a/include/types/buffers.h b/include/types/buffers.h
index 5925455..ab56129 100644
--- a/include/types/buffers.h
+++ b/include/types/buffers.h
@@ -180,7 +180,6 @@
 	int wex;                        /* expiration date for a write or connect, in ticks */
 	int rto;                        /* read timeout, in ticks */
 	int wto;                        /* write timeout, in ticks */
-	char *lr;                       /* last read read */
 	char *p;                        /* buffer's start pointer, separates in and out data */
 	unsigned int size;              /* buffer size in bytes */
 	unsigned int i;                 /* number of input bytes pending for analysis in the buffer */
diff --git a/include/types/proto_http.h b/include/types/proto_http.h
index 463149a..02468fa 100644
--- a/include/types/proto_http.h
+++ b/include/types/proto_http.h
@@ -304,6 +304,7 @@
 struct http_msg {
 	unsigned int msg_state;                /* where we are in the current message parsing */
 	unsigned int flags;                    /* flags describing the message (HTTP version, ...) */
+	unsigned int next;                     /* pointer to next byte to parse, relative to buf->p */
 	unsigned int col, sov;                 /* current header: colon, start of value */
 	unsigned int eoh;                      /* End Of Headers, relative to buffer */
 	char *sol;                             /* start of line, also start of message when fully parsed */
diff --git a/src/buffers.c b/src/buffers.c
index 91a0cbb..0352177 100644
--- a/src/buffers.c
+++ b/src/buffers.c
@@ -315,12 +315,13 @@
 
 /* This function writes the string <str> at position <pos> which must be in
  * buffer <b>, and moves <end> just after the end of <str>. <b>'s parameters
- * (l, r, lr) are updated to be valid after the shift. the shift value
+ * <l> and <r> are updated to be valid after the shift. The shift value
  * (positive or negative) is returned. If there's no space left, the move is
- * not done. The function does not adjust ->o nor BF_OUT_EMPTY because
- * it does not make sense to use it on data scheduled to be sent. The string
- * length is taken from parameter <len>. If <len> is null, the <str> pointer
- * is allowed to be null.
+ * not done. The function does not adjust ->o nor BF_OUT_EMPTY because it
+ * does not make sense to use it on data scheduled to be sent. For the same
+ * reason, it does not make sense to call this function on unparsed data, so
+ * <orig> is not updated. The string length is taken from parameter <len>. If
+ * <len> is null, the <str> pointer is allowed to be null.
  */
 int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int len)
 {
@@ -343,13 +344,11 @@
 	if (len)
 		memcpy(pos, str, len);
 
-	/* we only move data after the displaced zone */
-	if (b->lr > pos) b->lr += delta;
 	b->i += delta;
 
 	b->flags &= ~BF_FULL;
 	if (buffer_len(b) == 0)
-		b->p = b->lr = b->data;
+		b->p = b->data;
 	if (buffer_len(b) >= buffer_max_len(b))
 		b->flags |= BF_FULL;
 
@@ -361,7 +360,8 @@
  * argument informs about the length of string <str> so that we don't have to
  * measure it. It does not include the "\r\n". If <str> is NULL, then the buffer
  * is only opened for len+2 bytes but nothing is copied in. It may be useful in
- * some circumstances. The send limit is *not* adjusted.
+ * some circumstances. The send limit is *not* adjusted. Same comments as above
+ * for the valid use cases.
  *
  * The number of bytes added is returned on success. 0 is returned on failure.
  */
@@ -384,8 +384,6 @@
 		pos[len + 1] = '\n';
 	}
 
-	/* we only move data after the displaced zone */
-	if (b->lr > pos) b->lr += delta;
 	b->i += delta;
 
 	b->flags &= ~BF_FULL;
@@ -569,8 +567,8 @@
 void buffer_dump(FILE *o, struct buffer *b, int from, int to)
 {
 	fprintf(o, "Dumping buffer %p\n", b);
-	fprintf(o, "  data=%p o=%d i=%d p=%p lr=%p\n",
-		b->data, b->o, b->i, b->p, b->lr);
+	fprintf(o, "  data=%p o=%d i=%d p=%p\n",
+		b->data, b->o, b->i, b->p);
 
 	if (!to || to > buffer_len(b))
 		to = buffer_len(b);
diff --git a/src/dumpstats.c b/src/dumpstats.c
index d0baa71..106ea8c 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -3389,13 +3389,13 @@
 
 		chunk_printf(&msg,
 			     " wex=%s\n"
-			     "      data=%p p=%d lr=%d total=%lld\n",
+			     "      data=%p p=%d next=%d total=%lld\n",
 			     sess->req->wex ?
 			     human_time(TICKS_TO_MS(sess->req->wex - now_ms),
 					TICKS_TO_MS(1000)) : "<NEVER>",
 			     sess->req->data,
 			     (int)(sess->req->p - sess->req->data),
-			     (int)(sess->req->lr - sess->req->data),
+			     sess->txn.req.next,
 			     sess->req->total);
 
 		chunk_printf(&msg,
@@ -3418,13 +3418,13 @@
 
 		chunk_printf(&msg,
 			     " wex=%s\n"
-			     "      data=%p p=%d lr=%d total=%lld\n",
+			     "      data=%p p=%d next=%d total=%lld\n",
 			     sess->rep->wex ?
 			     human_time(TICKS_TO_MS(sess->rep->wex - now_ms),
 					TICKS_TO_MS(1000)) : "<NEVER>",
 			     sess->rep->data,
 			     (int)(sess->rep->p - sess->rep->data),
-			     (int)(sess->rep->lr - sess->rep->data),
+			     sess->txn.rsp.next,
 			     sess->rep->total);
 
 		if (buffer_feed_chunk(si->ib, &msg) >= 0)
diff --git a/src/proto_http.c b/src/proto_http.c
index aebca1b..bf9980c 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -390,17 +390,17 @@
 {
 	int size = 0;
 	size += snprintf(trash + size, sizeof(trash) - size,
-			 "[%04d] req: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p lr=%p sm=%d fw=%ld tf=%08x\n",
+			 "[%04d] req: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p o=%p sm=%d fw=%ld tf=%08x\n",
 			 line,
 			 s->si[0].state, s->si[0].fd, s->txn.req.msg_state, s->req->flags, s->req->analysers,
-			 s->req->data, s->req->size, s->req->l, s->req->w, s->req->r, s->req->lr, s->req->o, s->req->to_forward, s->txn.flags);
+			 s->req->data, s->req->size, s->req->l, s->req->w, s->req->r, s->req->p, s->req->o, s->req->to_forward, s->txn.flags);
 	write(-1, trash, size);
 	size = 0;
 	size += snprintf(trash + size, sizeof(trash) - size,
-			 " %04d  rep: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p lr=%p sm=%d fw=%ld\n",
+			 " %04d  rep: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p o=%p sm=%d fw=%ld\n",
 			 line,
 			 s->si[1].state, s->si[1].fd, s->txn.rsp.msg_state, s->rep->flags, s->rep->analysers,
-			 s->rep->data, s->rep->size, s->rep->l, s->rep->w, s->rep->r, s->rep->lr, s->rep->o, s->rep->to_forward);
+			 s->rep->data, s->rep->size, s->rep->l, s->rep->w, s->rep->r, s->rep->p, s->rep->o, s->rep->to_forward);
 
 	write(-1, trash, size);
 }
@@ -951,8 +951,9 @@
  * labels and variable names. Note that msg->sol is left unchanged.
  */
 const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
+			       const char *msg_start,
 			       unsigned int state, const char *ptr, const char *end,
-			       char **ret_ptr, unsigned int *ret_state)
+			       unsigned int *ret_ptr, unsigned int *ret_state)
 {
 	switch (state)	{
 	case HTTP_MSG_RPVER:
@@ -1035,7 +1036,7 @@
 	if (ret_state)
 		*ret_state = state;
 	if (ret_ptr)
-		*ret_ptr = (char *)ptr;
+		*ret_ptr = ptr - msg_start;
 	return NULL;
 }
 
@@ -1059,8 +1060,9 @@
  * labels and variable names. Note that msg->sol is left unchanged.
  */
 const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
+			       const char *msg_start,
 			       unsigned int state, const char *ptr, const char *end,
-			       char **ret_ptr, unsigned int *ret_state)
+			       unsigned int *ret_ptr, unsigned int *ret_state)
 {
 	switch (state)	{
 	case HTTP_MSG_RQMETH:
@@ -1177,7 +1179,7 @@
 	if (ret_state)
 		*ret_state = state;
 	if (ret_ptr)
-		*ret_ptr = (char *)ptr;
+		*ret_ptr = ptr - msg_start;
 	return NULL;
 }
 
@@ -1278,7 +1280,7 @@
 	register char *ptr, *end; /* request pointers, to avoid dereferences */
 
 	state = msg->msg_state;
-	ptr = buf->lr;
+	ptr = buffer_wrap_add(buf, buf->p + msg->next);
 	end = buffer_wrap_add(buf, buf->p + buf->i);
 
 	if (unlikely(ptr >= end))
@@ -1332,8 +1334,9 @@
 	case HTTP_MSG_RPCODE:
 	case HTTP_MSG_RPCODE_SP:
 	case HTTP_MSG_RPREASON:
-		ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
-						 &buf->lr, &msg->msg_state);
+		ptr = (char *)http_parse_stsline(msg, buf->data, buf->p,
+						 state, ptr, end,
+						 &msg->next, &msg->msg_state);
 		if (unlikely(!ptr))
 			return;
 
@@ -1402,8 +1405,9 @@
 	case HTTP_MSG_RQURI:
 	case HTTP_MSG_RQURI_SP:
 	case HTTP_MSG_RQVER:
-		ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
-						 &buf->lr, &msg->msg_state);
+		ptr = (char *)http_parse_reqline(msg, buf->data, buf->p,
+						 state, ptr, end,
+						 &msg->next, &msg->msg_state);
 		if (unlikely(!ptr))
 			return;
 
@@ -1561,8 +1565,8 @@
 		/* Assumes msg->sol points to the first of either CR or LF */
 		EXPECT_LF_HERE(ptr, http_msg_invalid);
 		ptr++;
-		buf->lr = ptr;
-		msg->col = msg->sov = buf->lr - buf->data;
+		msg->next = ptr - buf->p;
+		msg->col = msg->sov = ptr - buf->data;
 		msg->eoh = msg->sol - buf->data;
 		msg->sol = buf->data + msg->som;
 		msg->msg_state = HTTP_MSG_BODY;
@@ -1581,13 +1585,13 @@
  http_msg_ood:
 	/* out of data */
 	msg->msg_state = state;
-	buf->lr = ptr;
+	msg->next = ptr - buf->p;
 	return;
 
  http_msg_invalid:
 	/* invalid message */
 	msg->msg_state = HTTP_MSG_ERROR;
-	buf->lr = ptr;
+	msg->next = ptr - buf->p;
 	return;
 }
 
@@ -1616,7 +1620,7 @@
 	delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
 	http_msg_move_end(msg, delta);
 	cur_end += delta;
-	cur_end = (char *)http_parse_reqline(msg, req->data,
+	cur_end = (char *)http_parse_reqline(msg, req->data, req->p,
 					     HTTP_MSG_RQMETH,
 					     msg->sol, cur_end + 1,
 					     NULL, NULL);
@@ -1741,7 +1745,7 @@
 	return;
 }
 
-/* Parse the chunk size at buf->lr. Once done, it adjusts ->lr to point to the
+/* Parse the chunk size at msg->next. Once done, it adjusts ->next to point to the
  * first byte of body, and increments msg->sov by the number of bytes parsed,
  * so that we know we can forward between ->som and ->sov. Note that due to
  * possible wrapping at the end of the buffer, it is possible that msg->sov is
@@ -1751,7 +1755,8 @@
  */
 int http_parse_chunk_size(struct buffer *buf, struct http_msg *msg)
 {
-	char *ptr = buf->lr;
+	char *ptr = buffer_wrap_add(buf, buf->p + msg->next);
+	char *ptr_old = ptr;
 	char *end = buf->data + buf->size;
 	char *stop = buffer_wrap_add(buf, buf->p + buf->i);
 	unsigned int chunk = 0;
@@ -1775,7 +1780,7 @@
 	}
 
 	/* empty size not allowed */
-	if (ptr == buf->lr)
+	if (ptr == ptr_old)
 		goto error;
 
 	while (http_is_spht[(unsigned char)*ptr]) {
@@ -1826,11 +1831,11 @@
 	}
 
 	/* OK we found our CRLF and now <ptr> points to the next byte,
-	 * which may or may not be present. We save that into ->lr and
+	 * which may or may not be present. We save that into ->next and
 	 * ->sov.
 	 */
-	msg->sov += ptr - buf->lr;
-	buf->lr = ptr;
+	msg->sov += ptr - ptr_old;
+	msg->next = buffer_count(buf, buf->p, ptr);
 	msg->chunk_len = chunk;
 	msg->body_len += chunk;
 	msg->msg_state = chunk ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
@@ -1841,13 +1846,13 @@
 }
 
 /* This function skips trailers in the buffer <buf> associated with HTTP
- * message <msg>. The first visited position is buf->lr. If the end of
+ * message <msg>. The first visited position is msg->next. If the end of
  * the trailers is found, it is automatically scheduled to be forwarded,
  * msg->msg_state switches to HTTP_MSG_DONE, and the function returns >0.
  * If not enough data are available, the function does not change anything
- * except maybe buf->lr and msg->sov if it could parse some lines, and returns
+ * except maybe msg->next and msg->sov if it could parse some lines, and returns
  * zero. If a parse error is encountered, the function returns < 0 and does not
- * change anything except maybe buf->lr and msg->sov. Note that the message
+ * change anything except maybe msg->next and msg->sov. Note that the message
  * must already be in HTTP_MSG_TRAILERS state before calling this function,
  * which implies that all non-trailers data have already been scheduled for
  * forwarding, and that the difference between msg->som and msg->sov exactly
@@ -1857,10 +1862,10 @@
  */
 int http_forward_trailers(struct buffer *buf, struct http_msg *msg)
 {
-	/* we have buf->lr which points to next line. Look for CRLF. */
+	/* we have msg->next which points to next line. Look for CRLF. */
 	while (1) {
 		char *p1 = NULL, *p2 = NULL;
-		char *ptr = buf->lr;
+		char *ptr = buffer_wrap_add(buf, buf->p + msg->next);
 		char *stop = buffer_wrap_add(buf, buf->p + buf->i);
 		int bytes;
 
@@ -1894,7 +1899,7 @@
 		if (p2 >= buf->data + buf->size)
 			p2 = buf->data;
 
-		bytes = p2 - buf->lr;
+		bytes = p2 - buffer_wrap_add(buf, buf->p + msg->next);
 		if (bytes < 0)
 			bytes += buf->size;
 
@@ -1903,23 +1908,24 @@
 		if (msg->sov >= buf->size)
 			msg->sov -= buf->size;
 
-		if (p1 == buf->lr) {
+		if (p1 == buffer_wrap_add(buf, buf->p + msg->next)) {
 			/* LF/CRLF at beginning of line => end of trailers at p2.
 			 * Everything was scheduled for forwarding, there's nothing
 			 * left from this message.
 			 */
-			buf->lr = p2;
+			msg->next = buffer_count(buf, buf->p, p2);
 			msg->msg_state = HTTP_MSG_DONE;
 			return 1;
 		}
 		/* OK, next line then */
-		buf->lr = p2;
+		msg->next = buffer_count(buf, buf->p, p2);
 	}
 }
 
 /* This function may be called only in HTTP_MSG_DATA_CRLF. It reads the CRLF or
  * a possible LF alone at the end of a chunk. It automatically adjusts msg->sov,
- * ->som, buf->lr in order to include this part into the next forwarding phase.
+ * ->som, ->next in order to include this part into the next forwarding phase.
+ * Note that the caller must ensure that ->p points to the first byte to parse.
  * It also sets msg_state to HTTP_MSG_CHUNK_SIZE and returns >0 on success. If
  * not enough data are available, the function does not change anything and
  * returns zero. If a parse error is encountered, the function returns < 0 and
@@ -1936,7 +1942,7 @@
 	 * against the correct length.
 	 */
 	bytes = 1;
-	ptr = buf->lr;
+	ptr = buf->p;
 	if (*ptr == '\r') {
 		bytes++;
 		ptr++;
@@ -1955,7 +1961,7 @@
 	ptr++;
 	if (ptr >= buf->data + buf->size)
 		ptr = buf->data;
-	buf->lr = ptr;
+	msg->next = bytes;
 	/* prepare the CRLF to be forwarded. msg->som may be before data but we don't care */
 	msg->sov = ptr - buf->data;
 	msg->som = msg->sov - bytes;
@@ -1990,7 +1996,6 @@
 
 	/* adjust all known pointers */
 	buf->p = buf->data;
-	buf->lr  += off; if (buf->lr  >= end) buf->lr  -= buf->size;
 	msg->sol += off; if (msg->sol >= end) msg->sol -= buf->size;
 	msg->eol += off; if (msg->eol >= end) msg->eol -= buf->size;
 
@@ -2032,7 +2037,7 @@
 	 *   req->data + msg->som  = beginning of request
 	 *   req->data + msg->eoh  = end of processed headers / start of current one
 	 *   msg->eol              = end of current header or line (LF or CRLF)
-	 *   req->lr = first non-visited byte
+	 *   msg->next = first non-visited byte
 	 *   req->r  = end of data
 	 *
 	 * At end of parsing, we may perform a capture of the error (if any), and
@@ -2067,7 +2072,7 @@
 	if (buffer_not_empty(req) && msg->msg_state < HTTP_MSG_ERROR) {
 		if ((txn->flags & TX_NOT_FIRST) &&
 		    unlikely((req->flags & BF_FULL) ||
-			     buffer_wrap_add(req, req->p + req->i) < req->lr ||
+			     buffer_wrap_add(req, req->p + req->i) < buffer_wrap_add(req, req->p + msg->next) ||
 			     buffer_wrap_add(req, req->p + req->i) > req->data + req->size - global.tune.maxrewrite)) {
 			if (req->o) {
 				if (req->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_WRITE_ERROR|BF_WRITE_TIMEOUT))
@@ -2077,7 +2082,7 @@
 				req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
 				return 0;
 			}
-			if (buffer_wrap_add(req, req->p + req->i) < req->lr ||
+			if (buffer_wrap_add(req, req->p + req->i) < buffer_wrap_add(req, req->p + msg->next) ||
 			    buffer_wrap_add(req, req->p + req->i) > req->data + req->size - global.tune.maxrewrite)
 				http_buffer_heavy_realign(req, msg);
 		}
@@ -2091,7 +2096,7 @@
 		 */
 		if ((txn->flags & TX_NOT_FIRST) &&
 		    unlikely((s->rep->flags & BF_FULL) ||
-			     buffer_wrap_add(s->rep, s->rep->p + s->rep->i) < s->rep->lr ||
+			     buffer_wrap_add(s->rep, s->rep->p + s->rep->i) < buffer_wrap_add(s->rep, s->rep->p + txn->rsp.next) ||
 			     buffer_wrap_add(s->rep, s->rep->p + s->rep->i) > s->rep->data + s->rep->size - global.tune.maxrewrite)) {
 			if (s->rep->o) {
 				if (s->rep->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_WRITE_ERROR|BF_WRITE_TIMEOUT))
@@ -2104,7 +2109,7 @@
 			}
 		}
 
-		if (likely(req->lr < buffer_wrap_add(req, req->p + req->i)))
+		if (likely(msg->next < req->i)) /* some unparsed data are available */
 			http_msg_analyzer(req, msg, &txn->hdr_idx);
 	}
 
@@ -2312,7 +2317,7 @@
 	 * complete the request parsing by setting a few fields we will need
 	 * later. At this point, we have the last CRLF at req->data + msg->eoh.
 	 * If the request is in HTTP/0.9 form, the rule is still true, and eoh
-	 * points to the CRLF of the request line. req->lr points to the first
+	 * points to the CRLF of the request line. msg->next points to the first
 	 * byte after the last LF. msg->col and msg->sov point to the first
 	 * byte of data. msg->eol cannot be trusted because it may have been
 	 * left uninitialized (for instance in the absence of headers).
@@ -3589,10 +3594,11 @@
 	if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
 		/* we have msg->col and msg->sov which both point to the first
 		 * byte of message body. msg->som still points to the beginning
-		 * of the message. We must save the body in req->lr because it
+		 * of the message. We must save the body in msg->next because it
 		 * survives buffer re-alignments.
 		 */
-		req->lr = req->data + msg->sov;
+		msg->next = buffer_count(req, req->p, req->data + msg->sov);
+
 		if (msg->flags & HTTP_MSGF_TE_CHNK)
 			msg->msg_state = HTTP_MSG_CHUNK_SIZE;
 		else
@@ -3601,7 +3607,7 @@
 
 	if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
 		/* read the chunk size and assign it to ->chunk_len, then
-		 * set ->sov and ->lr to point to the body and switch to DATA or
+		 * set ->sov and ->next to point to the body and switch to DATA or
 		 * TRAILERS state.
 		 */
 		int ret = http_parse_chunk_size(req, msg);
@@ -3835,9 +3841,6 @@
 	buffer_auto_read(s->rep);
 	buffer_auto_close(s->rep);
 
-	/* make ->lr point to the first non-forwarded byte */
-	s->req->lr = s->req->p;
-	s->rep->lr = s->rep->p;
 	s->req->analysers = s->listener->analysers;
 	s->req->analysers &= ~AN_REQ_DECODE_PROXY;
 	s->rep->analysers = 0;
@@ -4206,10 +4209,11 @@
 	if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
 		/* we have msg->col and msg->sov which both point to the first
 		 * byte of message body. msg->som still points to the beginning
-		 * of the message. We must save the body in req->lr because it
+		 * of the message. We must save the body in msg->next because it
 		 * survives buffer re-alignments.
 		 */
-		req->lr = req->data + msg->sov;
+		msg->next = buffer_count(req, req->p, req->data + msg->sov);
+
 		if (msg->flags & HTTP_MSGF_TE_CHNK)
 			msg->msg_state = HTTP_MSG_CHUNK_SIZE;
 		else {
@@ -4227,6 +4231,7 @@
 			msg->som = msg->sov;
 			if (likely(bytes < 0)) /* sov may have wrapped at the end */
 				bytes += req->size;
+			msg->next -= bytes; /* will be forwarded */
 			msg->chunk_len += (unsigned int)bytes;
 			msg->chunk_len -= buffer_forward(req, msg->chunk_len);
 		}
@@ -4244,7 +4249,7 @@
 		}
 		else if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
 			/* read the chunk size and assign it to ->chunk_len, then
-			 * set ->sov and ->lr to point to the body and switch to DATA or
+			 * set ->sov and ->next to point to the body and switch to DATA or
 			 * TRAILERS state.
 			 */
 			int ret = http_parse_chunk_size(req, msg);
@@ -4263,7 +4268,6 @@
 			/* we want the CRLF after the data */
 			int ret;
 
-			req->lr = req->p;
 			ret = http_skip_chunk_crlf(req, msg);
 
 			if (ret == 0)
@@ -4473,7 +4477,7 @@
 	 *   rep->data + msg->som  = beginning of response
 	 *   rep->data + msg->eoh  = end of processed headers / start of current one
 	 *   msg->eol              = end of current header or line (LF or CRLF)
-	 *   rep->lr = first non-visited byte
+	 *   msg->next = first non-visited byte
 	 *   rep->r  = end of data
 	 * Once we reach MSG_BODY, rep->sol = rep->data + msg->som
 	 */
@@ -4485,7 +4489,7 @@
 	 */
 	if (buffer_not_empty(rep) && msg->msg_state < HTTP_MSG_ERROR) {
 		if (unlikely((rep->flags & BF_FULL) ||
-			     buffer_wrap_add(rep, rep->p + rep->i) < rep->lr ||
+			     buffer_wrap_add(rep, rep->p + rep->i) < buffer_wrap_add(rep, rep->p + msg->next) ||
 			     buffer_wrap_add(rep, rep->p + rep->i) > rep->data + rep->size - global.tune.maxrewrite)) {
 			if (rep->o) {
 				/* some data has still not left the buffer, wake us once that's done */
@@ -4499,7 +4503,7 @@
 				http_buffer_heavy_realign(rep, msg);
 		}
 
-		if (likely(rep->lr < buffer_wrap_add(rep, rep->p + rep->i)))
+		if (likely(msg->next < rep->i))
 			http_msg_analyzer(rep, msg, &txn->hdr_idx);
 	}
 
@@ -5044,7 +5048,7 @@
 		 */
 		if (unlikely(txn->status == 100)) {
 			hdr_idx_init(&txn->hdr_idx);
-			buffer_forward(rep, rep->lr - msg->sol);
+			msg->next -= buffer_forward(rep, rep->p + msg->next - msg->sol);
 			msg->msg_state = HTTP_MSG_RPBEFORE;
 			txn->status = 0;
 			rep->analysers |= AN_RES_WAIT_HTTP | an_bit;
@@ -5268,10 +5272,11 @@
 	if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
 		/* we have msg->col and msg->sov which both point to the first
 		 * byte of message body. msg->som still points to the beginning
-		 * of the message. We must save the body in req->lr because it
+		 * of the message. We must save the body in msg->next because it
 		 * survives buffer re-alignments.
 		 */
-		res->lr = res->data + msg->sov;
+		msg->next = buffer_count(res, res->p, res->data + msg->sov);
+
 		if (msg->flags & HTTP_MSGF_TE_CHNK)
 			msg->msg_state = HTTP_MSG_CHUNK_SIZE;
 		else {
@@ -5289,11 +5294,11 @@
 			msg->som = msg->sov;
 			if (likely(bytes < 0)) /* sov may have wrapped at the end */
 				bytes += res->size;
+			msg->next -= bytes; /* will be forwarded */
 			msg->chunk_len += (unsigned int)bytes;
 			msg->chunk_len -= buffer_forward(res, msg->chunk_len);
 		}
 
-
 		if (msg->msg_state == HTTP_MSG_DATA) {
 			/* must still forward */
 			if (res->to_forward)
@@ -5307,7 +5312,8 @@
 		}
 		else if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
 			/* read the chunk size and assign it to ->chunk_len, then
-			 * set ->sov to point to the body and switch to DATA or TRAILERS state.
+			 * set ->sov and ->next to point to the body and switch to DATA or
+			 * TRAILERS state.
 			 */
 			int ret = http_parse_chunk_size(res, msg);
 
@@ -5324,7 +5330,6 @@
 			/* we want the CRLF after the data */
 			int ret;
 
-			res->lr = res->p;
 			ret = http_skip_chunk_crlf(res, msg);
 
 			if (!ret)
@@ -5402,6 +5407,7 @@
 		msg->som = msg->sov;
 		if (likely(bytes < 0)) /* sov may have wrapped at the end */
 			bytes += res->size;
+		msg->next -= bytes; /* will be forwarded */
 		msg->chunk_len += (unsigned int)bytes;
 		msg->chunk_len -= buffer_forward(res, msg->chunk_len);
 	}
@@ -5698,7 +5704,7 @@
 
 			http_msg_move_end(&txn->req, delta);
 			cur_end += delta;
-			cur_end = (char *)http_parse_reqline(&txn->req, req->data,
+			cur_end = (char *)http_parse_reqline(&txn->req, req->data, req->p,
 							     HTTP_MSG_RQMETH,
 							     cur_ptr, cur_end + 1,
 							     NULL, NULL);
@@ -6537,7 +6543,7 @@
 
 			http_msg_move_end(&txn->rsp, delta);
 			cur_end += delta;
-			cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
+			cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data, rtr->p,
 							     HTTP_MSG_RPVER,
 							     cur_ptr, cur_end + 1,
 							     NULL, NULL);
@@ -7247,10 +7253,10 @@
 
 	if (msg->err_pos >= 0)
 		es->pos  = msg->err_pos - msg->som;
-	else if (buf->lr >= (buf->data + msg->som))
-		es->pos  = buf->lr - (buf->data + msg->som);
+	else if (buffer_wrap_add(buf, buf->p + msg->next) >= (buf->data + msg->som))
+		es->pos  = buffer_wrap_add(buf, buf->p + msg->next) - (buf->data + msg->som);
 	else
-		es->pos  = buf->lr - (buf->data + msg->som) + buf->size;
+		es->pos  = buffer_wrap_add(buf, buf->p + msg->next) - (buf->data + msg->som) + buf->size;
 
 	es->when = date; // user-visible date
 	es->sid  = s->uniq_id;
@@ -7361,9 +7367,11 @@
 	txn->req.flags = 0;
 	txn->req.sol = txn->req.eol = NULL;
 	txn->req.som = txn->req.eoh = 0; /* relative to the buffer */
+	txn->req.next = 0;
 	txn->rsp.flags = 0;
 	txn->rsp.sol = txn->rsp.eol = NULL;
 	txn->rsp.som = txn->rsp.eoh = 0; /* relative to the buffer */
+	txn->rsp.next = 0;
 	txn->req.chunk_len = 0LL;
 	txn->req.body_len = 0LL;
 	txn->rsp.chunk_len = 0LL;
@@ -8118,7 +8126,7 @@
 	}
 
 	/* Try to decode HTTP request */
-	if (likely(req->lr < buffer_wrap_add(req, req->p + req->i)))
+	if (likely(msg->next < req->i))
 		http_msg_analyzer(req, msg, &txn->hdr_idx);
 
 	if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
diff --git a/src/stream_sock.c b/src/stream_sock.c
index 3d462ab..0baf825 100644
--- a/src/stream_sock.c
+++ b/src/stream_sock.c
@@ -282,7 +282,7 @@
 		 */
 		if (buffer_empty(b)) {
 			/* let's realign the buffer to optimize I/O */
-			b->p = b->lr = b->data;
+			b->p = b->data;
 		}
 		else if (b->data + b->o < b->p &&
 			 b->p + b->i < b->data + b->size) {
@@ -647,7 +647,7 @@
 			b->o -= ret;
 			if (likely(!buffer_len(b)))
 				/* optimize data alignment in the buffer */
-				b->lr = b->p = b->data;
+				b->p = b->data;
 
 			if (likely(buffer_len(b) < buffer_max_len(b)))
 				b->flags &= ~BF_FULL;