mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-03-25 04:17:42 +00:00
MEDIUM: h2: perform a graceful shutdown on "Connection: close"
After some long brainstorming sessions, it appears that "Connection: close" seems to be the best signal from the L7 layer to indicate the need to close the connection. Indeed, in H1 it is only present in very rare cases (eg: certain unrecoverable errors, some of which could remove it now by the way). It will also be added when the L7 layer wants to force the connection to terminate. By default when running in keep-alive mode it is not present. It's worth mentionning that in H1 with persistent connections, we have sort of a concurrency-1 mux and this header field is used the same way. Thus here this patch detects "Connection: close" in response headers and if seen, sends a GOAWAY frame with the highest possible ID so that the client knows that it can quit whenever it wants to. If more aggressive closures are needed in the future, we may decide to advertise the max_id to abort after the current requests and better honor "http-request deny".
This commit is contained in:
parent
1c661986a8
commit
af1e4f5167
32
src/mux_h2.c
32
src/mux_h2.c
@ -2472,6 +2472,7 @@ static int h2s_frt_make_resp_headers(struct h2s *h2s, struct buffer *buf)
|
||||
|
||||
chunk_reset(&outbuf);
|
||||
|
||||
try_again:
|
||||
while (1) {
|
||||
outbuf.str = bo_end(h2c->mbuf);
|
||||
outbuf.size = bo_contig_space(h2c->mbuf);
|
||||
@ -2520,12 +2521,31 @@ static int h2s_frt_make_resp_headers(struct h2s *h2s, struct buffer *buf)
|
||||
|
||||
/* encode all headers, stop at empty name */
|
||||
for (hdr = 1; 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("proxy-connection")) ||
|
||||
isteq(list[hdr].n, ist("keep-alive")) ||
|
||||
isteq(list[hdr].n, ist("upgrade")) ||
|
||||
isteq(list[hdr].n, ist("transfer-encoding")))
|
||||
/* these ones do not exist in H2 and must be dropped. But if we
|
||||
* see "connection: close", we also perform a graceful shutdown
|
||||
* on the connection. Note that the match is not perfect but it
|
||||
* is sufficient for dealing with some deny rules.
|
||||
*/
|
||||
if (isteq(list[hdr].n, ist("connection"))) {
|
||||
if (!(h2c->flags & (H2_CF_GOAWAY_SENT|H2_CF_GOAWAY_FAILED)) &&
|
||||
word_match(list[hdr].v.ptr, list[hdr].v.len, "close", 5)) {
|
||||
if (h2c->last_sid < 0)
|
||||
h2c->last_sid = (1U << 31) - 1;
|
||||
if (h2c_send_goaway_error(h2c, h2s) <= 0) {
|
||||
ret = 0;
|
||||
goto end;
|
||||
}
|
||||
/* OK sent, but this changed the output buffer's
|
||||
* contents hence the write position.
|
||||
*/
|
||||
goto try_again;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (isteq(list[hdr].n, ist("proxy-connection")) ||
|
||||
isteq(list[hdr].n, ist("keep-alive")) ||
|
||||
isteq(list[hdr].n, ist("upgrade")) ||
|
||||
isteq(list[hdr].n, ist("transfer-encoding")))
|
||||
continue;
|
||||
|
||||
if (isteq(list[hdr].n, ist("")))
|
||||
|
Loading…
Reference in New Issue
Block a user