summaryrefslogtreecommitdiff
path: root/lib/cw-out.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cw-out.c')
-rw-r--r--lib/cw-out.c109
1 files changed, 72 insertions, 37 deletions
diff --git a/lib/cw-out.c b/lib/cw-out.c
index ee7dc65df..6d988a00b 100644
--- a/lib/cw-out.c
+++ b/lib/cw-out.c
@@ -74,6 +74,7 @@
typedef enum {
CW_OUT_NONE,
CW_OUT_BODY,
+ CW_OUT_BODY_0LEN,
CW_OUT_HDS
} cw_out_type;
@@ -170,6 +171,7 @@ static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype,
{
switch(otype) {
case CW_OUT_BODY:
+ case CW_OUT_BODY_0LEN:
*pwcb = data->set.fwrite_func;
*pwcb_data = data->set.out;
*pmax_write = CURL_MAX_WRITE_SIZE;
@@ -193,6 +195,51 @@ 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;
+
+ DEBUGASSERT(data->conn);
+ *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->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,
@@ -204,6 +251,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)
@@ -217,40 +265,24 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
}
*pconsumed = 0;
- 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;
+ if(otype == CW_OUT_BODY_0LEN) {
+ DEBUGASSERT(!blen);
+ 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;
+ result = cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
+ buf, wlen, &nwritten);
+ if(result)
+ return result;
+ *pconsumed += nwritten;
+ blen -= nwritten;
+ buf += nwritten;
}
- *pconsumed += nwritten;
- blen -= nwritten;
- buf += nwritten;
}
return CURLE_OK;
}
@@ -262,14 +294,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) {
@@ -382,8 +414,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,
@@ -413,7 +446,9 @@ static CURLcode cw_out_write(struct Curl_easy *data,
if((type & CLIENTWRITE_BODY) ||
((type & CLIENTWRITE_HEADER) && data->set.include_header)) {
- result = cw_out_do_write(ctx, data, CW_OUT_BODY, flush_all, buf, blen);
+ cw_out_type otype = (!blen && (type & CLIENTWRITE_0LEN)) ?
+ CW_OUT_BODY_0LEN : CW_OUT_BODY;
+ result = cw_out_do_write(ctx, data, otype, flush_all, buf, blen);
if(result)
return result;
}