diff options
Diffstat (limited to 'libs/libcurl/src/mime.c')
-rw-r--r-- | libs/libcurl/src/mime.c | 111 |
1 files changed, 77 insertions, 34 deletions
diff --git a/libs/libcurl/src/mime.c b/libs/libcurl/src/mime.c index a07449888d..35200a059b 100644 --- a/libs/libcurl/src/mime.c +++ b/libs/libcurl/src/mime.c @@ -29,10 +29,11 @@ struct Curl_easy;
#include "mime.h"
-#include "warnless.h"
+#include "curlx/warnless.h"
#include "urldata.h"
#include "sendf.h"
#include "strdup.h"
+#include "curlx/base64.h"
#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \
!defined(CURL_DISABLE_SMTP) || \
@@ -45,7 +46,7 @@ struct Curl_easy; #include "rand.h"
#include "slist.h"
#include "strcase.h"
-#include "dynbuf.h"
+#include "curlx/dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -87,10 +88,6 @@ static const struct mime_encoder encoders[] = { {ZERO_NULL, ZERO_NULL, ZERO_NULL}
};
-/* Base64 encoding table */
-static const char base64enc[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
/* Quoted-printable character class table.
*
* We cannot rely on ctype functions since quoted-printable input data
@@ -318,19 +315,19 @@ static char *escape_string(struct Curl_easy *data, if(strategy == MIMESTRATEGY_MAIL || (data && (data->set.mime_formescape)))
table = mimetable;
- Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
+ curlx_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
- for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
+ for(result = curlx_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
for(p = table; *p && **p != *src; p++)
;
if(*p)
- result = Curl_dyn_add(&db, *p + 1);
+ result = curlx_dyn_add(&db, *p + 1);
else
- result = Curl_dyn_addn(&db, src, 1);
+ result = curlx_dyn_addn(&db, src, 1);
}
- return Curl_dyn_ptr(&db);
+ return curlx_dyn_ptr(&db);
}
/* Check if header matches. */
@@ -472,10 +469,10 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, i = st->buf[st->bufbeg++] & 0xFF;
i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
- *ptr++ = base64enc[(i >> 18) & 0x3F];
- *ptr++ = base64enc[(i >> 12) & 0x3F];
- *ptr++ = base64enc[(i >> 6) & 0x3F];
- *ptr++ = base64enc[i & 0x3F];
+ *ptr++ = Curl_base64encdec[(i >> 18) & 0x3F];
+ *ptr++ = Curl_base64encdec[(i >> 12) & 0x3F];
+ *ptr++ = Curl_base64encdec[(i >> 6) & 0x3F];
+ *ptr++ = Curl_base64encdec[i & 0x3F];
cursize += 4;
st->pos += 4;
size -= 4;
@@ -499,10 +496,10 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof, i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
i |= (st->buf[st->bufbeg] & 0xFF) << 16;
- ptr[0] = base64enc[(i >> 18) & 0x3F];
- ptr[1] = base64enc[(i >> 12) & 0x3F];
+ ptr[0] = Curl_base64encdec[(i >> 18) & 0x3F];
+ ptr[1] = Curl_base64encdec[(i >> 12) & 0x3F];
if(++st->bufbeg != st->bufend) {
- ptr[2] = base64enc[(i >> 6) & 0x3F];
+ ptr[2] = Curl_base64encdec[(i >> 6) & 0x3F];
st->bufbeg++;
}
cursize += 4;
@@ -1561,6 +1558,14 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part, }
}
+ /* If subparts have already been used as a top-level MIMEPOST,
+ they might not be positioned at start. Rewind them now, as
+ a future check while rewinding the parent may cause this
+ content to be skipped. */
+ if(mime_subparts_seek(subparts, (curl_off_t) 0, SEEK_SET) !=
+ CURL_SEEKFUNC_OK)
+ return CURLE_SEND_FAIL_REWIND;
+
subparts->parent = part;
/* Subparts are processed internally: no read callback. */
part->seekfunc = mime_subparts_seek;
@@ -1590,8 +1595,8 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) (void) size; /* Always 1. */
- /* TODO: this loop is broken. If `nitems` is <= 4, some encoders will
- * return STOP_FILLING without adding any data and this loops infinitely. */
+ /* If `nitems` is <= 4, some encoders will return STOP_FILLING without
+ * adding any data and this loops infinitely. */
do {
hasread = FALSE;
ret = readback_part(part, buffer, nitems, &hasread);
@@ -1734,7 +1739,7 @@ const char *Curl_mime_contenttype(const char *filename) const char *nameend = filename + len1;
unsigned int i;
- for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
+ for(i = 0; i < CURL_ARRAYSIZE(ctts); i++) {
size_t len2 = strlen(ctts[i].extension);
if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
@@ -1926,6 +1931,7 @@ struct cr_mime_ctx { curl_off_t total_len;
curl_off_t read_len;
CURLcode error_result;
+ struct bufq tmpbuf;
BIT(seen_eos);
BIT(errored);
};
@@ -1937,9 +1943,18 @@ static CURLcode cr_mime_init(struct Curl_easy *data, (void)data;
ctx->total_len = -1;
ctx->read_len = 0;
+ Curl_bufq_init2(&ctx->tmpbuf, 1024, 1, BUFQ_OPT_NO_SPARES);
return CURLE_OK;
}
+static void cr_mime_close(struct Curl_easy *data,
+ struct Curl_creader *reader)
+{
+ struct cr_mime_ctx *ctx = reader->ctx;
+ (void)data;
+ Curl_bufq_free(&ctx->tmpbuf);
+}
+
/* Real client reader to installed client callbacks. */
static CURLcode cr_mime_read(struct Curl_easy *data,
struct Curl_creader *reader,
@@ -1948,6 +1963,7 @@ static CURLcode cr_mime_read(struct Curl_easy *data, {
struct cr_mime_ctx *ctx = reader->ctx;
size_t nread;
+ char tmp[256];
/* Once we have errored, we will return the same error forever */
@@ -1973,18 +1989,46 @@ static CURLcode cr_mime_read(struct Curl_easy *data, blen = (size_t)remain;
}
- if(blen <= 4) {
- /* TODO: Curl_mime_read() may go into an infinite loop when reading
- * such small lengths. Returning 0 bytes read is a fix that only works
- * as request upload buffers will get flushed eventually and larger
- * reads will happen again. */
- CURL_TRC_READ(data, "cr_mime_read(len=%zu), too small, return", blen);
- *pnread = 0;
- *peos = FALSE;
- goto out;
+ if(!Curl_bufq_is_empty(&ctx->tmpbuf)) {
+ CURLcode result = CURLE_OK;
+ ssize_t n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen,
+ &result);
+ if(n < 0) {
+ ctx->errored = TRUE;
+ ctx->error_result = result;
+ return result;
+ }
+ nread = (size_t)n;
+ }
+ else if(blen <= 4) {
+ /* Curl_mime_read() may go into an infinite loop when reading
+ * via a base64 encoder, as it stalls when the read buffer is too small
+ * to contain a complete 3 byte encoding. Read into a larger buffer
+ * and use that until empty. */
+ CURL_TRC_READ(data, "cr_mime_read(len=%zu), small read, using tmp", blen);
+ nread = Curl_mime_read(tmp, 1, sizeof(tmp), ctx->part);
+ if(nread <= sizeof(tmp)) {
+ CURLcode result = CURLE_OK;
+ ssize_t n = Curl_bufq_write(&ctx->tmpbuf, (unsigned char *)tmp, nread,
+ &result);
+ if(n < 0) {
+ ctx->errored = TRUE;
+ ctx->error_result = result;
+ return result;
+ }
+ /* stored it, read again */
+ n = Curl_bufq_read(&ctx->tmpbuf, (unsigned char *)buf, blen, &result);
+ if(n < 0) {
+ ctx->errored = TRUE;
+ ctx->error_result = result;
+ return result;
+ }
+ nread = (size_t)n;
+ }
}
+ else
+ nread = Curl_mime_read(buf, 1, blen, ctx->part);
- nread = Curl_mime_read(buf, 1, blen, ctx->part);
CURL_TRC_READ(data, "cr_mime_read(len=%zu), mime_read() -> %zd",
blen, nread);
@@ -2044,7 +2088,6 @@ static CURLcode cr_mime_read(struct Curl_easy *data, break;
}
-out:
CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T
", read=%"FMT_OFF_T") -> %d, %zu, %d",
blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos);
@@ -2133,14 +2176,14 @@ static bool cr_mime_is_paused(struct Curl_easy *data, {
struct cr_mime_ctx *ctx = reader->ctx;
(void)data;
- return (ctx->part && ctx->part->lastreadstatus == CURL_READFUNC_PAUSE);
+ return ctx->part && ctx->part->lastreadstatus == CURL_READFUNC_PAUSE;
}
static const struct Curl_crtype cr_mime = {
"cr-mime",
cr_mime_init,
cr_mime_read,
- Curl_creader_def_close,
+ cr_mime_close,
cr_mime_needs_rewind,
cr_mime_total_length,
cr_mime_resume_from,
|