]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mux-h1: Add C-L header in outgoing message if it was removed
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 2 Oct 2023 06:44:05 +0000 (08:44 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Wed, 4 Oct 2023 13:34:18 +0000 (15:34 +0200)
If a C-L header was found during parsing of a message but it was removed via
a HTTP action, it is re-added during the message formatting. Indeed, if
headers about the payload are modified, meta-data of the message must also
be updated. Otherwise, it is not possible to guarantee the message will be
properly formatted.

To do so, we rely on the flag H1S_F_HAVE_CLEN.

This patch should not be backported except an issue is explicitly
reported. It relies on "MINOR: mux-h1: Add flags if outgoing msg contains a
header about its payload".

src/mux_h1.c

index b3d2a619d954c44d92751aad0009281a213cc6b8..782dc7025071223e9951ef190437d8dd89199c58 100644 (file)
@@ -2029,6 +2029,11 @@ static size_t h1_make_reqline(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
        h1m->flags |= H1_MF_XFER_LEN;
        if (sl->flags & HTX_SL_F_BODYLESS)
                h1m->flags |= H1_MF_CLEN;
+
+       if (sl->flags & HTX_SL_F_BODYLESS) {
+               h1m->flags = (h1m->flags & ~H1_MF_CHNK) | H1_MF_CLEN;
+               h1s->flags |= H1S_F_HAVE_CLEN;
+       }
        if ((sl->flags & HTX_SL_F_BODYLESS_RESP) || h1s->meth == HTTP_METH_HEAD)
                h1s->flags |= H1S_F_BODYLESS_RESP;
 
@@ -2180,6 +2185,7 @@ static size_t h1_make_headers(struct h1s *h1s, struct h1m *h1m, struct htx *htx,
                                /* Only skip C-L header with invalid value. */
                                if (h1_parse_cont_len_header(h1m, &v) < 0)
                                        goto nextblk; // FIXME: must be handled as an error
+                               h1s->flags |= H1S_F_HAVE_CLEN;
                        }
                        else if (isteq(n, ist("connection"))) {
                                h1_parse_connection_header(h1m, &v);
@@ -2342,6 +2348,23 @@ static size_t h1_make_eoh(struct h1s *h1s, struct h1m *h1m, struct htx *htx, siz
                h1s->flags |= H1S_F_HAVE_CHNK;
        }
 
+       /* Deal with "Content-Length header */
+       if ((h1m->flags & H1_MF_CLEN) && !(h1s->flags & H1S_F_HAVE_CLEN)) {
+               char *end;
+
+               h1m->curr_len = h1m->body_len = htx->data + htx->extra - sz;
+                end = DISGUISE(ulltoa(h1m->body_len, trash.area, b_size(&trash)));
+
+               n = ist("content-length");
+               v = ist2(trash.area, end-trash.area);
+               if (h1c->px->options2 & (PR_O2_H1_ADJ_BUGCLI|PR_O2_H1_ADJ_BUGSRV))
+                       h1_adjust_case_outgoing_hdr(h1s, h1m, &n);
+               if (!h1_format_htx_hdr(n, v, &outbuf))
+                       goto full;
+               TRACE_STATE("add \"Content-Length: chunked\"", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1c->conn, h1s);
+               h1s->flags |= H1S_F_HAVE_CLEN;
+       }
+
        /* Add the server name to a header (if requested) */
        if (!(h1s->flags & H1S_F_HAVE_SRV_NAME) &&
            !(h1m->flags & H1_MF_RESP) && isttest(h1c->px->server_id_hdr_name)) {