您的位置:首页 > 编程语言 > PHP开发

libcurl smtp发送邮件附件大小限制问题

2016-12-21 11:54 721 查看
原文链接:http://codingfan.cn/index.php/archives/14/

问题

最近项目上有自动发送邮件的需求, 便用libcurl封装了个,发送hello world是ok的, 测试attachment的时候, 发现报错:read function returned funny value, 而且只要body或者attachment超过16k左右就报错

分析过程

翻看libcurl源码找到对应位置:

CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
{
struct SessionHandle *data = conn->data;
size_t buffersize = (size_t)bytes;

...

//fread_func为用户实现的读取buffer的回调函数
nread = (int)data->set.fread_func(data->req.upload_fromhere, 1,
buffersize, data->set.in);
...
else if((size_t)nread > buffersize) {
/* the read function returned a too large value */
*nreadp = 0;
failf(data, "read function returned funny value");
return CURLE_READ_ERROR;
}


调用处:

static CURLcode readwrite_upload(struct SessionHandle *data,
struct connectdata *conn,
struct SingleRequest *k,
int *didwhat)
{
...
result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount);
...
}


可以看出buffersize 即BUFSIZE为固定大小16348, 当满足回调函数返回值大于该数值,就会报错。

再看看回调函数的实现:

struct WriteThis
{
int pos;
int counter;
std::vector<std::string> data;
};

static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
struct WriteThis *pooh = (struct WriteThis *)userp;
const char *data;

if (size*nmemb < 1)
return 0;

data = text[pooh->counter];

if (data)
{
size_t len = strlen(data);
memcpy(ptr, data, len);
pooh->counter++; /* advance pointer */
return len;
}
return 0;                         /* no more data left to deliver */
}


很明显, 数组的任意一项大于该值,就会出错, 也就解释了为什么body或者attachment超出16k就会报错了

既然不支持大文件(不过16k居然能算大文件), 那我们就考虑chunk up分片读, 修改成如下, 解决问题:

#define CHUNCK_SIZE 1024 * 10
size_t CurlSmtp::read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{
struct WriteThis *pooh = (struct WriteThis *)userp;
const char *data;

if(size * nmemb < 1)
return 0;

const std::string& str = pooh->data[pooh->counter];
if(pooh->counter < pooh->data.size()) {
size_t len = str.size();
int size = len - pooh->pos;
if (len < CHUNCK_SIZE || size <= CHUNCK_SIZE)
{
memcpy(ptr, str.c_str() + pooh->pos, size);
pooh->counter++; /* advance pointer */
pooh->pos = 0;
return size;
}
else
{
memcpy(ptr, str.c_str() + pooh->pos, CHUNCK_SIZE);
pooh->pos += CHUNCK_SIZE;
return CHUNCK_SIZE;
}

}
return 0;
}


总结, libcurl的设计中, 默认只支持每次读取16k左右大小的buffer(包括读取smtp协议头, 消息体, 附件等), 一旦超过尺寸, 就需要考虑分片

工具源码:curlsmtp
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: