MEDIUM: filters: remove http_start_chunk, http_last_chunk and http_chunk_end

For Chunked HTTP request/response, the body filtering can be really
expensive. In the worse case (many chunks of 1 bytes), the filters overhead is
of 3 calls per chunk. If http_data callback is useful, others are just
informative.

So these callbacks has been removed. Of course, existing filters (trace and
compression) has beeen updated accordingly. For the HTTP compression filter, the
update is quite huge. Its implementation is closer to the old one.
diff --git a/src/filters.c b/src/filters.c
index 01dc5fa..88c3612 100644
--- a/src/filters.c
+++ b/src/filters.c
@@ -415,23 +415,6 @@
 	return ret;
 }
 
-int
-flt_http_start_chunk(struct stream *s, struct http_msg *msg)
-{
-	int ret = 1;
-
-	RESUME_FILTER_LOOP(s, msg->chn) {
-		if (filter->ops->http_start_chunk) {
-			ret = filter->ops->http_start_chunk(s, filter, msg);
-			if (ret <= 0)
-				BREAK_EXECUTION(s, msg->chn, end);
-		}
-		FLT_NXT(filter, msg->chn) += msg->sol;
-	} RESUME_FILTER_END;
- end:
-	return ret;
-}
-
 /*
  * Calls 'http_data' callback for all "data" filters attached to a stream. This
  * function is called when incoming data are available (excluding chunks
@@ -451,9 +434,14 @@
 	/* Save buffer state */
 	buf_i = msg->chn->buf->i;
 	list_for_each_entry(filter, &s->strm_flt.filters, list) {
+		/* If the HTTP parser is ahead, we update the next offset of the
+		 * current filter. This happens for chunked messages, at the
+		 * begining of a new chunk. */
+		if (msg->next > FLT_NXT(filter, msg->chn))
+			FLT_NXT(filter, msg->chn) = msg->next;
 		if (filter->ops->http_data && !flt_want_forward_data(filter, msg->chn)) {
 			ret = filter->ops->http_data(s, filter, msg);
-			if (ret < 0)
+			if (ret <= 0)
 				break;
 		}
 		else {
@@ -466,7 +454,7 @@
 			ret = MIN(msg->chunk_len + msg->next, msg->chn->buf->i) - FLT_NXT(filter, msg->chn);
 		}
 
-		/* Increase FLT_NXT offset of the current filter */
+		/* Update the next offset of the current filter */
 		FLT_NXT(filter, msg->chn) += ret;
 
 		/* And set this value as the bound for the next filter. It will
@@ -478,43 +466,6 @@
 	return ret;
 }
 
-int
-flt_http_end_chunk(struct stream *s, struct http_msg *msg)
-{
-	int ret = 1;
-
-	RESUME_FILTER_LOOP(s, msg->chn) {
-		if (filter->ops->http_end_chunk) {
-			ret = filter->ops->http_end_chunk(s, filter, msg);
-			if (ret <= 0)
-				BREAK_EXECUTION(s, msg->chn, end);
-		}
-		flt_reset_forward_data(filter, msg->chn);
-		FLT_NXT(filter, msg->chn) += msg->sol;
-	} RESUME_FILTER_END;
- end:
-	return ret;
-}
-
-int
-flt_http_last_chunk(struct stream *s, struct http_msg *msg)
-{
-	int ret = 1;
-
-	RESUME_FILTER_LOOP(s, msg->chn) {
-		if (filter->ops->http_last_chunk) {
-			ret = filter->ops->http_last_chunk(s, filter, msg);
-			if (ret <= 0)
-				BREAK_EXECUTION(s, msg->chn, end);
-		}
-		flt_reset_forward_data(filter, msg->chn);
-		FLT_NXT(filter, msg->chn) += msg->sol;
-	} RESUME_FILTER_END;
- end:
-	return ret;
-}
-
-
 /*
  * Calls 'http_chunk_trailers' callback for all "data" filters attached to a
  * stream. This function is called for chunked messages only when a part of the
@@ -526,17 +477,23 @@
 int
 flt_http_chunk_trailers(struct stream *s, struct http_msg *msg)
 {
-	int ret = 1;
+	struct filter *filter;
+	int            ret = 1;
 
-	RESUME_FILTER_LOOP(s, msg->chn) {
+	list_for_each_entry(filter, &s->strm_flt.filters, list) {
+		/* Be sure to set the next offset of the filter at the right
+		 * place. This is really useful when the first part of the
+		 * trailers was parsed. */
+		FLT_NXT(filter, msg->chn) = msg->next;
 		if (filter->ops->http_chunk_trailers) {
 			ret = filter->ops->http_chunk_trailers(s, filter, msg);
-			if (ret <= 0)
-				BREAK_EXECUTION(s, msg->chn, end);
+			if (ret < 0)
+				break;
 		}
+		/* Update the next offset of the current filter. Here all data
+		 * are always consumed. */
 		FLT_NXT(filter, msg->chn) += msg->sol;
-	} RESUME_FILTER_END;
-end:
+	}
 	return ret;
 }
 
