cfilters: send flush

Since data can be held in connection filter buffers when sending gives
EAGAIN, add methods to query this and perform flushing of those buffers.

The transfer loop will continue sending until all upload data is
processed and the connection is flushed.

- add `CF_QUERY_SEND_PENDING` to query filters
- add `CF_CTRL_DATA_SEND_FLUSH` to flush filters
- change `Curl_req_want_send()` to query the connection
  if it needs flushing
- use `Curl_req_want_send()` to determine the POLLOUT
  in the PERFORMING multi state
- implement flush handling in the HTTP/2 connection filter

Closes #14271
This commit is contained in:
Stefan Eissing 2024-07-25 13:10:01 +02:00 committed by Daniel Stenberg
parent 911c3166b6
commit 709a6a3965
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
10 changed files with 278 additions and 100 deletions

View file

@ -313,10 +313,9 @@ static CURLcode readwrite_data(struct Curl_easy *data,
DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
else
DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
/* stop receiving and ALL sending as well, including PAUSE and HOLD.
* We might still be paused on receive client writes though, so
* keep those bits around. */
k->keepon &= ~(KEEP_RECV|KEEP_SENDBITS);
result = Curl_req_stop_send_recv(data);
if(result)
goto out;
if(k->eos_written) /* already did write this to client, leave */
break;
}
@ -352,8 +351,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
may now close the connection. If there is now any kind of sending going
on from our side, we need to stop that immediately. */
infof(data, "we are done reading and this is set to close, stop send");
k->keepon &= ~KEEP_SEND; /* no writing anymore either */
k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */
Curl_req_abort_sending(data);
}
out:
@ -368,9 +366,6 @@ out:
*/
static CURLcode readwrite_upload(struct Curl_easy *data, int *didwhat)
{
if((data->req.keepon & KEEP_SEND_PAUSE))
return CURLE_OK;
/* We should not get here when the sending is already done. It
* probably means that someone set `data-req.keepon |= KEEP_SEND`
* when it should not. */
@ -435,7 +430,7 @@ CURLcode Curl_readwrite(struct Curl_easy *data)
else
fd_read = CURL_SOCKET_BAD;
if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
if(Curl_req_want_send(data))
fd_write = conn->writesockfd;
else
fd_write = CURL_SOCKET_BAD;
@ -467,7 +462,7 @@ CURLcode Curl_readwrite(struct Curl_easy *data)
}
/* If we still have writing to do, we check if we have a writable socket. */
if(((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) ||
if((Curl_req_want_send(data) && (select_bits & CURL_CSELECT_OUT)) ||
(k->keepon & KEEP_SEND_TIMED)) {
/* write */
@ -1233,6 +1228,22 @@ CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
return Curl_cw_out_done(data);
}
bool Curl_xfer_needs_flush(struct Curl_easy *data)
{
int sockindex;
sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
(data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
return Curl_conn_needs_flush(data, sockindex);
}
CURLcode Curl_xfer_flush(struct Curl_easy *data)
{
int sockindex;
sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
(data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
return Curl_conn_flush(data, sockindex);
}
CURLcode Curl_xfer_send(struct Curl_easy *data,
const void *buf, size_t blen, bool eos,
size_t *pnwritten)
@ -1259,6 +1270,8 @@ CURLcode Curl_xfer_send(struct Curl_easy *data,
else if(!result && *pnwritten)
data->info.request_size += *pnwritten;
DEBUGF(infof(data, "Curl_xfer_send(len=%zu) -> %d, %zu",
blen, result, *pnwritten));
return result;
}