lib: client writer, part 2, accounting + logging

This PR has these changes:

Renaming of unencode_* to cwriter, e.g. client writers
- documentation of sendf.h functions
- move max decode stack checks back to content_encoding.c
- define writer phase which was used as order before
- introduce phases for monitoring inbetween decode phases
- offering default implementations for init/write/close

Add type paramter to client writer's do_write()
- always pass all writes through the writer stack
- writers who only care about BODY data will pass other writes unchanged

add RAW and PROTOCOL client writers
- RAW used for Curl_debug() logging of CURLINFO_DATA_IN
- PROTOCOL used for updates to data->req.bytecount, max_filesize checks and
  Curl_pgrsSetDownloadCounter()
- remove all updates of data->req.bytecount and calls to
  Curl_pgrsSetDownloadCounter() and Curl_debug() from other code
- adjust test457 expected output to no longer see the excess write

Closes #12184
This commit is contained in:
Stefan Eissing 2023-10-23 10:33:07 +02:00 committed by Daniel Stenberg
parent 2b16b86bb6
commit ad051e1cbe
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
20 changed files with 459 additions and 389 deletions

View File

@ -172,17 +172,15 @@ static int hyper_each_header(void *userdata,
Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
if(!data->state.hconnect || !data->set.suppress_connect_headers) {
writetype = CLIENTWRITE_HEADER;
if(data->state.hconnect)
writetype |= CLIENTWRITE_CONNECT;
if(data->req.httpcode/100 == 1)
writetype |= CLIENTWRITE_1XX;
result = Curl_client_write(data, writetype, headp, len);
if(result) {
data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
return HYPER_ITER_BREAK;
}
writetype = CLIENTWRITE_HEADER;
if(data->state.hconnect)
writetype |= CLIENTWRITE_CONNECT;
if(data->req.httpcode/100 == 1)
writetype |= CLIENTWRITE_1XX;
result = Curl_client_write(data, writetype, headp, len);
if(result) {
data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
return HYPER_ITER_BREAK;
}
result = Curl_bump_headersize(data, len, FALSE);
@ -201,7 +199,7 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
struct SingleRequest *k = &data->req;
CURLcode result = CURLE_OK;
if(0 == k->bodywrites++) {
if(0 == k->bodywrites) {
bool done = FALSE;
#if defined(USE_NTLM)
struct connectdata *conn = data->conn;
@ -241,11 +239,6 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
return HYPER_ITER_BREAK;
}
}
if(k->ignorebody)
return HYPER_ITER_CONTINUE;
if(0 == len)
return HYPER_ITER_CONTINUE;
Curl_debug(data, CURLINFO_DATA_IN, buf, len);
result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
if(result) {
@ -253,12 +246,6 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
return HYPER_ITER_BREAK;
}
data->req.bytecount += len;
result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
if(result) {
data->state.hresult = result;
return HYPER_ITER_BREAK;
}
return HYPER_ITER_CONTINUE;
}
@ -310,13 +297,14 @@ static CURLcode status_line(struct Curl_easy *data,
Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
len);
if(!data->state.hconnect || !data->set.suppress_connect_headers) {
writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS;
result = Curl_client_write(data, writetype,
Curl_dyn_ptr(&data->state.headerb), len);
if(result)
return result;
}
writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS;
if(data->state.hconnect)
writetype |= CLIENTWRITE_CONNECT;
result = Curl_client_write(data, writetype,
Curl_dyn_ptr(&data->state.headerb), len);
if(result)
return result;
result = Curl_bump_headersize(data, len, FALSE);
return result;
}

View File