@@ -610,6 +567,11 @@
 	int            ret = len;
 
 	list_for_each_entry(filter, &s->strm_flt.filters, list) {
+		/* If the HTTP parser is ahead, we update the next offset of the
+		 * current filter. This happens for chunked messages, when the
+		 * chunk envelope is parsed. */
+		if (msg->next > FLT_NXT(filter, msg->chn))
+			FLT_NXT(filter, msg->chn) = msg->next;
 		if (filter->ops->http_forward_data) {
 			/*  Remove bytes that the current filter considered as
 			 *  forwarded */
diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c
index ddc607d..5dacc90 100644
--- a/src/flt_http_comp.c
+++ b/src/flt_http_comp.c
@@ -34,29 +34,14 @@
 
 static struct buffer *tmpbuf = &buf_empty;
 
-struct comp_chunk {
-	unsigned int start;   /* start of the chunk relative to FLT_FWD offset */
-	unsigned int end;     /* end of the chunk relative to FLT_FWD offset */
-	int          skip;    /* if set to 1, the chunk is skipped. Otherwise it is compressed */
-	int          is_last; /* if set, this is the last chunk. Data after this
-			       * chunk will be forwarded as it is. */
-	struct list  list;
-};
-
 struct comp_state {
 	struct comp_ctx  *comp_ctx;   /* compression context */
 	struct comp_algo *comp_algo;  /* compression algorithm if not NULL */
-	struct list  comp_chunks;     /* data chunks that should be compressed or skipped */
-	unsigned int first;           /* offset of the first chunk. Data before
-				       * this offset will be forwarded as it
-				       * is. */
+	int sov;
+	int consumed;
+	int initialized;
 };
 
-static int add_comp_chunk(struct comp_state *st, unsigned int start,
-			  unsigned int len, int skip, int is_last);
-static int skip_input_data(struct filter *filter, struct http_msg *msg,
-			   unsigned int consumed);
-
 static int select_compression_request_header(struct comp_state *st,
 					     struct stream *s,
 					     struct http_msg *msg);
@@ -70,7 +55,7 @@
 					    struct buffer *out, int sz);
 static int http_compression_buffer_end(struct comp_state *st, struct stream *s,
 				       struct buffer **in, struct buffer **out,
-				       unsigned int consumed, int end);
+				       int end);
 
 /***********************************************************************/
 static int
@@ -104,11 +89,12 @@
 		if (!(st = malloc(sizeof(*st))))
 			return -1;
 
-		LIST_INIT(&st->comp_chunks);
-		st->comp_algo = NULL;
-		st->comp_ctx = NULL;
-		st->first    = 0;
-		filter->ctx  = st;
+		st->comp_algo   = NULL;
+		st->comp_ctx    = NULL;
+		st->sov         = 0;
+		st->consumed    = 0;
+		st->initialized = 0;
+		filter->ctx     = st;
 	}
 	return 1;
 }
@@ -125,6 +111,8 @@
 	switch (an_bit) {
 		case AN_RES_HTTP_PROCESS_BE:
 			select_compression_response_header(st, s, &s->txn->rsp);
+			if (st->comp_algo)
+				st->sov = s->txn->rsp.sov;
 			break;
 	}
   end:
@@ -135,16 +123,10 @@
 comp_end_analyze(struct stream *s, struct filter *filter, struct channel *chn)
 {
 	struct comp_state *st = filter->ctx;
-	struct comp_chunk *cc, *back;
 
 	if (!st || !(chn->flags & CF_ISRESP))
 		goto end;
 
-	list_for_each_entry_safe(cc, back, &st->comp_chunks, list) {
-		LIST_DEL(&cc->list);
-		free(cc);
-	}
-
 	if (!st->comp_algo || !s->txn->status)
 		goto release_ctx;
 
@@ -177,11 +159,10 @@
 }
 
 static int
-comp_skip_http_chunk_envelope(struct stream *s, struct filter *filter,
-			      struct http_msg *msg)
+comp_http_data(struct stream *s, struct filter *filter, struct http_msg *msg)
 {
 	struct comp_state *st = filter->ctx;
-	unsigned int       start;
+	unsigned int       len;
 	int                ret;
 
 	if (!(msg->chn->flags & CF_ISRESP) || !st->comp_algo) {
@@ -189,230 +170,103 @@
 		return 1;
 	}
 
-	start = FLT_NXT(filter, msg->chn) - FLT_FWD(filter, msg->chn);
-	/* If this is the last chunk, we flag it */
-	if (msg->chunk_len == 0 && msg->msg_state == HTTP_MSG_CHUNK_SIZE)
-		ret = add_comp_chunk(st, start, 0, 1, 1);
-	else
-		ret = add_comp_chunk(st, start, msg->sol, 1, 0);
+	len = MIN(msg->chunk_len + msg->next, msg->chn->buf->i) - FLT_NXT(filter, msg->chn);
+	if (!len)
+		return len;
+
+	if (!st->initialized) {
+		b_adv(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->sov);
+		ret = http_compression_buffer_init(msg->chn->buf, tmpbuf);
+		b_rew(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->sov);
+		if (ret < 0) {
+			msg->chn->flags |= CF_WAKE_WRITE;
+			return 0;
+		}
+	}
+	b_adv(msg->chn->buf, FLT_NXT(filter, msg->chn));
+	ret = http_compression_buffer_add_data(st, msg->chn->buf, tmpbuf, len);
+	b_rew(msg->chn->buf, FLT_NXT(filter, msg->chn));
+	if (ret < 0)
+		return ret;
 
-	return !ret ? 1 : -1;
+	st->initialized = 1;
+	msg->next      += ret;
+	msg->chunk_len -= ret;
+	FLT_NXT(filter, msg->chn) = msg->next;
+	return 0;
 }
 
 static int
-comp_http_data(struct stream *s, struct filter *filter,
-		  struct http_msg *msg)
+comp_http_chunk_trailers(struct stream *s, struct filter *filter,
+			 struct http_msg *msg)
 {
 	struct comp_state *st = filter->ctx;
-	unsigned int       start;
-	int                is_last, ret;
+	int                ret;
 
-	ret = MIN(msg->chunk_len + msg->next, msg->chn->buf->i) - FLT_NXT(filter, msg->chn);
 	if (!(msg->chn->flags & CF_ISRESP) || !st->comp_algo) {
 		flt_set_forward_data(filter, msg->chn);
-		goto end;
+		return 1;
 	}
-	if (!ret)
-		goto end;
 
-	start   = FLT_NXT(filter, msg->chn) - FLT_FWD(filter, msg->chn);
-	is_last = (!(msg->flags & HTTP_MSGF_TE_CHNK) &&
-		   (msg->chunk_len == ret - msg->next + FLT_NXT(filter, msg->chn)));
+	if (!st->initialized)
+		return 1;
 
-	if (add_comp_chunk(st, start, ret, 0, is_last) == -1)
-		ret = -1;
- end:
-	return ret;
+	st->consumed = msg->next - st->sov;
+	b_adv(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->sov);
+	ret = http_compression_buffer_end(st, s, &msg->chn->buf, &tmpbuf, 1);
+	if (ret < 0)
+		return ret;
+
+	st->initialized = 0;
+	st->sov         = 0;
+	msg->next       = ret;
+	FLT_NXT(filter, msg->chn) = ret;
+	FLT_FWD(filter, msg->chn) = 0;
+	return 1;
 }
 
