From dcd8c5eed4a4843a5ccd7ae7f4c252d3ac9460d1 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 21 Jan 2019 11:24:38 +0100 Subject: [PATCH] BUG/MINOR: proto-htx: Return an error if all headers cannot be received at once When an HTX stream is waiting for a request or a response, it reports an error (400 for the request or 502 for the response) if a parsing error is reported by the mux (HTX_FL_PARSING_ERROR). The mux-h1 uses this error, among other things, when the headers are too big to be analyzed at once. But the mux-h2 doesn't. So the stream must also report an error if the multiplexer is unable to emit all headers at once. The multiplexers must always emit all the headers at once otherwise it is an error. There are 2 ways to detect this error: * The end-of-headers marker was not received yet _AND_ the HTX message is not empty. * The end-of-headers marker was not received yet _AND_ the multiplexer have some data to emit but it is waiting for more space in the channel's buffer. Note the mux-h2 is buggy for now when HTX is enabled. It does not respect the reserve. So there is no way to hit this bug. This patch must be backported to 1.9. --- src/proto_htx.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/proto_htx.c b/src/proto_htx.c index 9fa820653..9e285f216 100644 --- a/src/proto_htx.c +++ b/src/proto_htx.c @@ -126,9 +126,12 @@ int htx_wait_for_request(struct stream *s, struct channel *req, int an_bit) */ if (unlikely(htx_is_empty(htx) || htx_get_tail_type(htx) < HTX_BLK_EOH)) { /* - * First catch invalid request + * First catch invalid request because of a parsing error or + * because only part of headers have been transfered. + * Multiplexers have the responsibility to emit all headers at + * once. */ - if (htx->flags & HTX_FL_PARSING_ERROR) { + if ((htx->flags & HTX_FL_PARSING_ERROR) || htx_is_not_empty(htx) || (s->si[0].flags & SI_FL_RXBLK_ROOM)) { stream_inc_http_req_ctr(s); stream_inc_http_err_ctr(s); proxy_inc_fe_req_ctr(sess->fe); @@ -1086,7 +1089,7 @@ int htx_wait_for_request_body(struct stream *s, struct channel *req, int an_bit) * been received or if the buffer is full. */ if (htx_get_tail_type(htx) >= HTX_BLK_EOD || - htx_used_space(htx) + global.tune.maxrewrite >= htx->size) + channel_htx_full(req, htx, global.tune.maxrewrite)) goto http_end; missing_data: @@ -1457,9 +1460,14 @@ int htx_wait_for_response(struct stream *s, struct channel *rep, int an_bit) */ if (unlikely(co_data(rep) || htx_is_empty(htx) || htx_get_tail_type(htx) < HTX_BLK_EOH)) { /* - * First catch invalid response + * First catch invalid response because of a parsing error or + * because only part of headers have been transfered. + * Multiplexers have the responsibility to emit all headers at + * once. We must be sure to have forwarded all outgoing data + * first. */ - if (htx->flags & HTX_FL_PARSING_ERROR) + if (!co_data(rep) && + ((htx->flags & HTX_FL_PARSING_ERROR) || htx_is_not_empty(htx) || (s->si[1].flags & SI_FL_RXBLK_ROOM))) goto return_bad_res; /* 1: have we encountered a read error ? */