博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
libcurl smtp发送邮件附件大小限制问题
阅读量:2193 次
发布时间:2019-05-02

本文共 2812 字,大约阅读时间需要 9 分钟。

http://blog.csdn.net/lybingo/article/details/53782780

原文链接:

  • 问题

    最近项目上有自动发送邮件的需求, 便用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;  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

调用处:

static CURLcode readwrite_upload(struct SessionHandle *data,                                 struct connectdata *conn,                                 struct SingleRequest *k,                                 int *didwhat){    ...    result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount);    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

再看看回调函数的实现:

struct WriteThis    {        int pos;        int counter;        std::vector
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 */}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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

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

#define CHUNCK_SIZE 1024 * 10size_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;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 总结, libcurl的设计中, 默认只支持每次读取16k左右大小的buffer(包括读取smtp协议头, 消息体, 附件等), 一旦超过尺寸, 就需要考虑分片
  • 工具源码:

你可能感兴趣的文章
Spring源码剖析2:初探Spring IOC核心流程
查看>>
Spring源码剖析3:Spring IOC容器的加载过程
查看>>
Spring源码剖析4:懒加载的单例Bean获取过程分析
查看>>
Spring源码剖析5:JDK和cglib动态代理原理详解
查看>>
Spring源码剖析6:Spring AOP概述
查看>>
Spring源码剖析7:AOP实现原理详解
查看>>
Spring源码剖析8:Spring事务概述
查看>>
Spring源码剖析9:Spring事务源码剖析
查看>>
重新学习Mysql数据库1:无废话MySQL入门
查看>>
探索Redis设计与实现2:Redis内部数据结构详解——dict
查看>>
探索Redis设计与实现3:Redis内部数据结构详解——sds
查看>>
探索Redis设计与实现4:Redis内部数据结构详解——ziplist
查看>>
探索Redis设计与实现6:Redis内部数据结构详解——skiplist
查看>>
探索Redis设计与实现5:Redis内部数据结构详解——quicklist
查看>>
探索Redis设计与实现8:连接底层与表面的数据结构robj
查看>>
探索Redis设计与实现7:Redis内部数据结构详解——intset
查看>>
探索Redis设计与实现9:数据库redisDb与键过期删除策略
查看>>
探索Redis设计与实现10:Redis的事件驱动模型与命令执行过程
查看>>
分布式系统理论基础1: 一致性、2PC和3PC
查看>>
分布式系统理论基础2 :CAP
查看>>