+
 static int
 comp_http_forward_data(struct stream *s, struct filter *filter,
 		       struct http_msg *msg, unsigned int len)
 {
 	struct comp_state *st = filter->ctx;
-	struct comp_chunk *cc, *back;
-	unsigned int       sz, consumed = 0, compressed = 0;
-	int                is_last = 0, ret = len;
+	int                ret;
 
 	if (!(msg->chn->flags & CF_ISRESP) || !st->comp_algo) {
 		flt_set_forward_data(filter, msg->chn);
-		goto end;
-	}
-
-	/* no data to forward or no chunk or the first chunk is too far */
-	if (!len || LIST_ISEMPTY(&st->comp_chunks))
-		goto end;
-	if (st->first > len) {
-		consumed = len;
-		goto update_chunks;
-	}
-
-	/* initialize the buffer used to write compressed data */
-	b_adv(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->first);
-	ret = http_compression_buffer_init(msg->chn->buf, tmpbuf);
-	b_rew(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->first);
-	if (ret < 0) {
-		msg->chn->flags |= CF_WAKE_WRITE;
-		return 0;
+		ret = len;
+		return ret;
 	}
 
-	/* Loop on all chunks */
-	list_for_each_entry_safe(cc, back, &st->comp_chunks, list) {
-		/* current chunk must not be handled yet */
-		if (len <= cc->start) {
-			consumed = len;
-			break;
-		}
-
-		/* Get the number of bytes that must be handled in the current
-		 * chunk */
-		sz = MIN(len, cc->end) - cc->start;
-
-		if (cc->skip) {
-			/* No compression for this chunk, data must be
-			 * skipped. This happens when the HTTP response is
-			 * chunked, the chunk envelope is skipped. */
-			ret = sz;
-		}
-		else {
-			/* Compress the chunk */
-			b_adv(msg->chn->buf, FLT_FWD(filter, msg->chn) + cc->start);
-			ret = http_compression_buffer_add_data(st, msg->chn->buf, tmpbuf, sz);
-			b_rew(msg->chn->buf, FLT_FWD(filter, msg->chn) + cc->start);
-			if (ret < 0)
-				goto end;
-			compressed += ret;
-		}
-
-		/* Update the chunk by removing consumed bytes. If all bytes are
-		 * consumed, the chunk is removed from the list and we
-		 * loop. Otherwise, we stop here. */
-		cc->start += ret;
-		consumed = cc->start;
-		if (cc->start != cc->end)
-			break;
-
-		/* Remember if this is the last chunk */
-		is_last = cc->is_last;
-		LIST_DEL(&cc->list);
-		free(cc);
-	}
-
-	if (compressed) {
-		/* Some data was compressed so we can switch buffers to replace
-		 * uncompressed data by compressed ones. */
-		b_adv(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->first);
-		ret = http_compression_buffer_end(st, s, &msg->chn->buf, &tmpbuf,
-						  consumed - st->first, is_last);
-		b_rew(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->first);
-	}
-	else {
-		/* Here some data was consumed but no compression was
-		 * preformed. This means that all consumed data must be
-		 * skipped.
-		 */
-		ret = skip_input_data(filter, msg, consumed);
-	}
-
-	if (is_last && !(msg->flags & HTTP_MSGF_TE_CHNK)) {
-		/* At the end of data, if the original response was not
-		 * chunked-encoded, we must write the empty chunk 0<CRLF>, and
-		 * terminate the (empty) trailers section with a last <CRLF>. If
-		 * we're forwarding a chunked-encoded response, these parts are
-		 * preserved and not rewritten.
-		 */
-		char *p = bi_end(msg->chn->buf);
-		memcpy(p, "0\r\n\r\n", 5);
-		msg->chn->buf->i += 5;
-		ret += 5;
+	/* To work, previous filters MUST forward all data */
+	if (FLT_FWD(filter, msg->chn) + len != FLT_NXT(filter, msg->chn)) {
+		Warning("HTTP compression failed: unexpected behavior of previous filters\n");
+		return -1;
 	}
 
-	/* Then, the last step. We need to update state of other filters. */
-	if (ret >= 0) {
-		flt_change_forward_size(filter, msg->chn, -(consumed - st->first - ret));
-		msg->next -= (consumed - st->first - ret);
-		ret += st->first;
+	if (!st->initialized) {
+		ret = len;
+		st->sov = ((st->sov > ret) ?  (st->sov-ret) : 0);
+		return ret;
 	}
 
- update_chunks:
-	/* Now, we need to update all remaining chunks to keep them synchronized
-	 * with the next position of buf->p. If the chunk list is empty, we
-	 * forward remaining data, if any. */
-	st->first -= MIN(st->first, consumed);
-	if (LIST_ISEMPTY(&st->comp_chunks))
-		ret += len - consumed;
-	else {
-		list_for_each_entry(cc, &st->comp_chunks, list) {
-			cc->start -= consumed;
-			cc->end   -= consumed;
-		}
-	}
+	st->consumed = len - st->sov;
+	b_adv(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->sov);
+	ret = http_compression_buffer_end(st, s, &msg->chn->buf, &tmpbuf,
+					  msg->msg_state == HTTP_MSG_ENDING);
+	if (ret < 0)
+		return ret;
 
- end:
+	st->initialized = 0;
+	st->sov         = 0;
+	msg->next       = ret;
+	FLT_NXT(filter, msg->chn) = ret;
+	FLT_FWD(filter, msg->chn) = 0;
 	return ret;
 }
 
 /***********************************************************************/
-static int
-add_comp_chunk(struct comp_state *st, unsigned int start, unsigned int len,
-	       int skip, int is_last)
-{
-	struct comp_chunk *cc;
-
-	if (!(cc = malloc(sizeof(*cc))))
-		return -1;
-	cc->start   = start;
-	cc->end     = start + len;
-	cc->skip    = skip;
-	cc->is_last = is_last;
-
-	if (LIST_ISEMPTY(&st->comp_chunks))
-		st->first = cc->start;
-
-	LIST_ADDQ(&st->comp_chunks, &cc->list);
-	return 0;
-}
-
-/* This function might be moved in a filter function, probably with others to
- * add/remove/move/replace buffer data */
-static int
-skip_input_data(struct filter *filter, struct http_msg *msg,
-		unsigned int consumed)
-{
-	struct comp_state *st = filter->ctx;
-	int                block1, block2;
-
-	/* 1. Copy input data, skipping consumed ones. */
-	b_adv(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->first + consumed);
-	block1 = msg->chn->buf->i;
-	if (block1 > bi_contig_data(msg->chn->buf))
-		block1 = bi_contig_data(msg->chn->buf);
-	block2 = msg->chn->buf->i - block1;
-
-	memcpy(trash.str, bi_ptr(msg->chn->buf), block1);
-	if (block2 > 0)
-		memcpy(trash.str + block1, msg->chn->buf->data, block2);
-	trash.len = block1 + block2;
-	b_rew(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->first + consumed);
-
-	/* 2. Then write back these data at the right place in the buffer */
-	b_adv(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->first);
-	block1 = trash.len;
-	if (block1 > bi_contig_data(msg->chn->buf))
-		block1 = bi_contig_data(msg->chn->buf);
-	block2 = trash.len - block1;
-
-	memcpy(bi_ptr(msg->chn->buf), trash.str, block1);
-	if (block2 > 0)
-		memcpy(msg->chn->buf->data, trash.str + block1, block2);
-	b_rew(msg->chn->buf, FLT_FWD(filter, msg->chn) + st->first);
-
-	/* Then adjut the input size */
-	msg->chn->buf->i -= consumed;
-	return 0;
-}
-
-/***********************************************************************/
 /*
  * Selects a compression algorithm depending on the client request.
  */
@@ -740,7 +594,7 @@
 static int
 http_compression_buffer_end(struct comp_state *st, struct stream *s,
 			    struct buffer **in, struct buffer **out,
-			    unsigned int consumed, int end)
+			    int end)
 {
 	struct buffer *ib = *in, *ob = *out;
 	char *tail;
@@ -804,21 +658,39 @@
 	*tail++ = '\r';
 	*tail++ = '\n';
 
+	/* At the end of data, we must write the empty chunk 0<CRLF>,
+	 * and terminate the trailers section with a last <CRLF>. If
+	 * we're forwarding a chunked-encoded response, we'll have a
+	 * trailers section after the empty chunk which needs to be
+	 * forwarded and which will provide the last CRLF. Otherwise
+	 * we write it ourselves.
+	 */
+	if (end) {
+		struct http_msg *msg = &s->txn->rsp;
+
+		memcpy(tail, "0\r\n", 3);
+		tail += 3;
+		if (msg->msg_state == HTTP_MSG_ENDING) {
+			memcpy(tail, "\r\n", 2);
+			tail += 2;
+		}
+	}
+
 	ob->i = tail - ob->p;
 	to_forward = ob->i;
 
 	/* update input rate */
 	if (st->comp_ctx && st->comp_ctx->cur_lvl > 0) {
-		update_freq_ctr(&global.comp_bps_in, consumed);
-		strm_fe(s)->fe_counters.comp_in += consumed;
-		s->be->be_counters.comp_in      += consumed;
+		update_freq_ctr(&global.comp_bps_in, st->consumed);
+		strm_fe(s)->fe_counters.comp_in += st->consumed;
+		s->be->be_counters.comp_in      += st->consumed;
 	} else {
-		strm_fe(s)->fe_counters.comp_byp += consumed;
-		s->be->be_counters.comp_byp      += consumed;
+		strm_fe(s)->fe_counters.comp_byp += st->consumed;
+		s->be->be_counters.comp_byp      += st->consumed;
 	}
 
 	/* copy the remaining data in the tmp buffer. */
-	b_adv(ib, consumed);
+	b_adv(ib, st->consumed);
 	if (ib->i > 0) {
 		left = bi_contig_data(ib);
 		memcpy(ob->p + ob->i, bi_ptr(ib), left);
@@ -854,10 +726,8 @@
 	.channel_end_analyze   = comp_end_analyze,
 
 	.http_headers      = comp_http_headers,
-	.http_start_chunk  = comp_skip_http_chunk_envelope,
-	.http_end_chunk    = comp_skip_http_chunk_envelope,
-	.http_last_chunk   = comp_skip_http_chunk_envelope,
 	.http_data         = comp_http_data,
+	.http_chunk_trailers = comp_http_chunk_trailers,
 	.http_forward_data = comp_http_forward_data,
 };
 
diff --git a/src/proto_http.c b/src/proto_http.c
index 3b39e9c..ab608fe 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2214,9 +2214,10 @@
 	/* we have msg->next which points to next line. Look for CRLF. */
 	while (1) {
 		const char *p1 = NULL, *p2 = NULL;
-		const char *ptr = b_ptr(buf, msg->next + msg->sol);
-		const char *stop = bi_end(buf);
-		int bytes;
+		const char *start = b_ptr(buf, msg->next + msg->sol);
+		const char *stop  = bi_end(buf);
+		const char *ptr   = start;
+		int bytes = 0;
 
 		/* scan current line and stop at LF or CRLF */
 		while (1) {
@@ -2248,19 +2249,17 @@
 		if (p2 >= buf->data + buf->size)
 			p2 = buf->data;
 
-		bytes = p2 - b_ptr(buf, msg->next + msg->sol);
+		bytes = p2 - start;
 		if (bytes < 0)
 			bytes += buf->size;
+		msg->sol += bytes;
 
 		/* LF/CRLF at beginning of line => end of trailers at p2.
 		 * Everything was scheduled for forwarding, there's nothing left
-		 * from this message.
-		 */
-		if (p1 == b_ptr(buf, msg->next + msg->sol)) {
-			msg->sol += bytes;
+		 * from this message. */
+		if (p1 == start)
 			return 1;
-		}
-		msg->sol += bytes;
+
 		/* OK, next line then */
 	}
 }
@@ -5541,27 +5540,15 @@
 			 * set ->next to point to the body and switch to DATA or
 			 * TRAILERS state.
 			 */
-			if (!msg->sol) {
-				ret = http_parse_chunk_size(msg);
-				if (ret == 0)
-					goto missing_data;
-				else if (ret < 0) {
-					stream_inc_http_err_ctr(s);
-					if (msg->err_pos >= 0)
-						http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_CHUNK_SIZE, s->be);
-					goto return_bad_req;
-				}
+			ret = http_parse_chunk_size(msg);
+			if (ret == 0)
+				goto missing_data;
+			else if (ret < 0) {
+				stream_inc_http_err_ctr(s);
+				if (msg->err_pos >= 0)
+					http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_CHUNK_SIZE, s->be);
+				goto return_bad_req;
 			}
-			if (msg->chunk_len)
-				FLT_STRM_CB(s, flt_http_start_chunk(s, msg),
-					    /* default_ret */ 1,
-					    /* on_error    */ goto return_bad_req,
-					    /* on_wait     */ goto missing_data);
-			else
-				FLT_STRM_CB(s, flt_http_last_chunk(s, msg),
-					    /* default_ret */ 1,
-					    /* on_error    */ goto return_bad_req,
-					    /* on_wait     */ goto missing_data);
 			msg->next += msg->sol;
 			msg->sol   = 0;
 			msg->msg_state = msg->chunk_len ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
@@ -5569,41 +5556,31 @@
 		}
 		else if (msg->msg_state == HTTP_MSG_CHUNK_CRLF) {
 			/* we want the CRLF after the data */
-			if (!msg->sol) {
-				ret = http_skip_chunk_crlf(msg);
-				if (ret == 0)
-					goto missing_data;
-				else if (ret < 0) {
-					stream_inc_http_err_ctr(s);
-					if (msg->err_pos >= 0)
-						http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_CHUNK_CRLF, s->be);
-					goto return_bad_req;
-				}
+			ret = http_skip_chunk_crlf(msg);
+			if (ret == 0)
+				goto missing_data;
+			else if (ret < 0) {
+				stream_inc_http_err_ctr(s);
+				if (msg->err_pos >= 0)
+					http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_CHUNK_CRLF, s->be);
+				goto return_bad_req;
 			}
-			FLT_STRM_CB(s, flt_http_end_chunk(s, msg),
-				    /* default_ret */ 1,
-				    /* on_error    */ goto return_bad_req,
-				    /* on_wait     */ goto missing_data);
 			msg->next += msg->sol;
 			msg->sol   = 0;
 			msg->msg_state = HTTP_MSG_CHUNK_SIZE;
 			/* we're in MSG_CHUNK_SIZE now */
 		}
 		else if (msg->msg_state == HTTP_MSG_TRAILERS) {
-			ret = 1;
-			if (!msg->sol) {
-				ret = http_forward_trailers(msg);
-				if (ret < 0) {
-					stream_inc_http_err_ctr(s);
-					if (msg->err_pos >= 0)
-						http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_TRAILERS, s->be);
-					goto return_bad_req;
-				}
+			ret = http_forward_trailers(msg);
+			if (ret < 0) {
+				stream_inc_http_err_ctr(s);
+				if (msg->err_pos >= 0)
+					http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_TRAILERS, s->be);
+				goto return_bad_req;
 			}
 			FLT_STRM_CB(s, flt_http_chunk_trailers(s, msg),
 				    /* default_ret */ 1,
-				    /* on_error    */ goto return_bad_req,
-				    /* on_wait     */ goto missing_data);
+				    /* on_error    */ goto return_bad_req);
 			msg->next += msg->sol;
 			msg->sol   = 0;
 			if (!ret)
@@ -6866,20 +6843,14 @@
 
 		case HTTP_MSG_CHUNK_CRLF - HTTP_MSG_DATA:
 			/* we want the CRLF after the data */
-			if (!msg->sol) {
-				ret = http_skip_chunk_crlf(msg);
-				if (ret == 0)
-					goto missing_data;
-				else if (ret < 0) {
-					if (msg->err_pos >= 0)
-						http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_CHUNK_CRLF, sess->fe);
-					goto return_bad_res;
-				}
+			ret = http_skip_chunk_crlf(msg);
+			if (ret == 0)
+				goto missing_data;
+			else if (ret < 0) {
+				if (msg->err_pos >= 0)
+					http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_CHUNK_CRLF, sess->fe);
+				goto return_bad_res;
 			}
-			FLT_STRM_CB(s, flt_http_end_chunk(s, msg),
-				    /* default_ret */ 1,
-				    /* on_error    */ goto return_bad_res,
-				    /* on_wait     */ goto missing_data);
 			msg->next += msg->sol;
 			msg->sol   = 0;
 			msg->msg_state = HTTP_MSG_CHUNK_SIZE;
@@ -6890,46 +6861,33 @@
 			 * set ->next to point to the body and switch to DATA or
 			 * TRAILERS state.
 			 */