@ -374,7 +374,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data);
char *linep;
size_t perline;
int error;
int error, writetype;
#define SELECT_OK 0
#define SELECT_ERROR 1
@ -467,15 +467,12 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
/* output debug if that is requested */
Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
if(!data->set.suppress_connect_headers) {
/* send the header to the callback */
int writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
(ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
result = Curl_client_write(data, writetype, linep, perline);
if(result)
return result;
}
/* send the header to the callback */
writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
(ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
result = Curl_client_write(data, writetype, linep, perline);
if(result)
return result;
result = Curl_bump_headersize(data, perline, TRUE);
if(result)

View File

@ -63,6 +63,9 @@
#ifndef CURL_DISABLE_HTTP
/* allow no more than 5 "chained" compression steps */
#define MAX_ENCODE_STACK 5
#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
@ -95,7 +98,7 @@ typedef enum {
/* Deflate and gzip writer. */
struct zlib_writer {
struct contenc_writer super;
struct Curl_cwriter super;
zlibInitState zlib_init; /* zlib init state */
uInt trailerlen; /* Remaining trailer byte count. */
z_stream z; /* State structure for zlib. */
@ -171,7 +174,7 @@ static CURLcode process_trailer(struct Curl_easy *data,
}
static CURLcode inflate_stream(struct Curl_easy *data,
struct contenc_writer *writer,
struct Curl_cwriter *writer, int type,
zlibInitState started)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
@ -196,7 +199,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
/* because the buffer size is fixed, iteratively decompress and transfer to
the client via downstream_write function. */
the client via next_write function. */
while(!done) {
int status; /* zlib status */
done = TRUE;
@ -217,7 +220,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
if(z->avail_out != DSIZ) {
if(status == Z_OK || status == Z_STREAM_END) {
zp->zlib_init = started; /* Data started. */
result = Curl_unencode_write(data, writer->downstream, decomp,
result = Curl_cwriter_write(data, writer->next, type, decomp,
DSIZ - z->avail_out);
if(result) {
exit_zlib(data, z, &zp->zlib_init, result);
@ -274,8 +277,8 @@ static CURLcode inflate_stream(struct Curl_easy *data,
/* Deflate handler. */
static CURLcode deflate_init_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static CURLcode deflate_do_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@ -290,13 +293,16 @@ static CURLcode deflate_init_writer(struct Curl_easy *data,
return CURLE_OK;
}
static CURLcode deflate_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
static CURLcode deflate_do_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
/* Set the compressed input when this function is called */
z->next_in = (Bytef *) buf;
z->avail_in = (uInt) nbytes;
@ -305,11 +311,11 @@ static CURLcode deflate_unencode_write(struct Curl_easy *data,
return process_trailer(data, zp);
/* Now uncompress the data */
return inflate_stream(data, writer, ZLIB_INFLATING);
return inflate_stream(data, writer, type, ZLIB_INFLATING);
}
static void deflate_close_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static void deflate_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@ -317,19 +323,19 @@ static void deflate_close_writer(struct Curl_easy *data,
exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
}
static const struct content_encoding deflate_encoding = {
static const struct Curl_cwtype deflate_encoding = {
"deflate",
NULL,
deflate_init_writer,
deflate_unencode_write,
deflate_close_writer,
deflate_do_init,
deflate_do_write,
deflate_do_close,
sizeof(struct zlib_writer)
};
/* Gzip handler. */
static CURLcode gzip_init_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static CURLcode gzip_do_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@ -441,19 +447,22 @@ static enum {
}
#endif
static CURLcode gzip_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
static CURLcode gzip_do_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(zp->zlib_init == ZLIB_INIT_GZIP) {
/* Let zlib handle the gzip decompression entirely */
z->next_in = (Bytef *) buf;
z->avail_in = (uInt) nbytes;
/* Now uncompress the data */
return inflate_stream(data, writer, ZLIB_INIT_GZIP);
return inflate_stream(data, writer, type, ZLIB_INIT_GZIP);
}
#ifndef OLD_ZLIB_SUPPORT
@ -565,12 +574,12 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
}
/* We've parsed the header, now uncompress the data */
return inflate_stream(data, writer, ZLIB_GZIP_INFLATING);
return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING);
#endif
}
static void gzip_close_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static void gzip_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
@ -578,12 +587,12 @@ static void gzip_close_writer(struct Curl_easy *data,
exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
}
static const struct content_encoding gzip_encoding = {
static const struct Curl_cwtype gzip_encoding = {
"gzip",
"x-gzip",
gzip_init_writer,
gzip_unencode_write,
gzip_close_writer,
gzip_do_init,
gzip_do_write,
gzip_do_close,
sizeof(struct zlib_writer)
};
@ -593,7 +602,7 @@ static const struct content_encoding gzip_encoding = {
#ifdef HAVE_BROTLI
/* Brotli writer. */
struct brotli_writer {
struct contenc_writer super;
struct Curl_cwriter super;
BrotliDecoderState *br; /* State structure for brotli. */
};
@ -635,8 +644,8 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
return CURLE_WRITE_ERROR;
}
static CURLcode brotli_init_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static CURLcode brotli_do_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct brotli_writer *bp = (struct brotli_writer *) writer;
(void) data;
@ -645,8 +654,8 @@ static CURLcode brotli_init_writer(struct Curl_easy *data,
return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
}
static CURLcode brotli_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
static CURLcode brotli_do_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
struct brotli_writer *bp = (struct brotli_writer *) writer;
@ -657,6 +666,9 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data,
CURLcode result = CURLE_OK;
BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!bp->br)
return CURLE_WRITE_ERROR; /* Stream already ended. */
@ -670,7 +682,7 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data,
dstleft = DSIZ;
r = BrotliDecoderDecompressStream(bp->br,
&nbytes, &src, &dstleft, &dst, NULL);
result = Curl_unencode_write(data, writer->downstream,
result = Curl_cwriter_write(data, writer->next, type,
decomp, DSIZ - dstleft);
if(result)
break;
@ -693,8 +705,8 @@ static CURLcode brotli_unencode_write(struct Curl_easy *data,
return result;
}
static void brotli_close_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static void brotli_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct brotli_writer *bp = (struct brotli_writer *) writer;
@ -706,12 +718,12 @@ static void brotli_close_writer(struct Curl_easy *data,
}
}
static const struct content_encoding brotli_encoding = {
static const struct Curl_cwtype brotli_encoding = {
"br",
NULL,
brotli_init_writer,
brotli_unencode_write,
brotli_close_writer,
brotli_do_init,
brotli_do_write,
brotli_do_close,
sizeof(struct brotli_writer)
};
#endif
@ -720,13 +732,13 @@ static const struct content_encoding brotli_encoding = {
#ifdef HAVE_ZSTD
/* Zstd writer. */
struct zstd_writer {
struct contenc_writer super;
struct Curl_cwriter super;
ZSTD_DStream *zds; /* State structure for zstd. */
void *decomp;
};
static CURLcode zstd_init_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static CURLcode zstd_do_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zstd_writer *zp = (struct zstd_writer *) writer;
@ -737,8 +749,8 @@ static CURLcode zstd_init_writer(struct Curl_easy *data,
return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
}
static CURLcode zstd_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
static CURLcode zstd_do_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
CURLcode result = CURLE_OK;
@ -747,6 +759,9 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data,
ZSTD_outBuffer out;
size_t errorCode;
if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!zp->decomp) {
zp->decomp = malloc(DSIZ);
if(!zp->decomp)
@ -766,7 +781,7 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data,
return CURLE_BAD_CONTENT_ENCODING;
}
if(out.pos > 0) {
result = Curl_unencode_write(data, writer->downstream,
result = Curl_cwriter_write(data, writer->next, type,
zp->decomp, out.pos);
if(result)
break;
@ -778,8 +793,8 @@ static CURLcode zstd_unencode_write(struct Curl_easy *data,
return result;
}
static void zstd_close_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static void zstd_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
struct zstd_writer *zp = (struct zstd_writer *) writer;
@ -795,52 +810,30 @@ static void zstd_close_writer(struct Curl_easy *data,
}
}
static const struct content_encoding zstd_encoding = {
static const struct Curl_cwtype zstd_encoding = {
"zstd",
NULL,
zstd_init_writer,
zstd_unencode_write,
zstd_close_writer,
zstd_do_init,
zstd_do_write,
zstd_do_close,
sizeof(struct zstd_writer)
};
#endif
/* Identity handler. */
static CURLcode identity_init_writer(struct Curl_easy *data,
struct contenc_writer *writer)
{
(void)data;
(void)writer;
return CURLE_OK;
}
static CURLcode identity_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
return Curl_unencode_write(data, writer->downstream, buf, nbytes);
}
static void identity_close_writer(struct Curl_easy *data,
struct contenc_writer *writer)
{
(void) data;
(void) writer;
}
static const struct content_encoding identity_encoding = {
static const struct Curl_cwtype identity_encoding = {
"identity",
"none",
identity_init_writer,
identity_unencode_write,
identity_close_writer,
sizeof(struct contenc_writer)
Curl_cwriter_def_init,
Curl_cwriter_def_write,
Curl_cwriter_def_close,
sizeof(struct Curl_cwriter)
};
/* supported content encodings table. */
static const struct content_encoding * const encodings[] = {
static const struct Curl_cwtype * const encodings[] = {
&identity_encoding,
#ifdef HAVE_LIBZ
&deflate_encoding,
@ -860,8 +853,8 @@ static const struct content_encoding * const encodings[] = {
char *Curl_all_content_encodings(void)
{
size_t len = 0;
const struct content_encoding * const *cep;
const struct content_encoding *ce;
const struct Curl_cwtype * const *cep;
const struct Curl_cwtype *ce;
char *ace;
for(cep = encodings; *cep; cep++) {
@ -893,16 +886,16 @@ char *Curl_all_content_encodings(void)
/* Deferred error dummy writer. */
static CURLcode error_init_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static CURLcode error_do_init(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
(void)data;
(void)writer;
return CURLE_OK;
}
static CURLcode error_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
static CURLcode error_do_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
char *all = Curl_all_content_encodings();
@ -911,6 +904,9 @@ static CURLcode error_unencode_write(struct Curl_easy *data,
(void) buf;
(void) nbytes;
if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!all)
return CURLE_OUT_OF_MEMORY;
failf(data, "Unrecognized content encoding type. "
@ -919,43 +915,30 @@ static CURLcode error_unencode_write(struct Curl_easy *data,
return CURLE_BAD_CONTENT_ENCODING;
}
static void error_close_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static void error_do_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
(void) data;
(void) writer;
}
static const struct content_encoding error_encoding = {
static const struct Curl_cwtype error_writer = {
"ce-error",
NULL,
NULL,
error_init_writer,
error_unencode_write,
error_close_writer,
sizeof(struct contenc_writer)
error_do_init,
error_do_write,
error_do_close,
sizeof(struct Curl_cwriter)
};
/* Write data using an unencoding writer stack. "nbytes" is not
allowed to be 0. */
CURLcode Curl_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
if(!nbytes)
return CURLE_OK;
if(!writer)
return CURLE_WRITE_ERROR;
return writer->handler->unencode_write(data, writer, buf, nbytes);
}
/* Find the content encoding by name. */
static const struct content_encoding *find_encoding(const char *name,
static const struct Curl_cwtype *find_encoding(const char *name,
size_t len)
{
const struct content_encoding * const *cep;
const struct Curl_cwtype * const *cep;
for(cep = encodings; *cep; cep++) {
const struct content_encoding *ce = *cep;
const struct Curl_cwtype *ce = *cep;
if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
(ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
return ce;
@ -969,7 +952,8 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const char *enclist, int is_transfer)
{
struct SingleRequest *k = &data->req;
unsigned int order = is_transfer? 2: 1;
Curl_cwriter_phase phase = is_transfer?
CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE;
CURLcode result;
do {
@ -992,23 +976,32 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
Curl_httpchunk_init(data); /* init our chunky engine. */
}
else if(namelen) {
const struct content_encoding *encoding;
struct contenc_writer *writer;
if(is_transfer && !data->set.http_transfer_encoding)
const struct Curl_cwtype *cwt;
struct Curl_cwriter *writer;
if((is_transfer && !data->set.http_transfer_encoding) ||
(!is_transfer && data->set.http_ce_skip)) {
/* not requested, ignore */
return CURLE_OK;
}
encoding = find_encoding(name, namelen);
if(!encoding)
encoding = &error_encoding; /* Defer error at stack use. */
if(Curl_cwriter_count(data, phase) + 1 >= MAX_ENCODE_STACK) {
failf(data, "Reject response due to more than %u content encodings",
MAX_ENCODE_STACK);
return CURLE_BAD_CONTENT_ENCODING;
}
result = Curl_client_create_writer(&writer, data, encoding, order);
cwt = find_encoding(name, namelen);
if(!cwt)
cwt = &error_writer; /* Defer error at use. */
result = Curl_cwriter_create(&writer, data, cwt, phase);
if(result)
return result;
result = Curl_client_add_writer(data, writer);
result = Curl_cwriter_add(data, writer);
if(result) {
Curl_client_free_writer(data, writer);
Curl_cwriter_free(data, writer);
return result;
}
}
@ -1028,17 +1021,6 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
return CURLE_NOT_BUILT_IN;
}
CURLcode Curl_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
(void) data;
(void) writer;
(void) buf;
(void) nbytes;
return CURLE_NOT_BUILT_IN;
}
char *Curl_all_content_encodings(void)
{
return strdup(CONTENT_ENCODING_DEFAULT); /* Satisfy caller. */

View File

@ -25,15 +25,10 @@
***************************************************************************/
#include "curl_setup.h"
struct contenc_writer;
struct Curl_cwriter;
char *Curl_all_content_encodings(void);
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const char *enclist, int is_transfer);
CURLcode Curl_unencode_write(struct Curl_easy *data,
struct contenc_writer *writer,
const char *buf, size_t nbytes);
void Curl_unencode_cleanup(struct Curl_easy *data);
#endif /* HEADER_CURL_CONTENT_ENCODING_H */

View File

@ -414,7 +414,6 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
bool size_known;
bool fstated = FALSE;
char *buf = data->state.buffer;
curl_off_t bytecount = 0;
int fd;
struct FILEPROTO *file;
@ -563,7 +562,6 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
if(nread <= 0 || (size_known && (expected_size == 0)))
break;
bytecount += nread;
if(size_known)
expected_size -= nread;
@ -571,10 +569,6 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
if(result)
return result;
result = Curl_pgrsSetDownloadCounter(data, bytecount);
if(result)
return result;
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else

View File

@ -1194,8 +1194,6 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
if(result)
return result;
data->req.bytecount += chunk;
infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
" bytes are left for transfer", chunk, size - chunk);

View File

@ -313,7 +313,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
int ldap_ssl = 0;
char *val_b64 = NULL;
size_t val_b64_sz = 0;
curl_off_t dlsize = 0;
#ifdef LDAP_OPT_NETWORK_TIMEOUT
struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */
#endif
@ -535,6 +534,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
Curl_pgrsSetDownloadCounter(data, 0);
rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
@ -596,8 +596,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
dlsize += name_len + 5;
FREE_ON_WINLDAP(name);
ldap_memfree(dn);
}
@ -659,8 +657,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
dlsize += attr_len + 3;
if((attr_len > 7) &&
(strcmp(";binary", attr + (attr_len - 7)) == 0)) {
/* Binary attribute, encode to base64. */
@ -689,8 +685,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
dlsize += val_b64_sz;
}
}
else {
@ -705,8 +699,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
dlsize += vals[i]->bv_len;
}
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
@ -719,8 +711,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
dlsize++;
}
/* Free memory used to store values */
@ -734,10 +724,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
if(result)
goto quit;
dlsize++;
result = Curl_pgrsSetDownloadCounter(data, dlsize);
if(result)
goto quit;
}
if(ber)

View File

@ -677,7 +677,6 @@ MQTT_SUBACK_COMING:
/* FALLTHROUGH */
case MQTT_PUB_REMAIN: {
/* read rest of packet, but no more. Cap to buffer size */
struct SingleRequest *k = &data->req;
size_t rest = mq->npacket;
if(rest > (size_t)data->set.buffer_size)
rest = (size_t)data->set.buffer_size;
@ -693,13 +692,8 @@ MQTT_SUBACK_COMING:
result = CURLE_PARTIAL_FILE;
goto end;
}
Curl_debug(data, CURLINFO_DATA_IN, (char *)pkt, (size_t)nread);
mq->npacket -= nread;
k->bytecount += nread;
result = Curl_pgrsSetDownloadCounter(data, k->bytecount);
if(result)
goto end;
/* if QoS is set, message contains packet id */

View File

@ -953,18 +953,12 @@ static CURLcode client_write(struct Curl_easy *data,
if(!len && plen && prefix[plen - 1] == ' ')
plen--;
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, plen);
if(!result)
data->req.bytecount += plen;
}
if(!result && value) {
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len);
if(!result)
data->req.bytecount += len;
}
if(!result && suffix) {
result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, slen);
if(!result)
data->req.bytecount += slen;
}
return result;
}

View File

@ -319,12 +319,6 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
*/
CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
{
if(data->set.max_filesize && (size > data->set.max_filesize)) {
failf(data, "Exceeded the maximum allowed file size "
"(%" CURL_FORMAT_CURL_OFF_T ")",
data->set.max_filesize);
return CURLE_FILESIZE_EXCEEDED;
}
data->progress.downloaded = size;
return CURLE_OK;
}

View File

@ -655,7 +655,6 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
* to write it directly as BODY data */
result = Curl_client_write(data, CLIENTWRITE_BODY,
Curl_dyn_ptr(&rtspc->buf), 1);
++data->req.bytecount;
Curl_dyn_free(&rtspc->buf);
if(result)
goto out;

View File

@ -50,6 +50,7 @@
#include "strdup.h"
#include "http2.h"
#include "headers.h"
#include "progress.h"
#include "ws.h"
/* The last 3 #include files should be in this order */
@ -57,6 +58,9 @@
#include "curl_memory.h"
#include "memdebug.h"
static CURLcode do_init_stack(struct Curl_easy *data);
#if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP)
/*
* convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
@ -385,17 +389,17 @@ static CURLcode chop_write(struct Curl_easy *data,
the future to leave the original data alone.
*/
CURLcode Curl_client_write(struct Curl_easy *data,
int type,
char *ptr,
size_t len)
int type, char *buf, size_t blen)
{
CURLcode result;
#if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV)
/* FTP data may need conversion. */
if((type & CLIENTWRITE_BODY) &&
(data->conn->handler->protocol & PROTO_FAMILY_FTP) &&
data->conn->proto.ftpc.transfertype == 'A') {
/* convert end-of-line markers */
len = convert_lineends(data, ptr, len);
blen = convert_lineends(data, buf, blen);
}
#endif
/* it is one of those, at least */
@ -405,14 +409,14 @@ CURLcode Curl_client_write(struct Curl_easy *data,
/* 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);
if(!data->req.writer_stack) {
result = do_init_stack(data);
if(result)
return result;
DEBUGASSERT(data->req.writer_stack);
}
return chop_write(data, type, FALSE, ptr, len);
return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
}
CURLcode Curl_client_unpause(struct Curl_easy *data)
@ -449,12 +453,12 @@ CURLcode Curl_client_unpause(struct Curl_easy *data)
void Curl_client_cleanup(struct Curl_easy *data)
{
struct contenc_writer *writer = data->req.writer_stack;
struct Curl_cwriter *writer = data->req.writer_stack;
size_t i;
while(writer) {
data->req.writer_stack = writer->downstream;
writer->handler->close_writer(data, writer);
data->req.writer_stack = writer->next;
writer->cwt->do_close(data, writer);
free(writer);
writer = data->req.writer_stack;
}
@ -466,58 +470,152 @@ void Curl_client_cleanup(struct Curl_easy *data)
}
/* Real client writer: no downstream. */
static CURLcode client_cew_init(struct Curl_easy *data,
struct contenc_writer *writer)
/* Write data using an unencoding writer stack. "nbytes" is not
allowed to be 0. */
CURLcode Curl_cwriter_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
(void) data;
if(!nbytes)
return CURLE_OK;
if(!writer)
return CURLE_WRITE_ERROR;
return writer->cwt->do_write(data, writer, type, buf, nbytes);
}
CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
struct Curl_cwriter *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)
CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
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);
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
}
static void client_cew_close(struct Curl_easy *data,
struct contenc_writer *writer)
void Curl_cwriter_def_close(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
(void) data;
(void) writer;
}
static const struct content_encoding client_cew = {
/* Real client writer to installed callbacks. */
static CURLcode cw_client_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
(void)writer;
if(!nbytes)
return CURLE_OK;
return chop_write(data, type, FALSE, (char *)buf, nbytes);
}
static const struct Curl_cwtype cw_client = {
"client",
NULL,
Curl_cwriter_def_init,
cw_client_write,
Curl_cwriter_def_close,
sizeof(struct Curl_cwriter)
};
/* Download client writer in phase CURL_CW_PROTOCOL that
* sees the "real" download body data. */
static CURLcode cw_download_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
CURLcode result;
size_t nwrite;
if(!(type & CLIENTWRITE_BODY)) {
if((type & CLIENTWRITE_CONNECT) && data->set.suppress_connect_headers)
return CURLE_OK;
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
}
nwrite = nbytes;
data->req.bytecount += nbytes;
++data->req.bodywrites;
/* Enforce `max_filesize` also for downloads where we ignore the body.
* Also, write body data up to the max size. This ensures that we
* always produce the same result, even when buffers vary due to
* connection timings. test457 fails in CI randomly otherwise. */
if(data->set.max_filesize &&
(data->req.bytecount > data->set.max_filesize)) {
curl_off_t nexcess;
failf(data, "Exceeded the maximum allowed file size "
"(%" CURL_FORMAT_CURL_OFF_T ")",
data->set.max_filesize);
nexcess = data->req.bytecount - data->set.max_filesize;
nwrite = (nexcess >= (curl_off_t)nbytes)? 0 : (nbytes - (size_t)nexcess);
}
if(!data->req.ignorebody && nwrite) {
result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
if(result)
return result;
}
result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
if(result)
return result;
return (nwrite == nbytes)? CURLE_OK : CURLE_FILESIZE_EXCEEDED;
}
static const struct Curl_cwtype cw_download = {
"download",
NULL,
client_cew_init,
client_cew_write,
client_cew_close,
sizeof(struct contenc_writer)
Curl_cwriter_def_init,
cw_download_write,
Curl_cwriter_def_close,
sizeof(struct Curl_cwriter)
};
/* RAW client writer in phase CURL_CW_RAW that
* enabled tracing of raw data. */
static CURLcode cw_raw_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
if(type & CLIENTWRITE_BODY && data->set.verbose && !data->req.ignorebody) {
Curl_debug(data, CURLINFO_DATA_IN, (char *)buf, nbytes);
}
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
}
static const struct Curl_cwtype cw_raw = {
"raw",
NULL,
Curl_cwriter_def_init,
cw_raw_write,
Curl_cwriter_def_close,
sizeof(struct Curl_cwriter)
};
/* Create an unencoding writer stage using the given handler. */
CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
struct Curl_easy *data,
const struct content_encoding *ce_handler,
int order)
const struct Curl_cwtype *cwt,
Curl_cwriter_phase phase)
{
struct contenc_writer *writer;
struct Curl_cwriter *writer;
CURLcode result = CURLE_OUT_OF_MEMORY;
DEBUGASSERT(ce_handler->writersize >= sizeof(struct contenc_writer));
writer = (struct contenc_writer *) calloc(1, ce_handler->writersize);
DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
writer = (struct Curl_cwriter *) calloc(1, cwt->cwriter_size);
if(!writer)
goto out;
writer->handler = ce_handler;
writer->order = order;
result = ce_handler->init_writer(data, writer);
writer->cwt = cwt;
writer->phase = phase;
result = cwt->do_init(data, writer);
out:
*pwriter = result? NULL : writer;
@ -526,55 +624,74 @@ out:
return result;
}
void Curl_client_free_writer(struct Curl_easy *data,
struct contenc_writer *writer)
void Curl_cwriter_free(struct Curl_easy *data,
struct Curl_cwriter *writer)
{
if(writer) {
writer->handler->close_writer(data, writer);
writer->cwt->do_close(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)
size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
{
DEBUGASSERT(!data->req.writer_stack);
return Curl_client_create_writer(&data->req.writer_stack,
data, &client_cew, 0);
struct Curl_cwriter *w;
size_t n = 0;
for(w = data->req.writer_stack; w; w = w->next) {
if(w->phase == phase)
++n;
}
return n;
}
CURLcode Curl_client_add_writer(struct Curl_easy *data,
struct contenc_writer *writer)
static CURLcode do_init_stack(struct Curl_easy *data)
{
struct Curl_cwriter *writer;
CURLcode result;
if(!data->req.writer_stack) {
result = init_writer_stack(data);
DEBUGASSERT(!data->req.writer_stack);
result = Curl_cwriter_create(&data->req.writer_stack,
data, &cw_client, CURL_CW_CLIENT);
if(result)
return result;
result = Curl_cwriter_create(&writer, data, &cw_download, CURL_CW_PROTOCOL);
if(result)
return result;
result = Curl_cwriter_add(data, writer);
if(result) {
Curl_cwriter_free(data, writer);
}
result = Curl_cwriter_create(&writer, data, &cw_raw, CURL_CW_RAW);
if(result)
return result;
result = Curl_cwriter_add(data, writer);
if(result) {
Curl_cwriter_free(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;
if(!*anchor) {
result = do_init_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;
}
/* 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;
return CURLE_OK;
}

View File

@ -50,43 +50,122 @@
#define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */
#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */
/**
* Write `len` bytes at `prt` to the client. `type` indicates what
* kind of data is being written.
*/
CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
size_t len) WARN_UNUSED_RESULT;
/**
* For a paused transfer, there might be buffered data held back.
* Attempt to flush this data to the client. This *may* trigger
* another pause of the transfer.
*/
CURLcode Curl_client_unpause(struct Curl_easy *data);
/**
* Free all resources related to client writing.
*/
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. */
/**
* Client Writers - a chain passing transfer BODY data to the client.
* Main application: HTTP and related protocols
* Other uses: monitoring of download progress
*
* Writers in the chain are order by their `phase`. First come all
* writers in CURL_CW_RAW, followed by any in CURL_CW_TRANSFER_DECODE,
* followed by any in CURL_CW_PROTOCOL, etc.
*
* When adding a writer, it is inserted as first in its phase. This means
* the order of adding writers of the same phase matters, but writers for
* different phases may be added in any order.
*
* Writers which do modify the BODY data written are expected to be of
* phases TRANSFER_DECODE or CONTENT_DECODE. The other phases are intended
* for monitoring writers. Which do *not* modify the data but gather
* statistics or update progress reporting.
*/
/* Phase a writer operates at. */
typedef enum {
CURL_CW_RAW, /* raw data written, before any decoding */
CURL_CW_TRANSFER_DECODE, /* remove transfer-encodings */
CURL_CW_PROTOCOL, /* after transfer, but before content decoding */
CURL_CW_CONTENT_DECODE, /* remove content-encodings */
CURL_CW_CLIENT /* data written to client */
} Curl_cwriter_phase;
/* Client Writer Type, provides the implementation */
struct Curl_cwtype {
const char *name; /* writer name. */
const char *alias; /* writer name alias, maybe NULL. */
CURLcode (*do_init)(struct Curl_easy *data,
struct Curl_cwriter *writer);
CURLcode (*do_write)(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes);
void (*do_close)(struct Curl_easy *data,
struct Curl_cwriter *writer);
size_t cwriter_size; /* sizeof() allocated struct Curl_cwriter */
};
/* 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;
/* Client writer instance */
struct Curl_cwriter {
const struct Curl_cwtype *cwt; /* type implementation */
struct Curl_cwriter *next; /* Downstream writer. */
Curl_cwriter_phase phase; /* phase at which it operates */
};
/**
* Create a new cwriter instance with given type and phase. Is not
* inserted into the writer chain by this call.
* Invokes `writer->do_init()`.
*/
CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
struct Curl_easy *data,
const struct Curl_cwtype *ce_handler,
Curl_cwriter_phase phase);
CURLcode Curl_client_create_writer(struct contenc_writer **pwriter,
struct Curl_easy *data,
const struct content_encoding *ce_handler,
int order);
/**
* Free a cwriter instance.
* Invokes `writer->do_close()`.
*/
void Curl_cwriter_free(struct Curl_easy *data,
struct Curl_cwriter *writer);
void Curl_client_free_writer(struct Curl_easy *data,
struct contenc_writer *writer);
/**
* Count the number of writers installed of the given phase.
*/
size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase);
CURLcode Curl_client_add_writer(struct Curl_easy *data,
struct contenc_writer *writer);
/**
* Adds a writer to the transfer's writer chain.
* The writers `phase` determines where in the chain it is inserted.
*/
CURLcode Curl_cwriter_add(struct Curl_easy *data,
struct Curl_cwriter *writer);
/**
* Convenience method for calling `writer->do_write()` that
* checks for NULL writer.
*/
CURLcode Curl_cwriter_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes);
/**
* Default implementations for do_init, do_write, do_close that
* do nothing and pass the data through.
*/
CURLcode Curl_cwriter_def_init(struct Curl_easy *data,
struct Curl_cwriter *writer);
CURLcode Curl_cwriter_def_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes);
void Curl_cwriter_def_close(struct Curl_easy *data,
struct Curl_cwriter *writer);
/* internal read-function, does plain socket, SSL and krb4 */

View File

@ -1047,14 +1047,7 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
break;
}
}
data->req.bytecount += len;
data->req.offset += len;
result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
if(result) {
req->result = result;
next_state = SMB_CLOSE;
break;
}
next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD;
break;

View File

@ -1107,7 +1107,6 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct tftp_state_data *state = conn->proto.tftpc;
struct SingleRequest *k = &data->req;
/* Receive the packet */
fromlen = sizeof(fromaddr);
@ -1141,11 +1140,6 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
result = Curl_client_write(data, CLIENTWRITE_BODY,
(char *)state->rpacket.data + 4,
state->rbytes-4);
if(!result) {
k->bytecount += state->rbytes-4;
result = Curl_pgrsSetDownloadCounter(data,
(curl_off_t) k->bytecount);
}
if(result) {
tftp_state_machine(state, TFTP_EVENT_ERROR);
return result;

View File

@ -423,6 +423,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
ssize_t nread; /* number of bytes read */
ssize_t n_to_write;
bool readmore = FALSE; /* used by RTP to signal for more data */
int maxloops = 100;
curl_off_t max_recv = data->set.max_recv_speed?
@ -578,23 +579,6 @@ static CURLcode readwrite_data(struct Curl_easy *data,
} /* this is the first time we write a body part */
#endif /* CURL_DISABLE_HTTP */
k->bodywrites++;
/* pass data to the debug function before it gets "dechunked" */
if(data->set.verbose) {
if(k->badheader) {
Curl_debug(data, CURLINFO_DATA_IN,
Curl_dyn_ptr(&data->state.headerb),
Curl_dyn_len(&data->state.headerb));
if(k->badheader == HEADER_PARTHEADER)
Curl_debug(data, CURLINFO_DATA_IN,
k->str, (size_t)nread);
}
else
Curl_debug(data, CURLINFO_DATA_IN,
k->str, (size_t)nread);
}
#ifndef CURL_DISABLE_HTTP
if(k->chunk) {
/*
@ -634,16 +618,26 @@ static CURLcode readwrite_data(struct Curl_easy *data,
#endif /* CURL_DISABLE_HTTP */
/* Account for body content stored in the header buffer */
n_to_write = nread;
if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) {
size_t headlen = Curl_dyn_len(&data->state.headerb);
DEBUGF(infof(data, "Increasing bytecount by %zu", headlen));
k->bytecount += headlen;
n_to_write += Curl_dyn_len(&data->state.headerb);
}
if((-1 != k->maxdownload) &&
(k->bytecount + nread >= k->maxdownload)) {
(k->bytecount + n_to_write >= k->maxdownload)) {
excess = (size_t)(k->bytecount + n_to_write - k->maxdownload);
if(excess > 0 && !k->ignorebody) {
infof(data,
"Excess found in a read:"
" excess = %zu"
", size = %" CURL_FORMAT_CURL_OFF_T
", maxdownload = %" CURL_FORMAT_CURL_OFF_T
", bytecount = %" CURL_FORMAT_CURL_OFF_T,
excess, k->size, k->maxdownload, k->bytecount);
connclose(conn, "excess found in a read");
}
excess = (size_t)(k->bytecount + nread - k->maxdownload);
nread = (ssize_t) (k->maxdownload - k->bytecount);
if(nread < 0) /* this should be unusual */
nread = 0;
@ -657,17 +651,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,
}
}
k->bytecount += nread;
max_recv -= nread;
result = Curl_pgrsSetDownloadCounter(data, k->bytecount);
if(result)
goto out;
if(!k->chunk && (nread || k->badheader || is_empty_data)) {
/* If this is chunky transfer, it was already written */
if(k->badheader && !k->ignorebody) {
if(k->badheader) {
/* we parsed a piece of data wrongly assuming it was a header
and now we output it as body instead */
size_t headlen = Curl_dyn_len(&data->state.headerb);
@ -691,10 +680,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,
in http_chunks.c.
Make sure that ALL_CONTENT_ENCODINGS contains all the
encodings handled here. */
if(!k->ignorebody && nread) {
if(nread) {
#ifndef CURL_DISABLE_POP3
if(conn->handler->protocol & PROTO_FAMILY_POP3)
result = Curl_pop3_write(data, k->str, nread);
if(conn->handler->protocol & PROTO_FAMILY_POP3) {
result = k->ignorebody? CURLE_OK :
Curl_pop3_write(data, k->str, nread);
}
else
#endif /* CURL_DISABLE_POP3 */
result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,

View File

@ -685,7 +685,7 @@ struct SingleRequest {
enum upgrade101 upgr101; /* 101 upgrade state */
/* Content unencoding stack. See sec 3.5, RFC2616. */
struct contenc_writer *writer_stack;
struct Curl_cwriter *writer_stack;
time_t timeofdoc;
long bodywrites;
char *location; /* This points to an allocated version of the Location:

View File

@ -1466,13 +1466,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_STOP);
break;
}
/* since this counts what we send to the client, we include the
newline in this counter */
data->req.bytecount += sshc->readdir_len + 1;
/* output debug output if that is requested */
Curl_debug(data, CURLINFO_DATA_OUT, (char *)sshc->readdir_filename,
sshc->readdir_len);
}
else {
if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
@ -1564,12 +1558,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_dyn_ptr(&sshc->readdir_buf),
Curl_dyn_len(&sshc->readdir_buf));
if(!result) {
/* output debug output if that is requested */
Curl_debug(data, CURLINFO_DATA_OUT, Curl_dyn_ptr(&sshc->readdir_buf),
Curl_dyn_len(&sshc->readdir_buf));
data->req.bytecount += Curl_dyn_len(&sshc->readdir_buf);
}
ssh_string_free_char(sshc->readdir_tmp);
sshc->readdir_tmp = NULL;

View File

@ -2341,14 +2341,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_STOP);
break;
}
/* since this counts what we send to the client, we include the
newline in this counter */
data->req.bytecount += readdir_len + 1;
/* output debug output if that is requested */
Curl_debug(data, CURLINFO_DATA_IN, sshp->readdir_filename,
readdir_len);
Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1);
}
else {
result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry);
@ -2427,13 +2420,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_dyn_ptr(&sshp->readdir),
Curl_dyn_len(&sshp->readdir));
if(!result) {
/* output debug output if that is requested */
Curl_debug(data, CURLINFO_DATA_IN,
Curl_dyn_ptr(&sshp->readdir),
Curl_dyn_len(&sshp->readdir));
data->req.bytecount += Curl_dyn_len(&sshp->readdir);
}
if(result) {
Curl_dyn_free(&sshp->readdir);
state(data, SSH_STOP);

View File

@ -20,7 +20,8 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
30
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
21;heresatest=moooo
cccccccccccccccccccccccccccccccc
cccccccccccccccccccccccccccccc
c
0
@ -31,7 +32,7 @@ Server: fakeit/0.9 fakeitbad/1.0
Transfer-Encoding: chunked
Connection: mooo
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccccc
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccccccccccc
</datacheck>
</reply>