summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPatrick Monnerat <patrick@monnerat.net>2020-01-21 01:33:04 +0100
committerDaniel Stenberg <daniel@haxx.se>2020-03-02 00:00:50 +0100
commit87869e38d7afdec3ef1bb4965711458b088e254f (patch)
tree7da06feb40bf6ee89024a52f7f6a54fb33d44e8c /lib
parentcf1466bd473e06812dce0c3880f7e4af169e9e72 (diff)
downloadcurl-87869e38d7afdec3ef1bb4965711458b088e254f.tar.gz
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 Closes #4833
Diffstat (limited to 'lib')
-rw-r--r--lib/easy.c8
-rw-r--r--lib/formdata.c14
-rw-r--r--lib/mime.c41
-rw-r--r--lib/mime.h5
4 files changed, 58 insertions, 10 deletions
diff --git a/lib/easy.c b/lib/easy.c
index 1a6912748..85a882a97 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -983,6 +983,14 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
+ /* 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 429d479da..6103959cd 100644
--- a/lib/formdata.c
+++ b/lib/formdata.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -730,11 +730,15 @@ int curl_formget(struct curl_httppost *form, void *arg,
switch(nread) {
default:
- if(append(arg, buffer, nread) != nread)
- result = CURLE_READ_ERROR;
- break;
+ if(append(arg, buffer, nread) == nread)
+ break;
+ /* FALLTHROUGH */
case CURL_READFUNC_ABORT:
- case CURL_READFUNC_PAUSE:
+ result = CURLE_ABORTED_BY_CALLBACK;
+ break;
+ case (size_t) -1: /* Read error. */
+ case CURL_READFUNC_PAUSE: /* Should not be paused. */
+ result = CURLE_READ_ERROR;
break;
}
}
diff --git a/lib/mime.c b/lib/mime.c
index 081e51e50..5f928a171 100644
--- a/lib/mime.c
+++ b/lib/mime.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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 3241fdc1f..c6d374ec1 100644
--- a/lib/mime.h
+++ b/lib/mime.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -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