c++ libcurl 发送 https post 请求相关问题

2019-10-10 14:51:15 +08:00
 razrlele

发送请求代码是

size_t WriteBack( void *ptr, size_t size, size_t nmemb, void *stream ) {
    size_t realsize = size * nmemb;
    string *buffer = (string*)stream;
    buffer->append((const char *)ptr, realsize);

    return realsize;
}

bool ProfileOperator::CurlPost(const string &url, const string &postdata, string &res_buffer)
{
  CURL *curl;
  CURLcode code;
  curl = curl_easy_init();
  if (curl){
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteBack);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&res_buffer);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    LOG(DEBUG) << curl_version();
    LOG(DEBUG) << "ready to send req, url: " << url << " postdata: " << postdata;
    code = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
    if( code != CURLE_OK){
      LOG(WARNING) << "post req failed, res_buffer:" << res_buffer << " err:" << curl_easy_strerror(code);
      return false;
    }
  } else {
    return false;
  }
  return true;
}

然后在执行到 curl_easy_cleanup(curl) 函数的时候会栈溢出,gdb 信息如下

Program terminated with signal 11, Segmentation fault.
#0  0x000000330f523e44 in X509_certificate_type () from /usr/lib64/libcrypto.so.10
Missing separate debuginfos, use: debuginfo-install addops-zookeeper-client-3.4.5-1.el6.x86_64 boost153-system-1.53.0-8.el6.x86_64 boost153-thread-1.53.0-8.el6.x86_64 glibc-2.12-1.132.el6_5.2.x86_64 keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64 libcom_err-1.41.12-24.el6.x86_64 libqlog-2.1.14-1.el6.x86
_64 libselinux-2.0.94-7.el6.x86_64 nspr-4.8.8-3.el6.x86_64 nss-3.12.10-16.el6.x86_64 nss-softokn-freebl-3.14.3-10.el6_5.x86_64 nss-util-3.12.10-2.el6.x86_64 openldap-2.4.23-20.el6.x86_64 openssl-1.0.1e-57.el6.x86_64 snappy-1.0.5-1.el6.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0  0x000000330f523e44 in X509_certificate_type () from /usr/lib64/libcrypto.so.10
#1  0x0000003310822c3b in ssl3_check_cert_and_algorithm () from /usr/lib64/libssl.so.10
#2  0x0000003310827951 in ssl3_connect () from /usr/lib64/libssl.so.10
#3  0x0000003310830e07 in ssl23_connect () from /usr/lib64/libssl.so.10

如果我注释掉的两行 SSL 相关配置,程序就不会栈溢出,但是发送请求的时候会报错Problem with the SSL CA cert (path? access rights?)

size_t WriteBack( void *ptr, size_t size, size_t nmemb, void *stream ) {
    size_t realsize = size * nmemb;
    string *buffer = (string*)stream;
    buffer->append((const char *)ptr, realsize);

    return realsize;
}

bool ProfileOperator::CurlPost(const string &url, const string &postdata, string &res_buffer)
{
  CURL *curl;
  CURLcode code;
  curl = curl_easy_init();
  if (curl){
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
    //curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    //curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteBack);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&res_buffer);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    LOG(DEBUG) << curl_version();
    LOG(DEBUG) << "ready to send req, url: " << url << " postdata: " << postdata;
    code = curl_easy_perform(curl);
    curl_easy_cleanup(curl);
    if( code != CURLE_OK){
      LOG(WARNING) << "post req failed, res_buffer:" << res_buffer << " err:" << curl_easy_strerror(code);
      return false;
    }
  } else {
    return false;
  }
  return true;
}

我在 shell 里面直接执行的 curl 命令给 https 网站发送请求没问题,所以本机上的证书应该也是没有问题的,默认用的是

/etc/pki/tls/certs/ca-bundle.cr

shell 里面的 curl 版本是

curl 7.37.0 (x86_64-unknown-linux-gnu) libcurl/7.25.0 OpenSSL/1.0.0 zlib/1.2.3 c-ares/1.7.0 libidn/1.18 libssh2/1.4.2
Protocols: file ftp ftps http https ldap ldaps scp sftp telnet tftp
Features: AsynchDNS IDN Largefile NTLM NTLM_WB SSL libz TLS-SRP Metalink

libcurl 版本是

libcurl/7.65.1 OpenSSL/1.0.1e-fips zlib/1.2.3

版本虽然不一致但是 libcurl 版本和 openssl 版本都要高一点,应该兼容性更好,求问是哪里还需要配置一下吗?

3340 次点击
所在节点    问与答
4 条回复
Hallelu
2019-10-10 16:31:07 +08:00
libcurl 崩溃的问题之前遇到过,也是搞的头疼
libcurl 本身是线程安全的,但 openssl 不是。
设置一下禁止 libcurl 访问超市抛出的超时信号 curl_setopt(curl, CURLOPT_NOSIGNAL,1L);
还有 init 的时候,最好在主线程调用全局初始化 curl_global_init(CURL_GLOBAL_ALL);
在为 openssl 创建两个回调函数,楼主可以试试。
razrlele
2019-10-11 15:19:09 +08:00
@Hallelu 尝试了 curl_easy_setopt(curl, CURLOPT_NOSIGNAL,1L)和 curl_global_init(CURL_GLOBAL_ALL),还是不可以,为 openssl 创建两个回调函数是要自己去实现证书验证吗?
Hallelu
2019-10-11 20:11:32 +08:00
@razrlele 不是证书验证,两个回调函数是加锁和释放锁
razrlele
2019-10-11 21:24:07 +08:00
@Hallelu 可是我就算只起了一个线程还是崩溃。。。问题好像并不在线程不安全。。。

囧,已经放弃走 https 了,发现请求的那个接口走 http 也可以。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/607893

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX