From: Stefan Eissing Date: Fri, 29 Aug 2025 08:20:12 +0000 (+0200) Subject: cw-out: handle error codes for 0len writes X-Git-Tag: curl-8_16_0~62 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fa9151b41ad986e0514d99dd3fe149f26a7a57a3;p=thirdparty%2Fcurl.git 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 --- diff --git a/lib/cw-out.c b/lib/cw-out.c index c2c2f49c03..3df1c50483 100644 --- a/lib/cw-out.c +++ b/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,