MEDIUM: mux-h1: Support C-L/T-E header suppressions when sending messages
During the 2.9 dev cycle, to be able to support zero-copy data forwarding, a change on the H1 mux was performed to ignore the headers modifications about payload representation (Content-Length and Transfer-Encoding headers). It appears there are some use-cases where it could be handy to change values of these headers or just remove them. For instance, we can imagine to remove these headers on a server response to force the old HTTP/1.0 close mode behavior. So thaks to this patch, the rules are relaxed. It is now possible to remove these headers. When this happens, the following rules are applied: * If "Content-Length" header is removed but a "Transfer-Encoding: chunked" header is found, no special processing is performed. The message remains chunked. However the close mode is not forced. * If "Transfer-Encoding" header is removed but a "Content-Length" header is found, no special processing is performed. The payload length must comply to the specified content length. * If one of them is removed and the other one is not found, a response is switch the close mode and a "Content-Length: 0" header is forced on a request. With these rules, we fit the best to the user expectations. This patch depends on the following commit: * MINOR: mux-h1: Add a flag to ignore the request payload This patch should fix the issue #2536. It should be backported it to 2.9 with the commit above.
This commit is contained in:
parent
1a2699d5f7
commit
2fc9e6fa39
55
src/mux_h1.c
55
src/mux_h1.c
@ -2576,6 +2576,44 @@ static size_t h1_make_eoh(struct h1s *h1s, struct h1m *h1m, struct htx *htx, siz
|
||||
b_slow_realign(&h1c->obuf, trash.area, b_data(&h1c->obuf));
|
||||
outbuf = b_make(b_tail(&h1c->obuf), b_contig_space(&h1c->obuf), 0, 0);
|
||||
|
||||
/* Deal with removed "Content-Length" or "Transfer-Encoding" headers during analysis */
|
||||
if (((h1m->flags & H1_MF_CLEN) && !(h1s->flags & H1S_F_HAVE_CLEN))||
|
||||
((h1m->flags & H1_MF_CHNK) && !(h1s->flags & H1S_F_HAVE_CHNK))) {
|
||||
TRACE_STATE("\"Content-Length\" or \"Transfer-Encoding\" header removed during analysis", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1c->conn, h1s);
|
||||
|
||||
if (h1s->flags & (H1S_F_HAVE_CLEN|H1S_F_HAVE_CHNK)) {
|
||||
/* At least on header is present, we can continue */
|
||||
if (!(h1s->flags & H1S_F_HAVE_CLEN)) {
|
||||
h1m->curr_len = h1m->body_len = 0;
|
||||
h1m->flags &= ~H1_MF_CLEN;
|
||||
}
|
||||
else /* h1s->flags & H1S_F_HAVE_CHNK */
|
||||
h1m->flags &= ~(H1_MF_XFER_ENC|H1_MF_CHNK);
|
||||
}
|
||||
else {
|
||||
/* Both headers are missing */
|
||||
if (h1m->flags & H1_MF_RESP) {
|
||||
/* It is a esponse: Switch to unknown xfer length */
|
||||
h1m->flags &= ~(H1_MF_XFER_LEN|H1_MF_XFER_ENC|H1_MF_CLEN|H1_MF_CHNK);
|
||||
h1s->flags &= ~(H1S_F_HAVE_CLEN|H1S_F_HAVE_CHNK);
|
||||
TRACE_STATE("Switch response to unknown XFER length", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1c->conn, h1s);
|
||||
}
|
||||
else {
|
||||
/* It is the request: Add "Content-Length: 0" header and skip payload */
|
||||
struct ist n = ist("content-length");
|
||||
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, ist("0"), &outbuf))
|
||||
goto full;
|
||||
|
||||
h1m->flags = (h1m->flags & ~(H1_MF_XFER_ENC|H1_MF_CHNK)) | H1_MF_CLEN;
|
||||
h1s->flags = (h1s->flags & ~H1S_F_HAVE_CHNK) | (H1S_F_HAVE_CLEN|H1S_F_BODYLESS_REQ);
|
||||
h1m->curr_len = h1m->body_len = 0;
|
||||
TRACE_STATE("Set request content-length to 0 and skip payload", H1_EV_TX_DATA|H1_EV_TX_HDRS, h1c->conn, h1s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Deal with "Connection" header */
|
||||
if (!(h1s->flags & H1S_F_HAVE_O_CONN)) {
|
||||
if ((h1m->flags & (H1_MF_XFER_ENC|H1_MF_CLEN)) == (H1_MF_XFER_ENC|H1_MF_CLEN)) {
|
||||
@ -2626,23 +2664,6 @@ 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: <LEN>\"", 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)) {
|
||||
|
Loading…
Reference in New Issue
Block a user