if(0 == len)
return HYPER_ITER_CONTINUE;
Curl_debug(data, CURLINFO_DATA_IN, buf, len);
- if(!data->set.http_ce_skip && k->writer_stack)
- /* content-encoded data */
- result = Curl_unencode_write(data, k->writer_stack, buf, len);
- else
- result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
if(result) {
data->state.hresult = result;
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
- if(!writer->downstream)
- return CURLE_WRITE_ERROR;
-
/* Initialize zlib */
z->zalloc = (alloc_func) zalloc_cb;
z->zfree = (free_func) zfree_cb;
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
- if(!writer->downstream)
- return CURLE_WRITE_ERROR;
-
/* Initialize zlib */
z->zalloc = (alloc_func) zalloc_cb;
z->zfree = (free_func) zfree_cb;
struct brotli_writer *bp = (struct brotli_writer *) writer;
(void) data;
- if(!writer->downstream)
- return CURLE_WRITE_ERROR;
-
bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL);
return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
}
(void)data;
- if(!writer->downstream)
- return CURLE_WRITE_ERROR;
-
zp->zds = ZSTD_createDStream();
zp->decomp = NULL;
return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
static CURLcode identity_init_writer(struct Curl_easy *data,
struct contenc_writer *writer)
{
- (void) data;
- return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
+ (void)data;
+ (void)writer;
+ return CURLE_OK;
}
static CURLcode identity_unencode_write(struct Curl_easy *data,
}
-/* Real client writer: no downstream. */
-static CURLcode client_init_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
-{
- (void) data;
- return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
-}
-
-static CURLcode client_unencode_write(struct Curl_easy *data,
- struct contenc_writer *writer,
- const char *buf, size_t nbytes)
-{
- struct SingleRequest *k = &data->req;
-
- (void) writer;
-
- if(!nbytes || k->ignorebody)
- return CURLE_OK;
-
- return Curl_client_write(data, CLIENTWRITE_BODY, (char *) buf, nbytes);
-}
-
-static void client_close_writer(struct Curl_easy *data,
- struct contenc_writer *writer)
-{
- (void) data;
- (void) writer;
-}
-
-static const struct content_encoding client_encoding = {
- NULL,
- NULL,
- client_init_writer,
- client_unencode_write,
- client_close_writer,
- sizeof(struct contenc_writer)
-};
-
-
/* Deferred error dummy writer. */
static CURLcode error_init_writer(struct Curl_easy *data,
struct contenc_writer *writer)
{
- (void) data;
- return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
+ (void)data;
+ (void)writer;
+ return CURLE_OK;
}
static CURLcode error_unencode_write(struct Curl_easy *data,
sizeof(struct contenc_writer)
};
-/* Create an unencoding writer stage using the given handler. */
-static struct contenc_writer *
-new_unencoding_writer(struct Curl_easy *data,
- const struct content_encoding *handler,
- struct contenc_writer *downstream,
- int order)
-{
- struct contenc_writer *writer;
-
- DEBUGASSERT(handler->writersize >= sizeof(struct contenc_writer));
- writer = (struct contenc_writer *) calloc(1, handler->writersize);
-
- if(writer) {
- writer->handler = handler;
- writer->downstream = downstream;
- writer->order = order;
- if(handler->init_writer(data, writer)) {
- free(writer);
- writer = NULL;
- }
- }
-
- return writer;
-}
-
/* Write data using an unencoding writer stack. "nbytes" is not
allowed to be 0. */
CURLcode Curl_unencode_write(struct Curl_easy *data,
{
if(!nbytes)
return CURLE_OK;
+ if(!writer)
+ return CURLE_WRITE_ERROR;
return writer->handler->unencode_write(data, writer, buf, nbytes);
}
-/* Close and clean-up the connection's writer stack. */
-void Curl_unencode_cleanup(struct Curl_easy *data)
-{
- struct SingleRequest *k = &data->req;
- struct contenc_writer *writer = k->writer_stack;
-
- while(writer) {
- k->writer_stack = writer->downstream;
- writer->handler->close_writer(data, writer);
- free(writer);
- writer = k->writer_stack;
- }
-}
-
/* Find the content encoding by name. */
static const struct content_encoding *find_encoding(const char *name,
size_t len)
return NULL;
}
-/* allow no more than 5 "chained" compression steps */
-#define MAX_ENCODE_STACK 5
-
/* Set-up the unencoding stack from the Content-Encoding header value.
* See RFC 7231 section 3.1.2.2. */
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
{
struct SingleRequest *k = &data->req;
unsigned int order = is_transfer? 2: 1;
+ CURLcode result;
do {
const char *name;
if(is_transfer && !data->set.http_transfer_encoding)
/* not requested, ignore */
return CURLE_OK;
- encoding = find_encoding(name, namelen);
-
- if(!k->writer_stack) {
- k->writer_stack = new_unencoding_writer(data, &client_encoding,
- NULL, 0);
-
- if(!k->writer_stack)
- return CURLE_OUT_OF_MEMORY;
- }
+ encoding = find_encoding(name, namelen);
if(!encoding)
encoding = &error_encoding; /* Defer error at stack use. */
- if(k->writer_stack_depth++ >= MAX_ENCODE_STACK) {
- failf(data, "Reject response due to more than %u content encodings",
- MAX_ENCODE_STACK);
- return CURLE_BAD_CONTENT_ENCODING;
- }
- /* Stack the unencoding stage. */
- if(order >= k->writer_stack->order) {
- writer = new_unencoding_writer(data, encoding,
- k->writer_stack, order);
- if(!writer)
- return CURLE_OUT_OF_MEMORY;
- k->writer_stack = writer;
- }
- else {
- struct contenc_writer *w = k->writer_stack;
- while(w->downstream && order < w->downstream->order)
- w = w->downstream;
- writer = new_unencoding_writer(data, encoding,
- w->downstream, order);
- if(!writer)
- return CURLE_OUT_OF_MEMORY;
- w->downstream = writer;
+ result = Curl_client_create_writer(&writer, data, encoding, order);
+ if(result)
+ return result;
+
+ result = Curl_client_add_writer(data, writer);
+ if(result) {
+ Curl_client_free_writer(data, writer);
+ return result;
}
}
} while(*enclist);
return CURLE_NOT_BUILT_IN;
}
-void Curl_unencode_cleanup(struct Curl_easy *data)
-{
- (void) data;
-}
-
char *Curl_all_content_encodings(void)
{
return strdup(CONTENT_ENCODING_DEFAULT); /* Satisfy caller. */
***************************************************************************/
#include "curl_setup.h"
-struct contenc_writer {
- const struct content_encoding *handler; /* Encoding handler. */
- struct contenc_writer *downstream; /* Downstream writer. */
- unsigned int order; /* Ordering within writer stack. */
-};
-
-/* Content encoding writer. */
-struct content_encoding {
- const char *name; /* Encoding name. */
- const char *alias; /* Encoding name alias. */
- CURLcode (*init_writer)(struct Curl_easy *data,
- struct contenc_writer *writer);
- CURLcode (*unencode_write)(struct Curl_easy *data,
- struct contenc_writer *writer,
- const char *buf, size_t nbytes);
- void (*close_writer)(struct Curl_easy *data,
- struct contenc_writer *writer);
- size_t writersize;
-};
+struct contenc_writer;
+char *Curl_all_content_encodings(void);
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const char *enclist, int is_transfer);
struct contenc_writer *writer,
const char *buf, size_t nbytes);
void Curl_unencode_cleanup(struct Curl_easy *data);
-char *Curl_all_content_encodings(void);
#endif /* HEADER_CURL_CONTENT_ENCODING_H */
data->state.authhost.multipass = FALSE;
data->state.authproxy.multipass = FALSE;
- Curl_unencode_cleanup(data);
-
/* set the proper values (possibly modified on POST) */
conn->seek_func = data->set.seek_func; /* restore */
conn->seek_client = data->set.seek_client; /* restore */
/* Write the data portion available */
if(!data->set.http_te_skip && !k->ignorebody) {
- if(!data->set.http_ce_skip && k->writer_stack)
- result = Curl_unencode_write(data, k->writer_stack, datap, piece);
- else
- result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece);
if(result) {
*extrap = result;
{
CURLcode result;
struct connectdata *conn = data->conn;
- unsigned int i;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d",
Curl_safefree(data->state.ulbuf);
- /* if the transfer was completed in a paused state there can be buffered
- data left to free */
- for(i = 0; i < data->state.tempcount; i++) {
- Curl_dyn_free(&data->state.tempwrite[i].b);
- }
- data->state.tempcount = 0;
+ Curl_client_cleanup(data);
CONNCACHE_LOCK(data);
Curl_detach_connection(data);
#include "sendf.h"
#include "cfilters.h"
#include "connect.h"
+#include "content_encoding.h"
#include "vtls/vtls.h"
#include "vssh/ssh.h"
#include "easyif.h"
DEBUGASSERT(!(type & CLIENTWRITE_BODY) || (type == CLIENTWRITE_BODY));
/* INFO is only INFO */
DEBUGASSERT(!(type & CLIENTWRITE_INFO) || (type == CLIENTWRITE_INFO));
+
+ if(type == CLIENTWRITE_BODY) {
+ if(data->req.ignorebody)
+ return CURLE_OK;
+
+ if(data->req.writer_stack && !data->set.http_ce_skip)
+ return Curl_unencode_write(data, data->req.writer_stack, ptr, len);
+ }
return chop_write(data, type, FALSE, ptr, len);
}
return result;
}
+void Curl_client_cleanup(struct Curl_easy *data)
+{
+ struct contenc_writer *writer = data->req.writer_stack;
+ size_t i;
+
+ while(writer) {
+ data->req.writer_stack = writer->downstream;
+ writer->handler->close_writer(data, writer);
+ free(writer);
+ writer = data->req.writer_stack;
+ }
+
+ for(i = 0; i < data->state.tempcount; i++) {
+ Curl_dyn_free(&data->state.tempwrite[i].b);
+ }
+ data->state.tempcount = 0;
+
+}
+
+/* Real client writer: no downstream. */
+static CURLcode client_cew_init(struct Curl_easy *data,
+ struct contenc_writer *writer)
+{
+ (void) data;
+ (void)writer;
+ return CURLE_OK;
+}
+
+static CURLcode client_cew_write(struct Curl_easy *data,
+ struct contenc_writer *writer,
+ const char *buf, size_t nbytes)
+{
+ (void)writer;
+ if(!nbytes || data->req.ignorebody)
+ return CURLE_OK;
+ return chop_write(data, CLIENTWRITE_BODY, FALSE, (char *)buf, nbytes);
+}
+
+static void client_cew_close(struct Curl_easy *data,
+ struct contenc_writer *writer)
+{
+ (void) data;
+ (void) writer;
+}
+
+static const struct content_encoding client_cew = {
+ NULL,
+ NULL,
+ client_cew_init,
+ client_cew_write,
+ client_cew_close,
+ sizeof(struct contenc_writer)
+};
+
+/* Create an unencoding writer stage using the given handler. */
+CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
+ struct Curl_easy *data,
+ const struct content_encoding *ce_handler,
+ int order)
+{
+ struct contenc_writer *writer;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
+
+ DEBUGASSERT(ce_handler->writersize >= sizeof(struct contenc_writer));
+ writer = (struct contenc_writer *) calloc(1, ce_handler->writersize);
+ if(!writer)
+ goto out;
+
+ writer->handler = ce_handler;
+ writer->order = order;
+ result = ce_handler->init_writer(data, writer);
+
+out:
+ *pwriter = result? NULL : writer;
+ if(result)
+ free(writer);
+ return result;
+}
+
+void Curl_client_free_writer(struct Curl_easy *data,
+ struct contenc_writer *writer)
+{
+ if(writer) {
+ writer->handler->close_writer(data, writer);
+ free(writer);
+ }
+}
+
+/* allow no more than 5 "chained" compression steps */
+#define MAX_ENCODE_STACK 5
+
+
+static CURLcode init_writer_stack(struct Curl_easy *data)
+{
+ DEBUGASSERT(!data->req.writer_stack);
+ return Curl_client_create_writer(&data->req.writer_stack,
+ data, &client_cew, 0);
+}
+
+CURLcode Curl_client_add_writer(struct Curl_easy *data,
+ struct contenc_writer *writer)
+{
+ CURLcode result;
+
+ if(!data->req.writer_stack) {
+ result = init_writer_stack(data);
+ if(result)
+ return result;
+ }
+
+ if(data->req.writer_stack_depth++ >= MAX_ENCODE_STACK) {
+ failf(data, "Reject response due to more than %u content encodings",
+ MAX_ENCODE_STACK);
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Stack the unencoding stage. */
+ if(writer->order >= data->req.writer_stack->order) {
+ writer->downstream = data->req.writer_stack;
+ data->req.writer_stack = writer;
+ }
+ else {
+ struct contenc_writer *w = data->req.writer_stack;
+ while(w->downstream && writer->order < w->downstream->order)
+ w = w->downstream;
+ writer->downstream = w->downstream;
+ w->downstream = writer;
+ }
+ return CURLE_OK;
+}
+
+
/*
* Internal read-from-socket function. This is meant to deal with plain
* sockets, SSL sockets and kerberos sockets.
size_t len) WARN_UNUSED_RESULT;
CURLcode Curl_client_unpause(struct Curl_easy *data);
+void Curl_client_cleanup(struct Curl_easy *data);
+
+struct contenc_writer {
+ const struct content_encoding *handler; /* Encoding handler. */
+ struct contenc_writer *downstream; /* Downstream writer. */
+ unsigned int order; /* Ordering within writer stack. */
+};
+
+/* Content encoding writer. */
+struct content_encoding {
+ const char *name; /* Encoding name. */
+ const char *alias; /* Encoding name alias. */
+ CURLcode (*init_writer)(struct Curl_easy *data,
+ struct contenc_writer *writer);
+ CURLcode (*unencode_write)(struct Curl_easy *data,
+ struct contenc_writer *writer,
+ const char *buf, size_t nbytes);
+ void (*close_writer)(struct Curl_easy *data,
+ struct contenc_writer *writer);
+ size_t writersize;
+};
+
+
+CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
+ struct Curl_easy *data,
+ const struct content_encoding *ce_handler,
+ int order);
+
+void Curl_client_free_writer(struct Curl_easy *data,
+ struct contenc_writer *writer);
+
+CURLcode Curl_client_add_writer(struct Curl_easy *data,
+ struct contenc_writer *writer);
+
/* internal read-function, does plain socket, SSL and krb4 */
CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd,
in http_chunks.c.
Make sure that ALL_CONTENT_ENCODINGS contains all the
encodings handled here. */
- if(data->set.http_ce_skip || !k->writer_stack) {
- if(!k->ignorebody && nread) {
+ if(!k->ignorebody && nread) {
#ifndef CURL_DISABLE_POP3
- if(conn->handler->protocol & PROTO_FAMILY_POP3)
- result = Curl_pop3_write(data, k->str, nread);
- else
+ if(conn->handler->protocol & PROTO_FAMILY_POP3)
+ result = Curl_pop3_write(data, k->str, nread);
+ else
#endif /* CURL_DISABLE_POP3 */
- result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
- nread);
- }
+ result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
+ nread);
}
- else if(!k->ignorebody && nread)
- result = Curl_unencode_write(data, k->writer_stack, k->str, nread);
}
k->badheader = HEADER_NORMAL; /* taken care of now */
{
Curl_safefree(data->req.p.http);
Curl_safefree(data->req.newurl);
-
#ifndef CURL_DISABLE_DOH
if(data->req.doh) {
Curl_close(&data->req.doh->probe[0].easy);
Curl_close(&data->req.doh->probe[1].easy);
}
#endif
+ Curl_client_cleanup(data);
}