lib: move 'done' parameter to SingleRequests

A transfer may do several `SingleRequest`s for its success. This happens
regularly for authentication, follows and retries on failed connections.
The "readwrite()" calls and functions connected to those carried a `bool
*done` parameter to indicate that the current `SingleRequest` is over.
This may happen before `upload_done` or `download_done` bits of
`SingleRequest` are set.

The problem with that is now `write_resp()` protocol handlers are
invoked in places where the `bool *done` cannot be passed up to the
caller. Instead of being a bool in the call chain, it needs to become a
member of `SingleRequest`, reflecting its state.

This removes the `bool *done` parameter and adds the `done` bit to
`SingleRequest` instead. It adds `Curl_req_soft_reset()` for using a
`SingleRequest` in a follow up, clearing `done` and other
flags/counters.

Closes #13096
This commit is contained in:
Stefan Eissing 2024-03-11 12:35:07 +01:00 committed by Daniel Stenberg
parent 6aeb729b5c
commit 4e4e8af1f6
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
16 changed files with 96 additions and 100 deletions

View File

@ -207,7 +207,6 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
CURLcode result = CURLE_OK;
if(0 == k->bodywrites) {
bool done = FALSE;
#if defined(USE_NTLM)
struct connectdata *conn = data->conn;
if(conn->bits.close &&
@ -235,12 +234,12 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
}
if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
data->state.authproxy.done) {
done = TRUE;
data->req.done = TRUE;
result = CURLE_OK;
}
else
result = Curl_http_firstwrite(data, data->conn, &done);
if(result || done) {
result = Curl_http_firstwrite(data);
if(result || data->req.done) {
infof(data, "Return early from hyper_body_chunk");
data->state.hresult = result;
return HYPER_ITER_BREAK;
@ -338,7 +337,6 @@ static CURLcode empty_header(struct Curl_easy *data)
CURLcode Curl_hyper_stream(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
bool *done,
int select_res)
{
hyper_response *resp = NULL;
@ -382,7 +380,6 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
h->write_waker = NULL;
}
*done = FALSE;
do {
hyper_task_return_type t;
task = hyper_executor_poll(h->exec);
@ -425,7 +422,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
break;
}
}
*done = TRUE;
data->req.done = TRUE;
hyper_error_free(hypererr);
break;
}
@ -434,12 +431,11 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
hyper_task_free(task);
if((userdata_t)userdata == USERDATA_RESP_BODY) {
/* end of transfer */
*done = TRUE;
data->req.done = TRUE;
infof(data, "hyperstream is done");
if(!k->bodywrites) {
/* hyper doesn't always call the body write callback */
bool stilldone;
result = Curl_http_firstwrite(data, data->conn, &stilldone);
result = Curl_http_firstwrite(data);
}
break;
}

View File

