ngtcp2: fix HTTP/3 upload stall and avoid busy loop
This commit fixes HTTP/3 upload stall if upload data is larger than H3_SEND_SIZE. Only check writability of socket if a stream is writable to avoid busy loop when QUIC flow control window is filled up, or upload buffer is full. Closes #8688
This commit is contained in:
Родитель
37492ebbfa
Коммит
990bfdd7bc
|
@ -867,6 +867,8 @@ static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
|
||||||
{
|
{
|
||||||
struct SingleRequest *k = &data->req;
|
struct SingleRequest *k = &data->req;
|
||||||
int bitmap = GETSOCK_BLANK;
|
int bitmap = GETSOCK_BLANK;
|
||||||
|
struct HTTP *stream = data->req.p.http;
|
||||||
|
struct quicsocket *qs = conn->quic;
|
||||||
|
|
||||||
socks[0] = conn->sock[FIRSTSOCKET];
|
socks[0] = conn->sock[FIRSTSOCKET];
|
||||||
|
|
||||||
|
@ -875,7 +877,10 @@ static int ng_getsock(struct Curl_easy *data, struct connectdata *conn,
|
||||||
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
|
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
|
||||||
|
|
||||||
/* we're still uploading or the HTTP/2 layer wants to send data */
|
/* 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_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND &&
|
||||||
|
(!stream->h3out || stream->h3out->used < H3_SEND_SIZE) &&
|
||||||
|
ngtcp2_conn_get_max_data_left(qs->qconn) &&
|
||||||
|
nghttp3_conn_is_stream_writable(qs->h3conn, stream->stream3_id))
|
||||||
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
|
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
|
||||||
|
|
||||||
return bitmap;
|
return bitmap;
|
||||||
|
@ -1375,6 +1380,10 @@ static ssize_t cb_h3_readfunction(nghttp3_conn *conn, int64_t stream_id,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(stream->upload_len && H3_SEND_SIZE <= stream->h3out->used) {
|
||||||
|
return NGHTTP3_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
nread = CURLMIN(stream->upload_len, H3_SEND_SIZE - stream->h3out->used);
|
nread = CURLMIN(stream->upload_len, H3_SEND_SIZE - stream->h3out->used);
|
||||||
if(nread > 0) {
|
if(nread > 0) {
|
||||||
/* nghttp3 wants us to hold on to the data until it tells us it is okay to
|
/* nghttp3 wants us to hold on to the data until it tells us it is okay to
|
||||||
|
@ -1527,7 +1536,7 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
|
||||||
size_t len,
|
size_t len,
|
||||||
CURLcode *curlcode)
|
CURLcode *curlcode)
|
||||||
{
|
{
|
||||||
ssize_t sent;
|
ssize_t sent = 0;
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
struct quicsocket *qs = conn->quic;
|
struct quicsocket *qs = conn->quic;
|
||||||
curl_socket_t sockfd = conn->sock[sockindex];
|
curl_socket_t sockfd = conn->sock[sockindex];
|
||||||
|
@ -1539,6 +1548,9 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
|
||||||
*curlcode = CURLE_SEND_ERROR;
|
*curlcode = CURLE_SEND_ERROR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
/* Assume that mem of length len only includes HTTP/1.1 style
|
||||||
|
header fields. In other words, it does not contain request
|
||||||
|
body. */
|
||||||
sent = len;
|
sent = len;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1548,7 +1560,6 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
|
||||||
stream->upload_mem = mem;
|
stream->upload_mem = mem;
|
||||||
stream->upload_len = len;
|
stream->upload_len = len;
|
||||||
(void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
|
(void)nghttp3_conn_resume_stream(qs->h3conn, stream->stream3_id);
|
||||||
sent = len;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*curlcode = CURLE_AGAIN;
|
*curlcode = CURLE_AGAIN;
|
||||||
|
@ -1563,8 +1574,20 @@ static ssize_t ngh3_stream_send(struct Curl_easy *data,
|
||||||
|
|
||||||
/* Reset post upload buffer after resumed. */
|
/* Reset post upload buffer after resumed. */
|
||||||
if(stream->upload_mem) {
|
if(stream->upload_mem) {
|
||||||
|
if(data->set.postfields) {
|
||||||
|
sent = len;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sent = len - stream->upload_len;
|
||||||
|
}
|
||||||
|
|
||||||
stream->upload_mem = NULL;
|
stream->upload_mem = NULL;
|
||||||
stream->upload_len = 0;
|
stream->upload_len = 0;
|
||||||
|
|
||||||
|
if(sent == 0) {
|
||||||
|
*curlcode = CURLE_AGAIN;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*curlcode = CURLE_OK;
|
*curlcode = CURLE_OK;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче