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).
This commit is contained in:
Christopher Faulet 2020-12-02 16:13:22 +01:00
parent 5696f5450e
commit e5596bf53f
1 changed files with 20 additions and 9 deletions

View File

@ -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;