MINOR: mux-h1: Add a flag to ignore the request payload

There was a flag to skip the response payload on output, if any, by stating
it is bodyless. It is used for responses to HEAD requests or for 204/304
responses. This allow rewrites during analysis. For instance a HEAD request
can be rewrite to a GET request for any reason (ie, a server not supporting
HEAD requests). In this case, the server will send a response with a
payload. On frontend side, the payload will be skipped and a valid response
(without payload) will be sent to the client.

With this patch we introduce the corresponding flag for the request. It will
be used to skip the request payload. In addition, when payload must be
skipped for a request or a response, The zero-copy data forwarding is now
disabled.
This commit is contained in:
Christopher Faulet 2024-05-16 17:11:50 +02:00
parent 45a45c917a
commit 8e55d29109
2 changed files with 23 additions and 7 deletions

View File

@ -107,6 +107,8 @@ static forceinline char *h1c_show_flags(char *buf, size_t len, const char *delim
#define H1S_F_HAVE_CLEN 0x00010000 /* Set during output process to know C*L header was found or generated */
#define H1S_F_HAVE_CHNK 0x00020000 /* Set during output process to know "T-E; chunk" header was found or generated */
#define H1S_F_BODYLESS_REQ 0x00040000 /* Bodyless request message */
/* This function is used to report flags in debugging tools. Please reflect
* below any single-bit flag addition above in the same order via the
* __APPEND_FLAG macro. The new end of the buffer is returned.
@ -122,7 +124,7 @@ static forceinline char *h1s_show_flags(char *buf, size_t len, const char *delim
_(H1S_F_NOT_FIRST, _(H1S_F_BODYLESS_RESP,
_(H1S_F_INTERNAL_ERROR, _(H1S_F_NOT_IMPL_ERROR, _(H1S_F_PARSING_ERROR, _(H1S_F_PROCESSING_ERROR,
_(H1S_F_HAVE_SRV_NAME, _(H1S_F_HAVE_O_CONN, _(H1S_F_HAVE_WS_KEY,
_(H1S_F_HAVE_CLEN, _(H1S_F_HAVE_CHNK)))))))))))))))));
_(H1S_F_HAVE_CLEN, _(H1S_F_HAVE_CHNK, _(H1S_F_BODYLESS_REQ))))))))))))))))));
/* epilogue */
_(~0U);
return buf;

View File

@ -2797,7 +2797,8 @@ static size_t h1_make_data(struct h1s *h1s, struct h1m *h1m, struct buffer *buf,
* end-to-end. This is the situation that happens all the time with
* large files.
*/
if ((!(h1m->flags & H1_MF_RESP) || !(h1s->flags & H1S_F_BODYLESS_RESP)) &&
if (((!(h1m->flags & H1_MF_RESP) && !(h1s->flags & H1S_F_BODYLESS_REQ)) ||
((h1m->flags & H1_MF_RESP) && !(h1s->flags & H1S_F_BODYLESS_RESP))) &&
!b_data(&h1c->obuf) &&
(!(h1m->flags & H1_MF_CHNK) || ((h1m->flags & H1_MF_CHNK) && (!h1m->curr_len || count == h1m->curr_len))) &&
htx_nbblks(htx) == 1 &&
@ -2924,8 +2925,9 @@ static size_t h1_make_data(struct h1s *h1s, struct h1m *h1m, struct buffer *buf,
last_data = 1;
}
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, htx);
if ((!(h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_REQ)) ||
((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP))) {
TRACE_PROTO("Skip data for bodyless message", H1_EV_TX_DATA|H1_EV_TX_BODY, h1c->conn, h1s, htx);
goto nextblk;
}
@ -2996,7 +2998,8 @@ static size_t h1_make_data(struct h1s *h1s, struct h1m *h1m, struct buffer *buf,
}
else if (type == HTX_BLK_EOT || type == HTX_BLK_TLR) {
if ((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP)) {
if ((!(h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_REQ)) ||
((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP))) {
/* Do nothing the payload must be skipped
* because it is a bodyless response
*/
@ -3196,7 +3199,9 @@ static size_t h1_make_trailers(struct h1s *h1s, struct h1m *h1m, struct htx *htx
if (sz > count)
goto error;
if (!(h1m->flags & H1_MF_CHNK) || ((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP)))
if (!(h1m->flags & H1_MF_CHNK) ||
(!(h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_REQ)) ||
((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP)))
goto nextblk;
n = htx_get_blk_name(htx, blk);
@ -3209,7 +3214,9 @@ static size_t h1_make_trailers(struct h1s *h1s, struct h1m *h1m, struct htx *htx
goto full;
}
else if (type == HTX_BLK_EOT) {
if (!(h1m->flags & H1_MF_CHNK) || ((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP))) {
if (!(h1m->flags & H1_MF_CHNK) ||
(!(h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_REQ)) ||
((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP))) {
TRACE_PROTO((!(h1m->flags & H1_MF_RESP) ? "H1 request trailers skipped" : "H1 response trailers skipped"),
H1_EV_TX_DATA|H1_EV_TX_TLRS, h1c->conn, h1s);
}
@ -4592,6 +4599,13 @@ static size_t h1_nego_ff(struct stconn *sc, struct buffer *input, size_t count,
goto out;
}
if ((!(h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_REQ)) ||
((h1m->flags & H1_MF_RESP) && (h1s->flags & H1S_F_BODYLESS_RESP))) {
TRACE_STATE("Bodyless message, disable fastfwd", H1_EV_STRM_SEND|H1_EV_STRM_ERR, h1c->conn, h1s);
h1s->sd->iobuf.flags |= IOBUF_FL_NO_FF;
goto out;
}
if (h1m->flags & H1_MF_CLEN) {
if ((flags & NEGO_FF_FL_EXACT_SIZE) && count > h1m->curr_len) {
TRACE_ERROR("more payload than announced", H1_EV_STRM_SEND|H1_EV_STRM_ERR, h1c->conn, h1s);