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
This commit is contained in:
Stefan Eissing 2023-03-13 11:44:26 +01:00 committed by Jay Satiro
parent 7caaeca6f6
commit 06f65f771b
4 changed files with 9 additions and 10 deletions

View File

@ -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,

View File

@ -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)

View File

@ -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) &&

View File

@ -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);