]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: mux-h1: Add a flag to ignore the request payload
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 16 May 2024 15:11:50 +0000 (17:11 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 17 May 2024 14:33:53 +0000 (16:33 +0200)
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.

include/haproxy/mux_h1-t.h
src/mux_h1.c

index a0b64a9da971f08a6baf6b818f8afd86da30077c..79147abf55e652671d66bf96a9788b2f340966ff 100644 (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;
index a817b8657671e5211ba0b837b17b2730e8b16a38..46ceba439d44facd74f529c1e4d652f41444ee8c 100644 (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);