mirror of
https://github.com/curl/curl.git
synced 2026-07-08 10:47:16 +03:00
cw-out: handle error codes for 0len writes
Handle errors returned by the callback the same for 0-length writes as for all the others. Closes #18428
This commit is contained in:
parent
21c288902d
commit
fa9151b41a
1 changed files with 55 additions and 35 deletions
90
lib/cw-out.c
90
lib/cw-out.c
|
|
@ -195,6 +195,50 @@ static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype,
|
|||
}
|
||||
}
|
||||
|
||||
static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx,
|
||||
struct Curl_easy *data,
|
||||
curl_write_callback wcb,
|
||||
void *wcb_data,
|
||||
cw_out_type otype,
|
||||
const char *buf, size_t blen,
|
||||
size_t *pnwritten)
|
||||
{
|
||||
size_t nwritten;
|
||||
CURLcode result;
|
||||
|
||||
*pnwritten = 0;
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
nwritten = wcb((char *)CURL_UNCONST(buf), 1, blen, wcb_data);
|
||||
Curl_set_in_callback(data, FALSE);
|
||||
CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes -> %zu",
|
||||
blen, (otype == CW_OUT_HDS) ? "header" : "body",
|
||||
nwritten);
|
||||
if(CURL_WRITEFUNC_PAUSE == nwritten) {
|
||||
if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
|
||||
/* Protocols that work without network cannot be paused. This is
|
||||
actually only FILE:// just now, and it cannot pause since the
|
||||
transfer is not done using the "normal" procedure. */
|
||||
failf(data, "Write callback asked for PAUSE when not supported");
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
ctx->paused = TRUE;
|
||||
CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
|
||||
result = Curl_xfer_pause_recv(data, TRUE);
|
||||
return result ? result : CURLE_AGAIN;
|
||||
}
|
||||
else if(CURL_WRITEFUNC_ERROR == nwritten) {
|
||||
failf(data, "client returned ERROR on write of %zu bytes", blen);
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
else if(nwritten != blen) {
|
||||
failf(data, "Failure writing output to destination, "
|
||||
"passed %zu returned %zd", blen, nwritten);
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
*pnwritten = nwritten;
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
|
||||
struct Curl_easy *data,
|
||||
cw_out_type otype,
|
||||
|
|
@ -206,6 +250,7 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
|
|||
void *wcb_data;
|
||||
size_t max_write, min_write;
|
||||
size_t wlen, nwritten;
|
||||
CURLcode result;
|
||||
|
||||
/* If we errored once, we do not invoke the client callback again */
|
||||
if(ctx->errored)
|
||||
|
|
@ -221,44 +266,18 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
|
|||
*pconsumed = 0;
|
||||
if(otype == CW_OUT_BODY_0LEN) {
|
||||
DEBUGASSERT(!blen);
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
nwritten = wcb((char *)CURL_UNCONST(buf), 1, blen, wcb_data);
|
||||
Curl_set_in_callback(data, FALSE);
|
||||
CURL_TRC_WRITE(data, "[OUT] wrote %zu BODY bytes -> %zu",
|
||||
blen, nwritten);
|
||||
return cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
|
||||
buf, blen, &nwritten);
|
||||
}
|
||||
else {
|
||||
while(blen && !ctx->paused) {
|
||||
if(!flush_all && blen < min_write)
|
||||
break;
|
||||
wlen = max_write ? CURLMIN(blen, max_write) : blen;
|
||||
Curl_set_in_callback(data, TRUE);
|
||||
nwritten = wcb((char *)CURL_UNCONST(buf), 1, wlen, wcb_data);
|
||||
Curl_set_in_callback(data, FALSE);
|
||||
CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes -> %zu",
|
||||
wlen, (otype == CW_OUT_BODY) ? "body" : "header",
|
||||
nwritten);
|
||||
if(CURL_WRITEFUNC_PAUSE == nwritten) {
|
||||
if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
|
||||
/* Protocols that work without network cannot be paused. This is
|
||||
actually only FILE:// just now, and it cannot pause since the
|
||||
transfer is not done using the "normal" procedure. */
|
||||
failf(data, "Write callback asked for PAUSE when not supported");
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
ctx->paused = TRUE;
|
||||
CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
|
||||
return Curl_xfer_pause_recv(data, TRUE);
|
||||
}
|
||||
else if(CURL_WRITEFUNC_ERROR == nwritten) {
|
||||
failf(data, "client returned ERROR on write of %zu bytes", wlen);
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
else if(nwritten != wlen) {
|
||||
failf(data, "Failure writing output to destination, "
|
||||
"passed %zu returned %zd", wlen, nwritten);
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
result = cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
|
||||
buf, wlen, &nwritten);
|
||||
if(result)
|
||||
return result;
|
||||
*pconsumed += nwritten;
|
||||
blen -= nwritten;
|
||||
buf += nwritten;
|
||||
|
|
@ -274,14 +293,14 @@ static CURLcode cw_out_buf_flush(struct cw_out_ctx *ctx,
|
|||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(curlx_dyn_len(&cwbuf->b)) {
|
||||
if(curlx_dyn_len(&cwbuf->b) || (cwbuf->type == CW_OUT_BODY_0LEN)) {
|
||||
size_t consumed;
|
||||
|
||||
result = cw_out_ptr_flush(ctx, data, cwbuf->type, flush_all,
|
||||
curlx_dyn_ptr(&cwbuf->b),
|
||||
curlx_dyn_len(&cwbuf->b),
|
||||
&consumed);
|
||||
if(result)
|
||||
if(result && (result != CURLE_AGAIN))
|
||||
return result;
|
||||
|
||||
if(consumed) {
|
||||
|
|
@ -394,8 +413,9 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
|
|||
size_t consumed;
|
||||
result = cw_out_ptr_flush(ctx, data, otype, flush_all,
|
||||
buf, blen, &consumed);
|
||||
if(result)
|
||||
if(result && (result != CURLE_AGAIN))
|
||||
return result;
|
||||
result = CURLE_OK;
|
||||
if(consumed < blen) {
|
||||
/* did not write all, append the rest */
|
||||
result = cw_out_append(ctx, data, otype,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue