#include "slist.h"
#include "curlx/dynbuf.h"
+#define MAX_MIME_LEVELS 40 /* avoid deep nesting */
+
#define READ_ERROR ((size_t)-1)
#define STOP_FILLING ((size_t)-2)
static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
- void *instream, bool *hasread);
+ void *instream, bool *hasread,
+ size_t call_depth);
static curl_off_t mime_size(curl_mimepart *part);
/* Quoted-printable character class table.
}
/* Read a non-encoded part content. */
-static size_t read_part_content(curl_mimepart *part,
- char *buffer, size_t bufsize, bool *hasread)
+
+static size_t read_part_content(curl_mimepart *part, char *buffer,
+ size_t bufsize, bool *hasread,
+ size_t call_depth)
{
size_t sz = 0;
+ if(++call_depth > MAX_MIME_LEVELS)
+ return READ_ERROR;
+
switch(part->lastreadstatus) {
case 0:
case CURL_READFUNC_ABORT:
* Cannot be processed as other kinds since read function requires
* an additional parameter and is highly recursive.
*/
- sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread);
+ sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread,
+ call_depth);
break;
case MIMEKIND_FILE:
if(part->fp && feof(part->fp))
/* Read and encode part content. */
static size_t read_encoded_part_content(curl_mimepart *part, char *buffer,
- size_t bufsize, bool *hasread)
+ size_t bufsize, bool *hasread,
+ size_t call_depth)
{
struct mime_encoder_state *st = &part->encstate;
size_t cursize = 0;
size_t sz;
bool ateof = FALSE;
+ if(++call_depth > MAX_MIME_LEVELS)
+ return READ_ERROR;
+
for(;;) {
if(st->bufbeg < st->bufend || ateof) {
/* Encode buffered data. */
if(st->bufend >= sizeof(st->buf))
return cursize ? cursize : READ_ERROR; /* Buffer full. */
sz = read_part_content(part, st->buf + st->bufend,
- sizeof(st->buf) - st->bufend, hasread);
+ sizeof(st->buf) - st->bufend, hasread, call_depth);
switch(sz) {
case 0:
ateof = TRUE;
/* Readback a mime part. */
static size_t readback_part(curl_mimepart *part,
- char *buffer, size_t bufsize, bool *hasread)
+ char *buffer, size_t bufsize, bool *hasread,
+ size_t call_depth)
{
size_t cursize = 0;
- /* Readback from part. */
+ if(++call_depth > MAX_MIME_LEVELS)
+ return READ_ERROR;
+ /* Readback from part. */
while(bufsize) {
size_t sz = 0;
struct curl_slist *hdr = (struct curl_slist *)part->state.ptr;
break;
case MIMESTATE_CONTENT:
if(part->encoder)
- sz = read_encoded_part_content(part, buffer, bufsize, hasread);
+ sz = read_encoded_part_content(part, buffer, bufsize, hasread,
+ call_depth);
else
- sz = read_part_content(part, buffer, bufsize, hasread);
+ sz = read_part_content(part, buffer, bufsize, hasread, call_depth);
switch(sz) {
case 0:
mimesetstate(&part->state, MIMESTATE_END, NULL);
/* Readback from mime. Warning: not a read callback function. */
static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
- void *instream, bool *hasread)
+ void *instream, bool *hasread,
+ size_t call_depth)
{
curl_mime *mime = (curl_mime *)instream;
size_t cursize = 0;
(void)size; /* Always 1 */
+ if(++call_depth > MAX_MIME_LEVELS)
+ return READ_ERROR;
+
while(nitems) {
size_t sz = 0;
curl_mimepart *part = mime->state.ptr;
mimesetstate(&mime->state, MIMESTATE_END, NULL);
break;
}
- sz = readback_part(part, buffer, nitems, hasread);
+ sz = readback_part(part, buffer, nitems, hasread, call_depth);
switch(sz) {
case CURL_READFUNC_ABORT:
case CURL_READFUNC_PAUSE:
* adding any data and this loops infinitely. */
do {
hasread = FALSE;
- ret = readback_part(part, buffer, nitems, &hasread);
+ ret = readback_part(part, buffer, nitems, &hasread, 0);
/*
* If this is not possible to get some data without calling more than
* one read callback (probably because a content encoder is not able to