mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 23:27:04 +02:00
MEDIUM: mux-h2: Forward h2 client cancellations to h2 servers
When a H2 client sends a RST_STREAM(CANCEL) frame to abort a request, the abort reason is now used on server side, in the H2 mux, to set the RST_STREAM code. The main use case is to forward client cancellations to gRPC applications. This patch should fix the issue #172.
This commit is contained in:
parent
dea79f3fe1
commit
20b156ee15
38
src/mux_h2.c
38
src/mux_h2.c
@ -1264,6 +1264,20 @@ static inline int h2s_mws(const struct h2s *h2s)
|
|||||||
return h2s->sws + h2s->h2c->miw;
|
return h2s->sws + h2s->h2c->miw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns 1 if the H2 error of the opposite side is forwardable to the peer.
|
||||||
|
* Otherwise 0 is returned.
|
||||||
|
* For now, only CANCEL from the client is forwardable to the server.
|
||||||
|
*/
|
||||||
|
static inline int h2s_is_forwardable_abort(struct h2s *h2s, struct se_abort_info *reason)
|
||||||
|
{
|
||||||
|
enum h2_err err = H2_ERR_NO_ERROR;
|
||||||
|
|
||||||
|
if (reason && ((reason->info & SE_ABRT_SRC_MASK) >> SE_ABRT_SRC_SHIFT) == SE_ABRT_SRC_MUX_H2)
|
||||||
|
err = reason->code;
|
||||||
|
|
||||||
|
return ((h2s->h2c->flags & H2_CF_IS_BACK) && (err == H2_ERR_CANCEL));
|
||||||
|
}
|
||||||
|
|
||||||
/* marks an error on the connection. Before settings are sent, we must not send
|
/* 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()
|
* 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
|
* from verifying this so we set H2_CF_GOAWAY_FAILED to make sure it will not
|
||||||
@ -4915,6 +4929,10 @@ static void h2_do_shutr(struct h2s *h2s, struct se_abort_info *reason)
|
|||||||
h2c_error(h2c, H2_ERR_ENHANCE_YOUR_CALM);
|
h2c_error(h2c, H2_ERR_ENHANCE_YOUR_CALM);
|
||||||
h2s_error(h2s, H2_ERR_ENHANCE_YOUR_CALM);
|
h2s_error(h2s, H2_ERR_ENHANCE_YOUR_CALM);
|
||||||
}
|
}
|
||||||
|
else if (h2s_is_forwardable_abort(h2s, reason)) {
|
||||||
|
TRACE_STATE("shutr using opposite endp code", H2_EV_STRM_SHUT, h2c->conn, h2s);
|
||||||
|
h2s_error(h2s, reason->code);
|
||||||
|
}
|
||||||
else if (!(h2s->flags & H2_SF_HEADERS_SENT)) {
|
else if (!(h2s->flags & H2_SF_HEADERS_SENT)) {
|
||||||
/* Nothing was never sent for this stream, so reset with
|
/* Nothing was never sent for this stream, so reset with
|
||||||
* REFUSED_STREAM error to let the client retry the
|
* REFUSED_STREAM error to let the client retry the
|
||||||
@ -4960,8 +4978,9 @@ static void h2_do_shutr(struct h2s *h2s, struct se_abort_info *reason)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Performs a synchronous or asynchronous shutw(). */
|
/* Performs a synchronous or asynchronous shutw(). */
|
||||||
static void h2_do_shutw(struct h2s *h2s)
|
static void h2_do_shutw(struct h2s *h2s, struct se_abort_info *reason)
|
||||||
{
|
{
|
||||||
struct h2c *h2c = h2s->h2c;
|
struct h2c *h2c = h2s->h2c;
|
||||||
|
|
||||||
@ -4971,6 +4990,7 @@ static void h2_do_shutw(struct h2s *h2s)
|
|||||||
TRACE_ENTER(H2_EV_STRM_SHUT, h2c->conn, h2s);
|
TRACE_ENTER(H2_EV_STRM_SHUT, h2c->conn, h2s);
|
||||||
|
|
||||||
if (h2s->st != H2_SS_ERROR &&
|
if (h2s->st != H2_SS_ERROR &&
|
||||||
|
!h2s_is_forwardable_abort(h2s, reason) &&
|
||||||
(h2s->flags & (H2_SF_HEADERS_SENT | H2_SF_MORE_HTX_DATA)) == H2_SF_HEADERS_SENT) {
|
(h2s->flags & (H2_SF_HEADERS_SENT | H2_SF_MORE_HTX_DATA)) == H2_SF_HEADERS_SENT) {
|
||||||
/* we can cleanly close using an empty data frame only after headers
|
/* we can cleanly close using an empty data frame only after headers
|
||||||
* and if no more data is expected to be sent.
|
* and if no more data is expected to be sent.
|
||||||
@ -4995,6 +5015,10 @@ static void h2_do_shutw(struct h2s *h2s)
|
|||||||
h2c_error(h2c, H2_ERR_ENHANCE_YOUR_CALM);
|
h2c_error(h2c, H2_ERR_ENHANCE_YOUR_CALM);
|
||||||
h2s_error(h2s, H2_ERR_ENHANCE_YOUR_CALM);
|
h2s_error(h2s, H2_ERR_ENHANCE_YOUR_CALM);
|
||||||
}
|
}
|
||||||
|
else if (h2s_is_forwardable_abort(h2s, reason)) {
|
||||||
|
TRACE_STATE("shutw using opposite endp code", H2_EV_STRM_SHUT, h2c->conn, h2s);
|
||||||
|
h2s_error(h2s, reason->code);
|
||||||
|
}
|
||||||
else if (h2s->flags & H2_SF_MORE_HTX_DATA) {
|
else if (h2s->flags & H2_SF_MORE_HTX_DATA) {
|
||||||
/* some unsent data were pending (e.g. abort during an upload),
|
/* some unsent data were pending (e.g. abort during an upload),
|
||||||
* let's send a CANCEL.
|
* let's send a CANCEL.
|
||||||
@ -5061,10 +5085,10 @@ struct task *h2_deferred_shut(struct task *t, void *ctx, unsigned int state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (h2s->flags & H2_SF_WANT_SHUTW)
|
if (h2s->flags & H2_SF_WANT_SHUTW)
|
||||||
h2_do_shutw(h2s);
|
h2_do_shutw(h2s, NULL);
|
||||||
|
|
||||||
if (h2s->flags & H2_SF_WANT_SHUTR)
|
if (h2s->flags & H2_SF_WANT_SHUTR)
|
||||||
h2_do_shutr(h2s);
|
h2_do_shutr(h2s, NULL);
|
||||||
|
|
||||||
if (!(h2s->flags & (H2_SF_WANT_SHUTR|H2_SF_WANT_SHUTW))) {
|
if (!(h2s->flags & (H2_SF_WANT_SHUTR|H2_SF_WANT_SHUTW))) {
|
||||||
/* We're done trying to send, remove ourself from the send_list */
|
/* We're done trying to send, remove ourself from the send_list */
|
||||||
@ -5088,10 +5112,12 @@ static void h2_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_i
|
|||||||
struct h2s *h2s = __sc_mux_strm(sc);
|
struct h2s *h2s = __sc_mux_strm(sc);
|
||||||
|
|
||||||
TRACE_ENTER(H2_EV_STRM_SHUT, h2s->h2c->conn, h2s);
|
TRACE_ENTER(H2_EV_STRM_SHUT, h2s->h2c->conn, h2s);
|
||||||
if (mode & (SE_SHW_SILENT|SE_SHW_NORMAL))
|
if (mode & (SE_SHW_SILENT|SE_SHW_NORMAL)) {
|
||||||
h2_do_shutw(h2s);
|
/* Pass the reason for silent shutw only (abort) */
|
||||||
|
h2_do_shutw(h2s, (mode & SE_SHW_SILENT) ? reason : NULL);
|
||||||
|
}
|
||||||
if (mode & SE_SHR_RESET)
|
if (mode & SE_SHR_RESET)
|
||||||
h2_do_shutr(h2s);
|
h2_do_shutr(h2s, reason);
|
||||||
TRACE_LEAVE(H2_EV_STRM_SHUT, h2s->h2c->conn, h2s);
|
TRACE_LEAVE(H2_EV_STRM_SHUT, h2s->h2c->conn, h2s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user