]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: mux-h2: always set :authority on request output
authorWilly Tarreau <w@1wt.eu>
Fri, 1 Feb 2019 15:13:59 +0000 (16:13 +0100)
committerWilly Tarreau <w@1wt.eu>
Fri, 1 Feb 2019 15:47:46 +0000 (16:47 +0100)
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.

src/mux_h2.c

index 1c6f3d2099d0292c20c3cddbc5751b360715faa6..adf8f144dbf6a3f22d465fdd94f4ddb73e92c1f4 100644 (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 buffer outbuf;
        struct htx_sl *sl;
-       struct ist meth, path;
+       struct ist meth, path, auth;
        enum htx_blk_type type;
        int es_now = 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 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 */
        for (hdr = 0; hdr < sizeof(list)/sizeof(list[0]); hdr++) {
                /* these ones do not exist in H2 and must be dropped. */
                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("keep-alive")) ||
                    isteq(list[hdr].n, ist("upgrade")) ||