From e5596bf53f086bad49aeac0c00a9f57e6b2cd1a3 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Wed, 2 Dec 2020 16:13:22 +0100 Subject: [PATCH] MEDIUM: mux-h1: Don't emit any payload for bodyless responses Some responses must not contain data. Reponses to HEAD requests and 204/304 xresponses. But there is no warranty that this will be really respected by the senders or even if it is possible. For instance, the method may be rewritten by an http-request rule (HEAD->GET). Thus, it is not really possible to always strip the payload from the response at the receive stage. And the response may be emitted by an applet or an internal service not strictly following the spec. All that to say that we may be prepared to handle payload for bodyless responses on the sending path. So, thanks to previous patches, it is now possible to know on the sending path if a response must be bodyless or not. So, for such responses, no payload is emitted, all HTX blocks after the EOH are silently removed (including the trailers). --- src/mux_h1.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/mux_h1.c b/src/mux_h1.c index 277220b2e7..7b99f1a79c 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -1690,7 +1690,12 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun htx_nbblks(chn_htx) == 1 && htx_get_blk_type(blk) == HTX_BLK_DATA && htx_get_blk_value(chn_htx, blk).len == count) { - void *old_area = h1c->obuf.area; + void *old_area; + + if ((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP)) { + TRACE_PROTO("Skip data for bodyless response", H1_EV_TX_DATA|H1_EV_TX_BODY, h1c->conn, h1s, chn_htx); + goto skip_zero_copy; + } TRACE_PROTO("sending message data (zero-copy)", H1_EV_TX_DATA|H1_EV_TX_BODY, h1c->conn, h1s, chn_htx, (size_t[]){count}); if (h1m->state == H1_MSG_DATA && chn_htx->flags & HTX_FL_EOM) { @@ -1698,6 +1703,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun last_data = 1; } + old_area = h1c->obuf.area; h1c->obuf.area = buf->area; h1c->obuf.head = sizeof(struct htx) + blk->addr; h1c->obuf.data = count; @@ -1722,7 +1728,6 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun } } - total += count; if (h1m->state == H1_MSG_DATA) TRACE_PROTO((!(h1m->flags & H1_MF_RESP) ? "H1 request payload data xferred" : "H1 response payload data xferred"), H1_EV_TX_DATA|H1_EV_TX_BODY, h1c->conn, h1s, 0, (size_t[]){count}); @@ -1730,6 +1735,8 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun TRACE_PROTO((!(h1m->flags & H1_MF_RESP) ? "H1 request tunneled data xferred" : "H1 response tunneled data xferred"), H1_EV_TX_DATA|H1_EV_TX_BODY, h1c->conn, h1s, 0, (size_t[]){count}); + skip_zero_copy: + total += count; if (last_data) { h1m->state = H1_MSG_DONE; if (h1s->h1c->flags & H1C_F_WAIT_OUTPUT) { @@ -1878,7 +1885,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun if ((h1s->meth != HTTP_METH_CONNECT && (h1m->flags & (H1_MF_VER_11|H1_MF_RESP|H1_MF_CLEN|H1_MF_CHNK|H1_MF_XFER_LEN)) == (H1_MF_VER_11|H1_MF_XFER_LEN)) || - (h1s->status >= 200 && h1s->status != 204 && h1s->status != 304 && h1s->meth != HTTP_METH_HEAD && + (h1s->status >= 200 && !(h1s->flags & H1S_F_BODYLESS_RESP) && !(h1s->meth == HTTP_METH_CONNECT && h1s->status >= 200 && h1s->status < 300) && (h1m->flags & (H1_MF_VER_11|H1_MF_RESP|H1_MF_CLEN|H1_MF_CHNK|H1_MF_XFER_LEN)) == (H1_MF_VER_11|H1_MF_RESP|H1_MF_XFER_LEN))) { @@ -1935,12 +1942,6 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun h1s->flags &= ~H1S_F_HAVE_O_CONN; TRACE_STATE("1xx response xferred", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1c->conn, h1s); } - else if ((h1m->flags & H1_MF_RESP) && h1s->meth == HTTP_METH_HEAD) { - if (!chunk_memcat(&tmp, "\r\n", 2)) - goto full; - TRACE_STATE("HEAD response processed", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1c->conn, h1s); - goto done; - } else { /* EOM flag is set and it is the last block */ if (htx_is_unique_blk(chn_htx, blk) && (chn_htx->flags & HTX_FL_EOM)) { @@ -1969,6 +1970,11 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun else if (type != HTX_BLK_DATA) goto error; + if (h1m->state == H1_MSG_DATA && (h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP)) { + TRACE_PROTO("Skip data for bodyless response", H1_EV_TX_DATA|H1_EV_TX_BODY, h1c->conn, h1s, chn_htx); + break; + } + TRACE_PROTO("sending message data", H1_EV_TX_DATA|H1_EV_TX_BODY, h1c->conn, h1s, chn_htx, (size_t[]){sz}); /* It is the last block of this message. After this one, @@ -2035,6 +2041,11 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun if (!(h1m->flags & H1_MF_CHNK)) break; + if ((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP)) { + TRACE_PROTO("Skip trailers for bodyless response", H1_EV_TX_DATA|H1_EV_TX_BODY, h1c->conn, h1s, chn_htx); + break; + } + if (type == HTX_BLK_EOT) { if (!chunk_memcat(&tmp, "\r\n", 2)) goto full; -- 2.39.5