]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: mux-h2: do not send REFUSED_STREAM on aborted uploads
authorWilly Tarreau <w@1wt.eu>
Tue, 6 Aug 2019 08:30:58 +0000 (10:30 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 6 Aug 2019 08:32:02 +0000 (10:32 +0200)
If the server decides to close early, we don't want to send a
REFUSED_STREAM error but a CANCEL, so that the client doesn't want
to retry. The test in h2_do_shutw() was wrong for this as it would
handle the HLOC case like the case where nothing had been sent for
this stream, which is wrong. Now h2_do_shutw() does nothing in this
case and lets h2_do_shutr() decide.

Note that this partially undoes f983d00a1 ("BUG/MINOR: mux-h2: make
the do_shut{r,w} functions more robust against retries").

This must be backported to 2.0. The patch above was not backported to
1.9 for being too risky there, but if it eventually gets to it, this
one will be needed as well.

src/mux_h2.c

index 06eb5f4e02ba50aba53e66d0b9f4cbaf0e6f999b..2b34508fba4527099be0946dd4b5287aa4f85ff2 100644 (file)
@@ -3267,6 +3267,14 @@ static void h2_do_shutr(struct h2s *h2s)
                 */
                h2s_error(h2s, H2_ERR_REFUSED_STREAM);
        }
+       else {
+               /* a final response was already provided, we don't want this
+                * stream anymore. This may happen when the server responds
+                * before the end of an upload and closes quickly (redirect,
+                * deny, ...)
+                */
+               h2s_error(h2s, H2_ERR_CANCEL);
+       }
 
        if (!(h2s->flags & H2_SF_RST_SENT) &&
            h2s_send_rst_stream(h2c, h2s) <= 0)
@@ -3300,11 +3308,10 @@ static void h2_do_shutw(struct h2s *h2s)
        struct h2c *h2c = h2s->h2c;
        struct wait_event *sw = &h2s->wait_event;
 
-       if (h2s->st == H2_SS_CLOSED)
+       if (h2s->st == H2_SS_HLOC || h2s->st == H2_SS_CLOSED)
                goto done;
 
-       if (h2s->st != H2_SS_HLOC && h2s->st != H2_SS_ERROR &&
-           (h2s->flags & H2_SF_HEADERS_SENT)) {
+       if (h2s->st != H2_SS_ERROR && (h2s->flags & H2_SF_HEADERS_SENT)) {
                /* we can cleanly close using an empty data frame only after headers */
 
                if (!(h2s->flags & (H2_SF_ES_SENT|H2_SF_RST_SENT)) &&