-			if (!msg->sol) {
-				ret = http_parse_chunk_size(msg);
-				if (ret == 0)
-					goto missing_data;
-				else if (ret < 0) {
-					if (msg->err_pos >= 0)
-						http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_CHUNK_SIZE, sess->fe);
-					goto return_bad_res;
-				}
+			ret = http_parse_chunk_size(msg);
+			if (ret == 0)
+				goto missing_data;
+			else if (ret < 0) {
+				if (msg->err_pos >= 0)
+					http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_CHUNK_SIZE, sess->fe);
+				goto return_bad_res;
 			}
-			if (msg->chunk_len)
-				FLT_STRM_CB(s, flt_http_start_chunk(s, msg),
-					    /* default_ret */ 1,
-					    /* on_error    */ goto return_bad_res,
-					    /* on_wait     */ goto missing_data);
-			else
-				FLT_STRM_CB(s, flt_http_last_chunk(s, msg),
-					    /* default_ret */ 1,
-					    /* on_error    */ goto return_bad_res,
-					    /* on_wait     */ goto missing_data);
 			msg->next += msg->sol;
 			msg->sol   = 0;
-			msg->msg_state = msg->chunk_len ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
-			/* otherwise we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state */
-			break;
+			if (msg->chunk_len) {
+				msg->msg_state = HTTP_MSG_DATA;
+				break;
+			}
+			msg->msg_state = HTTP_MSG_TRAILERS;
+			/* fall through */
 
 		case HTTP_MSG_TRAILERS - HTTP_MSG_DATA:
-			ret = 1;
-			if (!msg->sol) {
-				ret = http_forward_trailers(msg);
-				if (ret < 0) {
-					if (msg->err_pos >= 0)
-						http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_TRAILERS, sess->fe);
-					goto return_bad_res;
-				}
+			ret = http_forward_trailers(msg);
+			if (ret < 0) {
+				if (msg->err_pos >= 0)
+					http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_TRAILERS, sess->fe);
+				goto return_bad_res;
 			}
 			FLT_STRM_CB(s, flt_http_chunk_trailers(s, msg),
 				    /* default_ret */ 1,
-				    /* on_error    */ goto return_bad_res,
-				    /* on_wait     */ goto missing_data);
+				    /* on_error    */ goto return_bad_res);
 			msg->next += msg->sol;
 			msg->sol   = 0;
 			if (!ret)