BUG/MEDIUM: mux-h2: always set :authority on request output

PiBa-NL reported that some servers don't fall back to the Host header when
:authority is absent. After studying all the combinations of Host and
:authority, it appears that we always have to send the latter, hence we
never need the former. In case of CONNECT method, the authority is retrieved
from the URI part, otherwise it's extracted from the Host field.

The tricky part is that we have to scan all headers for the Host header
before dumping other headers. This is due to the fact that we must emit
pseudo headers before other ones. One improvement could possibly be made
later in the request parser to search and emit the Host header immediately
if authority was not found. This would cost nothing on the vast marjority
of requests and make the lookup faster on output since Host would appear
first.

This fix must be backported to 1.9.
This commit is contained in:
Willy Tarreau 2019-02-01 16:13:59 +01:00
parent 5be92ff23f
commit 053c15750b

View File

@ -4333,7 +4333,7 @@ static size_t h2s_htx_bck_make_req_headers(struct h2s *h2s, struct htx *htx)
struct htx_blk *blk_end; struct htx_blk *blk_end;
struct buffer outbuf; struct buffer outbuf;
struct htx_sl *sl; struct htx_sl *sl;
struct ist meth, path; struct ist meth, path, auth;
enum htx_blk_type type; enum htx_blk_type type;
int es_now = 0; int es_now = 0;
int ret = 0; int ret = 0;
@ -4446,12 +4446,36 @@ static size_t h2s_htx_bck_make_req_headers(struct h2s *h2s, struct htx *htx)
goto realign_again; goto realign_again;
goto full; goto full;
} }
/* look for the Host header and place it in :authority */
auth = ist2(NULL, 0);
for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); hdr++) {
if (isteq(list[hdr].n, ist("")))
break; // end
if (isteq(list[hdr].n, ist("host"))) {
auth = list[hdr].v;
break;
}
}
}
else {
/* for CONNECT, :authority is taken from the path */
auth = path;
}
if (auth.ptr && !hpack_encode_header(&outbuf, ist(":authority"), auth)) {
/* output full */
if (b_space_wraps(&h2c->mbuf))
goto realign_again;
goto full;
} }
/* encode all headers, stop at empty name */ /* encode all headers, stop at empty name */
for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); hdr++) { for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); hdr++) {
/* these ones do not exist in H2 and must be dropped. */ /* these ones do not exist in H2 and must be dropped. */
if (isteq(list[hdr].n, ist("connection")) || if (isteq(list[hdr].n, ist("connection")) ||
isteq(list[hdr].n, ist("host")) ||
isteq(list[hdr].n, ist("proxy-connection")) || isteq(list[hdr].n, ist("proxy-connection")) ||
isteq(list[hdr].n, ist("keep-alive")) || isteq(list[hdr].n, ist("keep-alive")) ||
isteq(list[hdr].n, ist("upgrade")) || isteq(list[hdr].n, ist("upgrade")) ||