From: Stefan Eissing Date: Mon, 13 Mar 2023 10:44:26 +0000 (+0100) Subject: http2: Use KEEP_SEND_HOLD for flow control in HTTP/2 X-Git-Tag: curl-8_0_0~25 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=06f65f771b52122cf78a6ca3279686679d72bd8e;p=thirdparty%2Fcurl.git http2: Use KEEP_SEND_HOLD for flow control in HTTP/2 - use the defined, but so far not used, KEEP_SEND_HOLD bit for flow control based suspend of sending in transfers. Prior to this change KEEP_SEND_PAUSE bit was used instead, but that can interfere with pausing streams from the user side via curl_easy_pause. Fixes https://github.com/curl/curl/issues/10751 Closes https://github.com/curl/curl/pull/10753 --- diff --git a/lib/http2.c b/lib/http2.c index 94250bf6eb..b0ce87d987 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -958,12 +958,12 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, break; case NGHTTP2_WINDOW_UPDATE: DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv WINDOW_UPDATE", stream_id)); - if((data_s->req.keepon & KEEP_SEND_PAUSE) && + if((data_s->req.keepon & KEEP_SEND_HOLD) && (data_s->req.keepon & KEEP_SEND)) { - data_s->req.keepon &= ~KEEP_SEND_PAUSE; + data_s->req.keepon &= ~KEEP_SEND_HOLD; drain_this(cf, data_s); Curl_expire(data_s, 0, EXPIRE_RUN_NOW); - DEBUGF(LOG_CF(data, cf, "[h2sid=%u] unpausing after win update", + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] un-holding after win update", stream_id)); } break; @@ -2055,8 +2055,8 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* We cannot upload more as the stream's remote window size * is 0. We need to receive WIN_UPDATEs before we can continue. */ - data->req.keepon |= KEEP_SEND_PAUSE; - DEBUGF(LOG_CF(data, cf, "[h2sid=%u] pausing send as remote flow " + data->req.keepon |= KEEP_SEND_HOLD; + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] holding send as remote flow " "window is exhausted", stream->stream_id)); } } @@ -2189,7 +2189,7 @@ static int cf_h2_get_select_socks(struct Curl_cfilter *cf, /* we're (still uploading OR the HTTP/2 layer wants to send data) AND there's a window to send data in */ - if((((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) || + if((((k->keepon & KEEP_SENDBITS) == KEEP_SEND) || nghttp2_session_want_write(ctx->h2)) && (nghttp2_session_get_remote_window_size(ctx->h2) && nghttp2_session_get_stream_remote_window_size(ctx->h2, diff --git a/lib/transfer.c b/lib/transfer.c index 140895113e..a28395233c 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -1234,8 +1234,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, } /* Now update the "done" boolean we return */ - *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND| - KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE; + *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE; result = CURLE_OK; out: if(result) diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 4ff87ae5dc..d2d0a3a5af 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -903,7 +903,7 @@ static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf, rv |= GETSOCK_READSOCK(0); /* we're still uploading or the HTTP/2 layer wants to send data */ - if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND && + if((k->keepon & KEEP_SENDBITS) == KEEP_SEND && (!stream->h3out || stream->h3out->used < H3_SEND_SIZE) && ngtcp2_conn_get_cwnd_left(ctx->qconn) && ngtcp2_conn_get_max_data_left(ctx->qconn) && diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 0c48c1c2eb..87a221cc18 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -950,7 +950,7 @@ static int cf_quiche_get_select_socks(struct Curl_cfilter *cf, rv |= GETSOCK_READSOCK(0); /* we're still uploading or the HTTP/3 layer wants to send data */ - if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) + if(((k->keepon & KEEP_SENDBITS) == KEEP_SEND) && stream_is_writeable(cf, data)) rv |= GETSOCK_WRITESOCK(0);