@ -51,7 +51,6 @@ size_t Curl_hyper_send(void *userp, hyper_context *ctx,
CURLcode Curl_hyper_stream(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
bool *done,
int select_res);
CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,

View File

@ -832,9 +832,9 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
int didwhat;
(void)ts;
*done = FALSE;
result = Curl_hyper_stream(data, cf->conn, &didwhat, done,
result = Curl_hyper_stream(data, cf->conn, &didwhat,
CURL_CSELECT_IN | CURL_CSELECT_OUT);
*done = data->req.done;
if(result || !*done)
return result;
if(h->exec) {
@ -918,6 +918,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
* If the other side indicated a connection close, or if someone
* else told us to close this connection, do so now.
*/
Curl_req_soft_reset(&data->req, data);
if(ts->close_connection || conn->bits.close) {
/* Close this filter and the sub-chain, re-connect the
* sub-chain and continue. Closing this filter will
@ -1003,10 +1004,8 @@ out:
*done = (result == CURLE_OK) && tunnel_is_established(cf->ctx);
if(*done) {
cf->connected = TRUE;
/* Restore `data->req` fields that may habe been touched */
data->req.header = TRUE; /* assume header */
data->req.bytecount = 0;
data->req.ignorebody = FALSE;
/* The real request will follow the CONNECT, reset request partially */
Curl_req_soft_reset(&data->req, data);
Curl_client_reset(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);

View File

@ -1040,7 +1040,7 @@ fail:
*/
void curl_easy_reset(struct Curl_easy *data)
{
Curl_req_reset(&data->req, data);
Curl_req_hard_reset(&data->req, data);
/* zero out UserDefined data: */
Curl_freeset(data);

View File

@ -2446,19 +2446,17 @@ CURLcode Curl_http_range(struct Curl_easy *data,
return CURLE_OK;
}
CURLcode Curl_http_firstwrite(struct Curl_easy *data,
struct connectdata *conn,
bool *done)
CURLcode Curl_http_firstwrite(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
*done = FALSE;
if(data->req.newurl) {
if(conn->bits.close) {
/* Abort after the headers if "follow Location" is set
and we're set to close anyway. */
k->keepon &= ~KEEP_RECV;
*done = TRUE;
k->done = TRUE;
return CURLE_OK;
}
/* We have a new url to load, but since we want to be able to reuse this
@ -2477,7 +2475,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
streamclose(conn, "already downloaded");
/* Abort download */
k->keepon &= ~KEEP_RECV;
*done = TRUE;
k->done = TRUE;
return CURLE_OK;
}
@ -2495,7 +2493,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
action for an HTTP/1.1 client */
if(!Curl_meets_timecondition(data, k->timeofdoc)) {
*done = TRUE;
k->done = TRUE;
/* We're simulating an HTTP 304 from server so we return
what should have been returned from the server */
data->info.httpcode = 304;
@ -3951,10 +3949,8 @@ out:
*/
CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen,
size_t *pconsumed,
bool *done)
size_t *pconsumed)
{
*done = FALSE;
if(!data->req.header) {
*pconsumed = 0;
return CURLE_OK;
@ -3965,7 +3961,7 @@ CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
result = http_rw_headers(data, buf, blen, pconsumed);
if(!result && !data->req.header) {
/* we have successfully finished parsing the HEADERs */
result = Curl_http_firstwrite(data, data->conn, done);
result = Curl_http_firstwrite(data);
if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
/* leftover from parsing something that turned out not
@ -3983,16 +3979,14 @@ CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos,
bool *done)
bool is_eos)
{
CURLcode result;
size_t consumed;
int flags;
*done = FALSE;
result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done);
if(result || *done)
result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
if(result || data->req.done)
goto out;
DEBUGASSERT(consumed <= blen);

View File

@ -121,9 +121,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
#endif
CURLcode Curl_http_range(struct Curl_easy *data,
Curl_HttpReq httpreq);
CURLcode Curl_http_firstwrite(struct Curl_easy *data,
struct connectdata *conn,
bool *done);
CURLcode Curl_http_firstwrite(struct Curl_easy *data);
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http_setup_conn(struct Curl_easy *data,
@ -135,8 +133,7 @@ int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks);
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos,
bool *done);
bool is_eos);
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
@ -197,8 +194,7 @@ CURLcode Curl_http_size(struct Curl_easy *data);
CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen,
size_t *pconsumed,
bool *done);
size_t *pconsumed);
/**
* Curl_http_output_auth() setups the authentication headers for the

View File

@ -951,10 +951,8 @@ static CURLcode recvbuf_write_hds(struct Curl_cfilter *cf,
struct Curl_easy *data,
const char *buf, size_t blen)
{
bool done;
(void)cf;
return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE, &done);
return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
}
static CURLcode on_stream_frame(struct Curl_cfilter *cf,
@ -1234,7 +1232,6 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
struct h2_stream_ctx *stream;
struct Curl_easy *data_s;
CURLcode result;
bool done;
(void)flags;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
@ -1257,7 +1254,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
result = Curl_xfer_write_resp(data_s, (char *)mem, len, FALSE, &done);
result = Curl_xfer_write_resp(data_s, (char *)mem, len, FALSE);
if(result && result != CURLE_AGAIN)
return NGHTTP2_ERR_CALLBACK_FAILURE;

View File

@ -1843,7 +1843,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool async;
bool protocol_connected = FALSE;
bool dophase_done = FALSE;
bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
timediff_t recv_timeout_ms;
@ -2405,9 +2404,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* read/write data if it is ready to do so */
result = Curl_readwrite(data, &done);
result = Curl_readwrite(data);
if(done || (result == CURLE_RECV_ERROR)) {
if(data->req.done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
* condition and the server closed the reused connection exactly when
* we wanted to use it, so figure out if that is indeed the case.
@ -2422,7 +2421,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* if we are to retry, set the result to OK and consider the
request as done */
result = CURLE_OK;
done = TRUE;
data->req.done = TRUE;
}
}
else if((CURLE_HTTP2_STREAM == result) &&
@ -2442,7 +2441,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
as done */
retry = TRUE;
result = CURLE_OK;
done = TRUE;
data->req.done = TRUE;
}
else
result = ret;
@ -2464,7 +2463,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_posttransfer(data);
multi_done(data, result, TRUE);
}
else if(done) {
else if(data->req.done) {
/* call this even if the readwrite function returned error */
Curl_posttransfer(data);

View File

@ -46,12 +46,23 @@ CURLcode Curl_req_init(struct SingleRequest *req)
return CURLE_OK;
}
CURLcode Curl_req_start(struct SingleRequest *req,
struct Curl_easy *data)
CURLcode Curl_req_soft_reset(struct SingleRequest *req,
struct Curl_easy *data)
{
CURLcode result;
req->start = Curl_now();
req->done = FALSE;
req->upload_done = FALSE;
req->download_done = FALSE;
req->ignorebody = FALSE;
req->bytecount = 0;
req->writebytecount = 0;
req->header = TRUE; /* assume header */
req->headerline = 0;
req->headerbytecount = 0;
req->allheadercount = 0;
req->deductheadercount = 0;
result = Curl_client_start(data);
if(result)
return result;
@ -73,6 +84,13 @@ CURLcode Curl_req_start(struct SingleRequest *req,
return CURLE_OK;
}
CURLcode Curl_req_start(struct SingleRequest *req,
struct Curl_easy *data)
{
req->start = Curl_now();
return Curl_req_soft_reset(req, data);
}
static CURLcode req_flush(struct Curl_easy *data);
CURLcode Curl_req_done(struct SingleRequest *req,
@ -85,7 +103,7 @@ CURLcode Curl_req_done(struct SingleRequest *req,
return CURLE_OK;
}
void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data)
void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
{
struct curltime t0 = {0, 0};

View File

@ -123,6 +123,9 @@ struct SingleRequest {
unsigned char setcookies;
#endif
BIT(header); /* incoming data has HTTP header */
BIT(done); /* request is done, e.g. no more send/recv should
* happen. This can be TRUE before `upload_done` or
* `download_done` is TRUE. */
BIT(content_range); /* set TRUE if Content-Range: was found */
BIT(download_done); /* set to TRUE when download is complete */
BIT(eos_written); /* iff EOS has been written to client */
@ -153,11 +156,18 @@ struct SingleRequest {
CURLcode Curl_req_init(struct SingleRequest *req);
/**
* The request is about to start.
* The request is about to start. Record time and do a soft reset.
*/
CURLcode Curl_req_start(struct SingleRequest *req,
struct Curl_easy *data);
/**
* The request may continue with a follow up. Reset
* members, but keep start time for overall duration calc.
*/
CURLcode Curl_req_soft_reset(struct SingleRequest *req,
struct Curl_easy *data);
/**
* The request is done. If not aborted, make sure that buffers are
* flushed to the client.
@ -174,10 +184,10 @@ CURLcode Curl_req_done(struct SingleRequest *req,
void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data);
/**
* Reset the state of the request for new use, given the
* settings.
* Hard reset the state of the request to virgin state base on
* transfer settings.
*/
void Curl_req_reset(struct SingleRequest *req, struct Curl_easy *data);
void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data);
#ifndef USE_HYPER
/**

View File

@ -70,8 +70,7 @@ static int rtsp_getsock_do(struct Curl_easy *data,
static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
const char *buf,
size_t blen,
bool is_eos,
bool *done);
bool is_eos);
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
@ -790,8 +789,7 @@ out:
static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
const char *buf,
size_t blen,
bool is_eos,
bool *done)
bool is_eos)
{
struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
CURLcode result = CURLE_OK;
@ -799,7 +797,6 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
if(!data->req.header)
rtspc->in_header = FALSE;
*done = FALSE;
if(!blen) {
goto out;
}
@ -823,7 +820,7 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
/* we want to parse headers, do so */
if(data->req.header && blen) {
rtspc->in_header = TRUE;
result = Curl_http_write_resp_hds(data, buf, blen, &consumed, done);
result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
if(result)
goto out;
@ -849,13 +846,14 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
}
if(rtspc->state != RTP_PARSE_SKIP)
*done = FALSE;
data->req.done = FALSE;
/* we SHOULD have consumed all bytes, unless the response is borked.
* In which case we write out the left over bytes, letting the client
* writer deal with it (it will report EXCESS and fail the transfer). */
DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d "
" rtspc->state=%d, req.size=%" CURL_FORMAT_CURL_OFF_T ")",
blen, rtspc->in_header, *done, rtspc->state, data->req.size));
blen, rtspc->in_header, data->req.done, rtspc->state,
data->req.size));
if(!result && (is_eos || blen)) {
result = Curl_client_write(data, CLIENTWRITE_BODY|
(is_eos? CLIENTWRITE_EOS:0),

View File

@ -209,7 +209,7 @@ static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
*/
static CURLcode readwrite_data(struct Curl_easy *data,
struct SingleRequest *k,
int *didwhat, bool *done)
int *didwhat)
{
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
@ -219,8 +219,6 @@ static CURLcode readwrite_data(struct Curl_easy *data,
curl_off_t total_received = 0;
bool is_multiplex = FALSE;
*done = FALSE;
result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
if(result)
goto out;
@ -281,8 +279,8 @@ static CURLcode readwrite_data(struct Curl_easy *data,
}
total_received += blen;
result = Curl_xfer_write_resp(data, buf, blen, is_eos, done);
if(result || *done)
result = Curl_xfer_write_resp(data, buf, blen, is_eos);
if(result || data->req.done)
goto out;
/* if we are done, we stop receiving. On multiplexed connections,
@ -403,8 +401,7 @@ static int select_bits_paused(struct Curl_easy *data, int select_bits)
* Curl_readwrite() is the low-level function to be called when data is to
* be read and written to/from the connection.
*/
CURLcode Curl_readwrite(struct Curl_easy *data,
bool *done)
CURLcode Curl_readwrite(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
@ -450,8 +447,8 @@ CURLcode Curl_readwrite(struct Curl_easy *data,
#ifdef USE_HYPER
if(conn->datastream) {
result = conn->datastream(data, conn, &didwhat, done, select_bits);
if(result || *done)
result = conn->datastream(data, conn, &didwhat, select_bits);
if(result || data->req.done)
goto out;
}
else {
@ -460,8 +457,8 @@ CURLcode Curl_readwrite(struct Curl_easy *data,
the stream was rewound (in which case we have data in a
buffer) */
if((k->keepon & KEEP_RECV) && (select_bits & CURL_CSELECT_IN)) {
result = readwrite_data(data, k, &didwhat, done);
if(result || *done)
result = readwrite_data(data, k, &didwhat);
if(result || data->req.done)
goto out;
}
@ -561,8 +558,10 @@ CURLcode Curl_readwrite(struct Curl_easy *data,
}
}
/* Now update the "done" boolean we return */
*done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE;
/* If there is nothing more to send/recv, the request is done */
if(0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS)))
data->req.done = TRUE;
out:
if(result)
DEBUGF(infof(data, "Curl_readwrite() -> %d", result));
@ -937,7 +936,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
data->state.url = newurl;
data->state.url_alloc = TRUE;
Curl_req_soft_reset(&data->req, data);
infof(data, "Issue another request to this URL: '%s'", data->state.url);
/*
@ -1209,14 +1208,14 @@ void Curl_xfer_setup(
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
char *buf, size_t blen,
bool is_eos, bool *done)
bool is_eos)
{
CURLcode result = CURLE_OK;
if(data->conn->handler->write_resp) {
/* protocol handlers offering this function take full responsibility
* for writing all received download data to the client. */
result = data->conn->handler->write_resp(data, buf, blen, is_eos, done);
result = data->conn->handler->write_resp(data, buf, blen, is_eos);
}
else {
/* No special handling by protocol handler, write all received data

View File

@ -45,7 +45,7 @@ typedef enum {
CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
followtype type);
CURLcode Curl_readwrite(struct Curl_easy *data, bool *done);
CURLcode Curl_readwrite(struct Curl_easy *data);
int Curl_single_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
@ -66,7 +66,7 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
*/
CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
char *buf, size_t blen,
bool is_eos, bool *done);
bool is_eos);
/* This sets up a forthcoming transfer */
void Curl_xfer_setup(struct Curl_easy *data,

View File

@ -3839,8 +3839,8 @@ CURLcode Curl_connect(struct Curl_easy *data,
*asyncp = FALSE; /* assume synchronous resolves by default */
/* init the single-transfer specific data */
Curl_req_reset(&data->req, data);
/* Set the request to virgin state based on transfer settings */
Curl_req_hard_reset(&data->req, data);
/* call the stuff that needs to be called */
result = create_conn(data, &conn, asyncp);
@ -3883,8 +3883,6 @@ CURLcode Curl_connect(struct Curl_easy *data,
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
struct SingleRequest *k = &data->req;
/* if this is a pushed stream, we need this: */
CURLcode result = Curl_preconnect(data);
if(result)
@ -3910,10 +3908,6 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
if(result)
return result;
k->header = TRUE; /* assume header */
k->bytecount = 0;
k->ignorebody = FALSE;
Curl_speedinit(data);
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);

View File

@ -163,7 +163,6 @@ typedef ssize_t (Curl_recv)(struct Curl_easy *data, /* transfer */
typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
bool *done,
int select_res);
#endif
@ -703,7 +702,7 @@ struct Curl_handler {
allow the protocol to do extra handling in writing response to
the client. */
CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen,
bool is_eos, bool *done);
bool is_eos);
/* This function can perform various checks on the connection. See
CONNCHECK_* for more information about the checks that can be performed,

View File

@ -762,8 +762,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
static CURLcode write_resp_hds(struct Curl_easy *data,
const char *buf, size_t blen)
{
bool done;
return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE, &done);
return Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
}
static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
@ -775,7 +774,6 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
struct Curl_easy *data = stream_user_data;
struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result;
bool done;
(void)conn;
(void)stream3_id;
@ -783,7 +781,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
if(!stream)
return NGHTTP3_ERR_CALLBACK_FAILURE;
result = Curl_xfer_write_resp(data, (char *)buf, blen, FALSE, &done);
result = Curl_xfer_write_resp(data, (char *)buf, blen, FALSE);
if(result) {
CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
stream->id, blen, result);