diff --git a/src/mux_h2.c b/src/mux_h2.c index a16d972c9..9949bbc5c 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -1249,11 +1249,17 @@ static inline __maybe_unused int h2c_mux_busy(const struct h2c *h2c, const struc return 1; } -/* marks an error on the connection */ +/* marks an error on the connection. Before settings are sent, we must not send + * a GOAWAY frame, and the error state will prevent h2c_send_goaway_error() + * from verifying this so we set H2_CF_GOAWAY_FAILED to make sure it will not + * even try. + */ static inline __maybe_unused void h2c_error(struct h2c *h2c, enum h2_err err) { TRACE_POINT(H2_EV_H2C_ERR, h2c->conn, 0, 0, (void *)(long)(err)); h2c->errcode = err; + if (h2c->st0 < H2_CS_SETTINGS1) + h2c->flags |= H2_CF_GOAWAY_FAILED; h2c->st0 = H2_CS_ERROR; } @@ -1879,7 +1885,8 @@ static int h2c_bck_send_preface(struct h2c *h2c) * the message, it subscribes the requester (either or ) to future * notifications. It sets H2_CF_GOAWAY_SENT on success, and H2_CF_GOAWAY_FAILED * on unrecoverable failure. It will not attempt to send one again in this last - * case so that it is safe to use h2c_error() to report such errors. + * case, nor will it send one if settings were not sent (e.g. still waiting for + * a preface) so that it is safe to use h2c_error() to report such errors. */ static int h2c_send_goaway_error(struct h2c *h2c, struct h2s *h2s) { @@ -1889,7 +1896,7 @@ static int h2c_send_goaway_error(struct h2c *h2c, struct h2s *h2s) TRACE_ENTER(H2_EV_TX_FRAME|H2_EV_TX_GOAWAY, h2c->conn); - if (h2c->flags & H2_CF_GOAWAY_FAILED) { + if ((h2c->flags & H2_CF_GOAWAY_FAILED) || h2c->st0 < H2_CS_SETTINGS1) { ret = 1; // claim that it worked goto out; }