struct cw_out_ctx {
struct Curl_cwriter super;
struct cw_out_buf *buf;
- BIT(paused);
BIT(errored);
};
}
}
-static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx,
- struct Curl_easy *data,
+static CURLcode cw_out_cb_write(struct Curl_easy *data,
curl_write_callback wcb,
void *wcb_data,
cw_out_type otype,
failf(data, "Write callback asked for PAUSE when not supported");
return CURLE_WRITE_ERROR;
}
- ctx->paused = TRUE;
+ data->req.writer.paused = TRUE;
CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client");
result = Curl_xfer_pause_recv(data, TRUE);
return result ? result : CURLE_AGAIN;
*pconsumed = 0;
if(otype == CW_OUT_BODY_0LEN) {
DEBUGASSERT(!blen);
- return cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
+ return cw_out_cb_write(data, wcb, wcb_data, otype,
buf, blen, &nwritten);
}
else {
- while(blen && !ctx->paused) {
+ while(blen && !data->req.writer.paused) {
if(!flush_all && blen < min_write)
break;
wlen = max_write ? CURLMIN(blen, max_write) : blen;
if(otype == CW_OUT_BODY)
result = Curl_pgrs_deliver_check(data, wlen);
if(!result)
- result = cw_out_cb_write(ctx, data, wcb, wcb_data, otype,
+ result = cw_out_cb_write(data, wcb, wcb_data, otype,
buf, wlen, &nwritten);
if(result)
return result;
if(!cwbuf)
return CURLE_OK;
- if(ctx->paused)
+ if(data->req.writer.paused)
return CURLE_OK;
/* write the end of the chain until it blocks or gets empty */
return result;
if(*plast) {
/* could not write last, paused again? */
- DEBUGASSERT(ctx->paused);
+ DEBUGASSERT(data->req.writer.paused);
return CURLE_OK;
}
}
if(ctx->errored)
return CURLE_WRITE_ERROR;
- if(ctx->paused)
+ if(data->req.writer.paused)
return CURLE_OK; /* not doing it */
result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
sizeof(struct cw_out_ctx)
};
-bool Curl_cw_out_is_paused(struct Curl_easy *data)
-{
- struct Curl_cwriter *cw_out;
- struct cw_out_ctx *ctx;
-
- cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
- if(!cw_out)
- return FALSE;
-
- ctx = (struct cw_out_ctx *)cw_out;
- return (bool)ctx->paused;
-}
-
-CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
-{
- struct Curl_cwriter *cw_out;
- CURLcode result = CURLE_OK;
-
- cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
- if(cw_out) {
- struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
- CURL_TRC_WRITE(data, "[OUT] unpause");
- ctx->paused = FALSE;
- }
- return result;
-}
-
CURLcode Curl_cw_out_done(struct Curl_easy *data)
{
struct Curl_cwriter *cw_out;
static void cl_reset_writer(struct Curl_easy *data)
{
- struct Curl_cwriter *writer = data->req.writer_stack;
+ struct Curl_cwriter *writer = data->req.writer.stack;
while(writer) {
- data->req.writer_stack = writer->next;
+ data->req.writer.stack = writer->next;
writer->cwt->do_close(data, writer);
curlx_free(writer);
- writer = data->req.writer_stack;
+ writer = data->req.writer.stack;
}
}
static void cl_reset_reader(struct Curl_easy *data)
{
- struct Curl_creader *reader = data->req.reader_stack;
+ struct Curl_creader *reader = data->req.reader.stack;
data->req.reader_started = FALSE;
while(reader) {
- data->req.reader_stack = reader->next;
+ data->req.reader.stack = reader->next;
reader->crt->do_close(data, reader);
curlx_free(reader);
- reader = data->req.reader_stack;
+ reader = data->req.reader.stack;
}
}
CURLcode Curl_client_start(struct Curl_easy *data)
{
if(data->req.rewind_read) {
- struct Curl_creader *r = data->req.reader_stack;
+ struct Curl_creader *r = data->req.reader.stack;
CURLcode result = CURLE_OK;
CURL_TRC_READ(data, "client start, rewind readers");
data->req.rewind_read = !!enable;
}
-/* Write data using an unencoding writer stack. */
-CURLcode Curl_cwriter_write(struct Curl_easy *data,
- struct Curl_cwriter *writer, int type,
- const char *buf, size_t nbytes)
-{
- if(!writer)
- return CURLE_WRITE_ERROR;
- return writer->cwt->do_write(data, writer, type, buf, nbytes);
-}
-
-CURLcode Curl_cwriter_flush(struct Curl_easy *data,
- struct Curl_cwriter *writer)
-{
- if(!writer) {
- return CURLE_WRITE_ERROR;
- }
- return writer->cwt->do_flush(data, writer);
-}
-
CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
sizeof(struct Curl_cwriter)
};
+static void cwriter_add(struct Curl_easy *data,
+ struct Curl_cwriter *writer)
+{
+ struct Curl_cwriter **anchor = &data->req.writer.stack;
+
+ /* Insert the writer as first in its phase.
+ * Skip existing writers of lower phases. */
+ while(*anchor && (*anchor)->phase < writer->phase)
+ anchor = &((*anchor)->next);
+ writer->next = *anchor;
+ *anchor = writer;
+}
+
static CURLcode do_init_writer_stack(struct Curl_easy *data)
{
struct Curl_cwriter *writer;
CURLcode result;
- DEBUGASSERT(!data->req.writer_stack);
- result = Curl_cwriter_create(&data->req.writer_stack,
+ DEBUGASSERT(!data->req.writer.stack);
+ result = Curl_cwriter_create(&data->req.writer.stack,
data, &Curl_cwt_out, CURL_CW_CLIENT);
if(result)
return result;
- /* This places the "pause" writer behind the "download" writer that
- * is added below. Meaning the "download" can do checks on content length
- * and other things *before* write outs are buffered for paused transfers. */
- result = Curl_cwriter_create(&writer, data, &Curl_cwt_pause,
- CURL_CW_PROTOCOL);
- if(!result) {
- result = Curl_cwriter_add(data, writer);
- if(result)
- Curl_cwriter_free(data, writer);
- }
- if(result)
- return result;
-
result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
- if(!result) {
- result = Curl_cwriter_add(data, writer);
- if(result)
- Curl_cwriter_free(data, writer);
- }
if(result)
return result;
+ cwriter_add(data, writer);
result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
- if(!result) {
- result = Curl_cwriter_add(data, writer);
- if(result)
- Curl_cwriter_free(data, writer);
- }
if(result)
return result;
+ cwriter_add(data, writer);
return result;
}
DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
((type & ~(CLIENTWRITE_INFO | CLIENTWRITE_EOS)) == 0));
- if(!data->req.writer_stack) {
+ if(!data->req.writer.stack) {
result = do_init_writer_stack(data);
if(result)
return result;
- DEBUGASSERT(data->req.writer_stack);
+ DEBUGASSERT(data->req.writer.stack);
}
- result = Curl_cwriter_write(data, data->req.writer_stack, type, buf, len);
+ result = Curl_cwriter_write(data, data->req.writer.stack, type, buf, len);
CURL_TRC_WRITE(data, "client_write(type=%x, len=%zu) -> %d",
(unsigned int)type, len, (int)result);
return result;
{
CURLcode result;
- if(!data->req.writer_stack) {
+ if(!data->req.writer.stack) {
result = do_init_writer_stack(data);
if(result)
return result;
- DEBUGASSERT(data->req.writer_stack);
+ DEBUGASSERT(data->req.writer.stack);
}
- result = Curl_cwriter_flush(data, data->req.writer_stack);
+ result = Curl_cwriter_flush(data, data->req.writer.stack);
CURL_TRC_WRITE(data, "client_flush() -> %d", (int)result);
return result;
}
struct Curl_cwriter *w;
size_t n = 0;
- for(w = data->req.writer_stack; w; w = w->next) {
+ for(w = data->req.writer.stack; w; w = w->next) {
if(w->phase == phase)
++n;
}
return n;
}
+static CURLcode cwriter_ensure_pause_writer(struct Curl_easy *data)
+{
+ struct Curl_cwriter *writer =
+ Curl_cwriter_get_by_type(data, &Curl_cwt_pause);
+ CURLcode result = CURLE_OK;
+
+ if(!writer) {
+ result = Curl_cwriter_create(&writer, data, &Curl_cwt_pause,
+ CURL_CW_BEFORE_DECODE);
+ if(!result)
+ cwriter_add(data, writer);
+ }
+ return result;
+}
+
CURLcode Curl_cwriter_add(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
CURLcode result;
- struct Curl_cwriter **anchor = &data->req.writer_stack;
+ struct Curl_cwriter **anchor = &data->req.writer.stack;
if(!*anchor) {
result = do_init_writer_stack(data);
return result;
}
- /* Insert the writer as first in its phase.
- * Skip existing writers of lower phases. */
- while(*anchor && (*anchor)->phase < writer->phase)
- anchor = &((*anchor)->next);
- writer->next = *anchor;
- *anchor = writer;
+ if(writer->phase == CURL_CW_CONTENT_DECODE) {
+ /* On adding a content decoder, add the pause writer. Do this
+ * BEFORE the given writer as any failure will make the
+ * caller destroy the writer again. */
+ result = cwriter_ensure_pause_writer(data);
+ if(result)
+ return result;
+ }
+
+ cwriter_add(data, writer);
return CURLE_OK;
}
const char *name)
{
struct Curl_cwriter *writer;
- for(writer = data->req.writer_stack; writer; writer = writer->next) {
+ for(writer = data->req.writer.stack; writer; writer = writer->next) {
if(!strcmp(name, writer->cwt->name))
return writer;
}
const struct Curl_cwtype *cwt)
{
struct Curl_cwriter *writer;
- for(writer = data->req.writer_stack; writer; writer = writer->next) {
+ for(writer = data->req.writer.stack; writer; writer = writer->next) {
if(writer->cwt == cwt)
return writer;
}
return NULL;
}
-bool Curl_cwriter_is_content_decoding(struct Curl_easy *data)
-{
- struct Curl_cwriter *writer;
- for(writer = data->req.writer_stack; writer; writer = writer->next) {
- if(writer->phase == CURL_CW_CONTENT_DECODE)
- return TRUE;
- }
- return FALSE;
-}
-
-bool Curl_cwriter_is_paused(struct Curl_easy *data)
-{
- return Curl_cw_out_is_paused(data);
-}
-
CURLcode Curl_cwriter_unpause(struct Curl_easy *data)
{
- CURLcode result = Curl_cw_out_unpause(data);
- if(!result)
- result = Curl_cwriter_flush(data, data->req.writer_stack);
- return result;
+ data->req.writer.paused = FALSE;
+ return Curl_cwriter_flush(data, data->req.writer.stack);
}
CURLcode Curl_creader_read(struct Curl_easy *data,
DEBUGASSERT(r);
DEBUGASSERT(r->crt);
DEBUGASSERT(r->phase == CURL_CR_CLIENT);
- DEBUGASSERT(!data->req.reader_stack);
+ DEBUGASSERT(!data->req.reader.stack);
- data->req.reader_stack = r;
+ data->req.reader.stack = r;
clen = r->crt->total_length(data, r);
/* if we do not have 0 length init, and crlf conversion is wanted,
* add the reader for it */
struct Curl_creader *reader)
{
CURLcode result;
- struct Curl_creader **anchor = &data->req.reader_stack;
+ struct Curl_creader **anchor = &data->req.reader.stack;
if(!*anchor) {
result = Curl_creader_set_fread(data, data->state.infilesize);
DEBUGASSERT(eos);
*nread = 0;
- if(!data->req.reader_stack) {
+ if(!data->req.reader.stack) {
result = Curl_creader_set_fread(data, data->state.infilesize);
if(result)
return result;
- DEBUGASSERT(data->req.reader_stack);
+ DEBUGASSERT(data->req.reader.stack);
}
if(!data->req.reader_started) {
Curl_rlimit_start(&data->progress.ul.rlimit, Curl_pgrs_now(data), -1);
if(ul_avail < (curl_off_t)blen)
blen = (size_t)ul_avail;
}
- result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
+ result = Curl_creader_read(data, data->req.reader.stack, buf, blen,
nread, eos);
out:
bool Curl_creader_needs_rewind(struct Curl_easy *data)
{
- struct Curl_creader *reader = data->req.reader_stack;
+ struct Curl_creader *reader = data->req.reader.stack;
while(reader) {
if(reader->crt->needs_rewind(data, reader)) {
CURL_TRC_READ(data, "client reader needs rewind before next request");
curl_off_t Curl_creader_total_length(struct Curl_easy *data)
{
- struct Curl_creader *r = data->req.reader_stack;
+ struct Curl_creader *r = data->req.reader.stack;
return r ? r->crt->total_length(data, r) : -1;
}
curl_off_t Curl_creader_client_length(struct Curl_easy *data)
{
- struct Curl_creader *r = data->req.reader_stack;
+ struct Curl_creader *r = data->req.reader.stack;
while(r && r->phase != CURL_CR_CLIENT)
r = r->next;
return r ? r->crt->total_length(data, r) : -1;
CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
{
- struct Curl_creader *r = data->req.reader_stack;
+ struct Curl_creader *r = data->req.reader.stack;
while(r && r->phase != CURL_CR_CLIENT)
r = r->next;
return r ? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
CURLcode Curl_creader_unpause(struct Curl_easy *data)
{
- struct Curl_creader *reader = data->req.reader_stack;
+ struct Curl_creader *reader = data->req.reader.stack;
CURLcode result = CURLE_OK;
while(reader) {
bool Curl_creader_is_paused(struct Curl_easy *data)
{
- struct Curl_creader *reader = data->req.reader_stack;
+ struct Curl_creader *reader = data->req.reader.stack;
while(reader) {
if(reader->crt->is_paused(data, reader))
void Curl_creader_done(struct Curl_easy *data, int premature)
{
- struct Curl_creader *reader = data->req.reader_stack;
+ struct Curl_creader *reader = data->req.reader.stack;
while(reader) {
reader->crt->done(data, reader, premature);
reader = reader->next;
const struct Curl_crtype *crt)
{
struct Curl_creader *r;
- for(r = data->req.reader_stack; r; r = r->next) {
+ for(r = data->req.reader.stack; r; r = r->next) {
if(r->crt == crt)
return r;
}