From 96972ec1c00a142e3859efc82a06b0b810527da2 Mon Sep 17 00:00:00 2001 From: Patrick Monnerat Date: Fri, 6 Mar 2020 09:46:39 +0100 Subject: mime: latch last read callback status. In case a read callback returns a status (pause, abort, eof, error) instead of a byte count, drain the bytes read so far but remember this status for further processing. Takes care of not losing data when pausing, and properly resume a paused mime structure when requested. New tests 670-673 check unpausing cases, with easy or multi interface and mime or form api. Fixes #4813 Reported-by: MrdUkk on github --- lib/easy.c | 8 ++++++++ lib/formdata.c | 12 ++++-------- lib/mime.c | 39 ++++++++++++++++++++++++++++++++++++--- lib/mime.h | 3 +++ 4 files changed, 51 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/easy.c b/lib/easy.c index d3a29f48b..b648e80c1 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -1003,6 +1003,14 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action) return CURLE_OK; } + /* Unpause parts in active mime tree. */ + if((k->keepon & ~newstate & KEEP_SEND_PAUSE) && + (data->mstate == CURLM_STATE_PERFORM || + data->mstate == CURLM_STATE_TOOFAST) && + data->state.fread_func == (curl_read_callback) Curl_mime_read) { + Curl_mime_unpause(data->state.in); + } + /* put it back in the keepon */ k->keepon = newstate; diff --git a/lib/formdata.c b/lib/formdata.c index 50a37e0e7..57ec6ad25 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -728,14 +728,10 @@ int curl_formget(struct curl_httppost *form, void *arg, if(!nread) break; - switch(nread) { - default: - if(append(arg, buffer, nread) != nread) - result = CURLE_READ_ERROR; - break; - case CURL_READFUNC_ABORT: - case CURL_READFUNC_PAUSE: - break; + if(nread > sizeof(buffer) || append(arg, buffer, nread) != nread) { + result = CURLE_READ_ERROR; + if(nread == CURL_READFUNC_ABORT) + result = CURLE_ABORTED_BY_CALLBACK; } } diff --git a/lib/mime.c b/lib/mime.c index 2571287c6..5f928a171 100644 --- a/lib/mime.c +++ b/lib/mime.c @@ -740,9 +740,19 @@ static size_t read_part_content(curl_mimepart *part, { size_t sz = 0; - if(part->readfunc) - sz = part->readfunc(buffer, 1, bufsize, part->arg); - return sz; + switch(part->lastreadstatus) { + case 0: + case CURL_READFUNC_ABORT: + case CURL_READFUNC_PAUSE: + case READ_ERROR: + break; + default: + if(part->readfunc) + sz = part->readfunc(buffer, 1, bufsize, part->arg); + part->lastreadstatus = sz; + break; + } + return part->lastreadstatus; } /* Read and encode part content. */ @@ -1031,6 +1041,7 @@ static int mime_part_rewind(curl_mimepart *part) if(res == CURL_SEEKFUNC_OK) mimesetstate(&part->state, targetstate, NULL); + part->lastreadstatus = 1; /* Successful read status. */ return res; } @@ -1073,6 +1084,7 @@ static void cleanup_part_content(curl_mimepart *part) part->datasize = (curl_off_t) 0; /* No size yet. */ cleanup_encoder_state(&part->encstate); part->kind = MIMEKIND_NONE; + part->lastreadstatus = 1; /* Successful read status. */ } static void mime_subparts_free(void *ptr) @@ -1238,6 +1250,7 @@ void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy) { memset((char *) part, 0, sizeof(*part)); part->easy = easy; + part->lastreadstatus = 1; /* Successful read status. */ mimesetstate(&part->state, MIMESTATE_BEGIN, NULL); } @@ -1805,6 +1818,26 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part, return ret; } +/* Recursively reset paused status in the given part. */ +void Curl_mime_unpause(curl_mimepart *part) +{ + if(part) { + if(part->lastreadstatus == CURL_READFUNC_PAUSE) + part->lastreadstatus = 1; /* Successful read status. */ + if(part->kind == MIMEKIND_MULTIPART) { + curl_mime *mime = (curl_mime *) part->arg; + + if(mime) { + curl_mimepart *subpart; + + for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) + Curl_mime_unpause(subpart); + } + } + } +} + + #else /* !CURL_DISABLE_HTTP || !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */ /* Mime not compiled in: define stubs for externally-referenced functions. */ diff --git a/lib/mime.h b/lib/mime.h index 431212579..c6d374ec1 100644 --- a/lib/mime.h +++ b/lib/mime.h @@ -125,6 +125,7 @@ struct curl_mimepart_s { mime_state state; /* Current readback state. */ const mime_encoder *encoder; /* Content data encoder. */ mime_encoder_state encstate; /* Data encoder state. */ + size_t lastreadstatus; /* Last read callback returned status. */ }; CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...); @@ -147,6 +148,7 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream); CURLcode Curl_mime_rewind(curl_mimepart *part); const char *Curl_mime_contenttype(const char *filename); +void Curl_mime_unpause(curl_mimepart *part); #else /* if disabled */ @@ -158,6 +160,7 @@ const char *Curl_mime_contenttype(const char *filename); #define Curl_mime_size(x) (curl_off_t) -1 #define Curl_mime_read NULL #define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN) +#define Curl_mime_unpause(x) #endif -- cgit v1.2.3