#include "stdafx.h" #include "CurlClient.h" #include "CharEncoding.h" #include CCurlClient::CCurlClient(void) { m_bDebug = FALSE; m_headers = NULL; } CCurlClient::~CCurlClient(void) { // 释放curl的全局对象; curl_global_cleanup(); } INT CCurlClient::Initialize() { // 初始化全局调用模式; CURLcode res = ::curl_global_init( CURL_GLOBAL_ALL ); if( CURLE_OK != res ) { fprintf( stderr, "curl_global_init failed: %d \n", res ); return -1; } return 0; } static int OnDebug(CURL *, curl_infotype itype, char * pData, size_t size, void *) { if(itype == CURLINFO_TEXT) { //TRACE("[TEXT]%s\n", pData); //LOG4C((LOG_WARN, "[TEXT]%s\n", pData)); } else if(itype == CURLINFO_HEADER_IN) { //TRACE("[HEADER_IN]%s\n", pData); //LOG4C((LOG_WARN, "[HEADER_IN]%s\n", pData)); } else if(itype == CURLINFO_HEADER_OUT) { //TRACE("[HEADER_OUT]%s\n", pData); //LOG4C((LOG_WARN, "[HEADER_OUT]%s\n", pData)); } else if(itype == CURLINFO_DATA_IN) { //TRACE("[DATA_IN]%s\n", pData); //LOG4C((LOG_WARN, "[DATA_IN]%s\n", pData)); } else if(itype == CURLINFO_DATA_OUT) { //TRACE("[DATA_OUT]%s\n", pData); //LOG4C((LOG_WARN, "[DATA_OUT]%s\n", pData)); } return 0; } size_t CCurlClient::OnWriteData(const void *ptr, size_t size, size_t nmemb, std::string *stream) { if( NULL == stream || NULL == ptr ) return -1; stream->append((char*)ptr, size * nmemb); return nmemb; } int CCurlClient::Post(const std::string & strUrl, const std::string & strPost, std::string & strResponse, long time_out /*= 3*/) { CURLcode res; CURL* curl = curl_easy_init(); if(NULL == curl) { return CURLE_FAILED_INIT; } if(m_bDebug) {// 是否开启调试日志输出; curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } // 设置URL地址; curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); // 设置POST方式; curl_easy_setopt(curl, CURLOPT_POST, 1); // 设置POST参数; curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str()); // 设置回调函数-读取; curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); // 设置回调函数-写入; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); // 设置回调函数-写入的缓存区; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); // 设置(多线程下,只是尽量减少)无签名; curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); // 设置连接超时值(单位毫秒); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30000); // 设置操作超时值(单位毫秒); curl_easy_setopt(curl, CURLOPT_TIMEOUT, time_out); // 设置头; curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers); // 执行POST提交; res = curl_easy_perform(curl); // 释放资源; curl_easy_cleanup(curl); //curl_global_cleanup(); ClearHeaders(); /* free the header list */ return res; } int CCurlClient::Post(IN LPCTSTR lpUrl, IN LPCTSTR lpPost, OUT LPTSTR lpResponse, IN CONST INT& nMaxlen, long time_out /*= 3*/) { if ( lpUrl == NULL || lpPost == NULL ) return CURLE_FAILED_INIT; string strUrl; string strPost; string strResponse; #ifdef UNICODE CharEncoding::UNICODE2ASCII((LPWCH)lpUrl, strUrl); CharEncoding::UNICODE2ASCII((LPWCH)lpPost, strPost); int res = Post(strUrl, strPost, strResponse) ; if ( CURLE_OK == res ) { CharEncoding::ASCII2UNICODE(strResponse.c_str(), (LPWCH)lpResponse, nMaxlen); return CURLE_OK; } return res; #else strUrl = lpUrl; strPost = lpPost; int res = Post(strUrl, strPost, strResponse, time_out) ; if ( CURLE_OK == res ) { sprintf_s(lpResponse, nMaxlen, "%s", strResponse.c_str()); return CURLE_OK; } return res; #endif } int CCurlClient::Post(IN CString& strUrl, IN CString& strPost, OUT CString& strResponse, long time_out /*= 3*/) { if ( strUrl.IsEmpty() || strPost.IsEmpty() ) return CURLE_FAILED_INIT; string url; string post; string response; #ifdef UNICODE CharEncoding::UNICODE2ASCII((LPWCH)strUrl.GetString(), url); CharEncoding::UNICODE2ASCII((LPWCH)strPost.GetString(), post); int res = Post(url, post, response) ; if ( CURLE_OK == res ) { WCHAR* pResult = CharEncoding::ASCII2UNICODE(response.c_str()); if ( pResult ) { strResponse = pResult; delete []pResult; pResult = NULL; return CURLE_OK; } } return res; #else url = strUrl.GetString(); post = strPost.GetString(); int res = Post(url, post, response, time_out) ; if ( CURLE_OK == res ) { strResponse = response.c_str(); return CURLE_OK; } return res; #endif } int CCurlClient::Get(const std::string & strUrl, std::string & strResponse, long time_out /*= 3*/) { CURLcode res; CURL* curl = curl_easy_init(); if(NULL == curl) { return CURLE_FAILED_INIT; } if(m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } // 设置URL地址; curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); // 设置回调函数-读取; curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); // 设置回调函数-写入; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); // 设置回调函数-写入的缓存区; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); /** * 当多个线程都使用超时处理的时候,同时主线程中有sleep或是wait等操作。 * 如果不设置这个选项,libcurl将会发信号打断这个wait从而导致程序退出。 */ // 设置(多线程下,只是尽量减少)无签名; curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); // 设置连接超时值; curl_easy_setopt(curl,CURLOPT_CONNECTTIMEOUT,5000); // 设置超时值; curl_easy_setopt(curl,CURLOPT_TIMEOUT, time_out); // 设置头; curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers); res = curl_easy_perform(curl); curl_easy_cleanup(curl); //curl_global_cleanup(); ClearHeaders(); /* free the header list */ return res; } int CCurlClient::Get(IN LPCTSTR lpUrl, OUT LPTSTR lpResponse, IN CONST INT& nMaxlen, long time_out /*= 3*/) { if ( lpUrl == NULL ) return CURLE_FAILED_INIT; string strUrl; string strResponse; #ifdef UNICODE CharEncoding::UNICODE2ASCII((LPWCH)lpUrl, strUrl); int res = Get(strUrl, strResponse) ; if ( CURLE_OK == res ) { CharEncoding::ASCII2UNICODE(strResponse.c_str(), (LPWCH)lpResponse, nMaxlen); return CURLE_OK; } return res; #else strUrl = lpUrl; int res = Get(strUrl, strResponse, time_out) ; if ( CURLE_OK == res ) { sprintf_s(lpResponse, nMaxlen, "%s", strResponse.c_str()); return CURLE_OK; } return res; #endif } int CCurlClient::Get(IN CString& strUrl, OUT CString& strResponse, long time_out /*= 3*/) { if ( strUrl.IsEmpty() ) return CURLE_FAILED_INIT; string url; string post; string response; #ifdef UNICODE CharEncoding::UNICODE2ASCII((LPWCH)strUrl.GetString(), url); int res = Get(url, response) ; if ( CURLE_OK == res ) { WCHAR* pResult = CharEncoding::ASCII2UNICODE(response.c_str()); if ( pResult ) { strResponse = pResult; delete []pResult; pResult = NULL; return CURLE_OK; } } return res; #else url = strUrl.GetString(); int res = Get(url, response, time_out) ; if ( CURLE_OK == res ) { strResponse = response.c_str(); return CURLE_OK; } return res; #endif } CURLcode CCurlClient::Posts(const std::string & strUrl, const std::string & strPost, std::string & strResponse, const char * pCaPath, long time_out /*= 3*/) { CURLcode res; CURL* curl = curl_easy_init(); if(NULL == curl) { return CURLE_FAILED_INIT; } if(m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } // 设置URL地址; curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); // 设置POST提交方式; curl_easy_setopt(curl, CURLOPT_POST, 1); // 设置POST参数; curl_easy_setopt(curl, CURLOPT_POSTFIELDS, strPost.c_str()); // 设置回调函数-读取; curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); // 设置回调函数-写入; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); // 设置回调函数-写入的缓存区; curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); // 设置; curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); if(NULL == pCaPath || pCaPath[0] == '\0') { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); } else { //缺省情况就是PEM,所以无需设置,另外支持DER //curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM"); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath); } // 设置连接超时值; curl_easy_setopt(curl,CURLOPT_CONNECTTIMEOUT,5000); // 设置超时值; curl_easy_setopt(curl,CURLOPT_TIMEOUT, time_out); // 设置头; curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers); // 执行POST提交; res = curl_easy_perform(curl); // 释放资源; curl_easy_cleanup(curl); //curl_global_cleanup(); ClearHeaders(); /* free the header list */ return res; } int CCurlClient::Posts(IN LPCTSTR lpUrl, IN LPCTSTR lpPost, OUT LPTSTR lpResponse, IN CONST INT& nMaxlen, IN LPCTSTR lpCaPath /* = NULL */, long time_out /*= 3*/) { if ( lpUrl == NULL || lpPost == NULL ) return CURLE_FAILED_INIT; string strUrl; string strPost; string strCapath; string strResponse; #ifdef UNICODE CharEncoding::UNICODE2ASCII((LPWCH)lpUrl, strUrl); CharEncoding::UNICODE2ASCII((LPWCH)lpPost, strPost); CharEncoding::UNICODE2ASCII((LPWCH)lpCaPath, strCapath); int res = Posts(strUrl, strPost, strResponse, strCapath.c_str()) ; if ( CURLE_OK == res ) { CharEncoding::ASCII2UNICODE(strResponse.c_str(), (LPWCH)lpResponse, nMaxlen); return CURLE_OK; } return res; #else strUrl = lpUrl; strPost = lpPost; strCapath = lpCaPath; int res = Posts(strUrl, strPost, strResponse, strCapath.c_str(), time_out ) ; if ( CURLE_OK == res ) { sprintf_s(lpResponse, nMaxlen, "%s", strResponse.c_str()); return CURLE_OK; } return res; #endif } int CCurlClient::Posts(IN CString& strUrl, IN CString& strPost, OUT CString& strResponse, IN const CString& strCaPath /* = _T("") */, long time_out /*= 3*/) { if ( strUrl.IsEmpty() || strPost.IsEmpty() ) return CURLE_FAILED_INIT; string url; string post; string capth; string response; #ifdef UNICODE CharEncoding::UNICODE2ASCII((LPWCH)strUrl.GetString(), url); CharEncoding::UNICODE2ASCII((LPWCH)strPost.GetString(), post); CharEncoding::UNICODE2ASCII((LPWCH)strCaPath.GetString(), capth); int res = Posts(url, post, response, capth.c_str()) ; if ( CURLE_OK == res ) { WCHAR* pResult = CharEncoding::ASCII2UNICODE(response.c_str()); if ( pResult ) { strResponse = pResult; delete []pResult; pResult = NULL; return CURLE_OK; } } return res; #else url = strUrl.GetString(); post = strPost.GetString(); capth = strCaPath.GetString(); int res = Posts(url, post, response, capth.c_str(), time_out) ; if ( CURLE_OK == res ) { strResponse = response.c_str(); return CURLE_OK; } return res; #endif } int CCurlClient::Gets(const std::string & strUrl, std::string & strResponse, const char * pCaPath, long time_out /*= 3*/) { CURLcode res; CURL* curl = curl_easy_init(); if(NULL == curl) { return CURLE_FAILED_INIT; } if(m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str()); curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&strResponse); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); if(NULL == pCaPath || pCaPath[0] == '\0') { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); } else { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, true); curl_easy_setopt(curl, CURLOPT_CAINFO, pCaPath); } curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5000); curl_easy_setopt(curl, CURLOPT_TIMEOUT, time_out); // 设置头; curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers); res = curl_easy_perform(curl); curl_easy_cleanup(curl); //curl_global_cleanup(); ClearHeaders(); /* free the header list */ return res; } int CCurlClient::Gets(IN LPCTSTR lpUrl, OUT LPTSTR lpResponse, IN CONST INT& nMaxlen, IN LPCTSTR lpCaPath /* = NULL */, long time_out /*= 3*/) { if ( lpUrl == NULL ) return CURLE_FAILED_INIT; string strUrl; string strCapath; string strResponse; #ifdef UNICODE CharEncoding::UNICODE2ASCII((LPWCH)lpUrl, strUrl); CharEncoding::UNICODE2ASCII((LPWCH)lpCaPath, strCapath); int res = Gets(strUrl, strResponse, strCapath.c_str()) ; if ( CURLE_OK == res ) { CharEncoding::ASCII2UNICODE(strResponse.c_str(), (LPWCH)lpResponse, nMaxlen); return CURLE_OK; } return res; #else strUrl = lpUrl; strCapath = lpCaPath; int res = Gets(strUrl, strResponse, strCapath.c_str(), time_out) ; if ( CURLE_OK == res ) { sprintf_s(lpResponse, nMaxlen, "%s", strResponse.c_str()); return CURLE_OK; } return res; #endif } int CCurlClient::Gets(IN CString& strUrl, OUT CString& strResponse, IN const CString& strCaPath /* = _T("") */, long time_out /*= 3*/) { if ( strUrl.IsEmpty() ) return CURLE_FAILED_INIT; string url; string post; string capth; string response; #ifdef UNICODE CharEncoding::UNICODE2ASCII((LPWCH)strUrl.GetString(), url); CharEncoding::UNICODE2ASCII((LPWCH)strCaPath.GetString(), capth); int res = Gets(url, response, capth.c_str()) ; if ( CURLE_OK == res ) { WCHAR* pResult = CharEncoding::ASCII2UNICODE(response.c_str()); if ( pResult ) { strResponse = pResult; delete []pResult; pResult = NULL; return CURLE_OK; } } return res; #else url = strUrl.GetString(); capth = strCaPath.GetString(); int res = Gets(url, response, capth.c_str(), time_out) ; if ( CURLE_OK == res ) { strResponse = response.c_str(); return CURLE_OK; } return res; #endif } void CCurlClient::SetDebug(bool bDebug) { m_bDebug = bDebug; } void CCurlClient::SetHeaders(const std::string headers) { m_headers = curl_slist_append(m_headers, headers.c_str()); } // 参考:https://blog.csdn.net/lengyuezuixue/article/details/81987695 bool CCurlClient::DownloadEx(const std::string& url, const std::string& path, long time_out /* = 3000 */) { FILE* pf = NULL; curl_off_t local_file_len = -1; long file_size = 0; CURLcode res = CURLE_GOT_NOTHING; int c = 0; struct stat file_info; int use_resume = 0; // 获取本地文件大小; if (stat(path.c_str(), &file_info) == 0) { local_file_len = file_info.st_size; use_resume = 1; } // 采用追加方式打开文件,便于实现断点续传; int nErr = _tfopen_s(&pf, path.c_str(), "ab+"); if (pf) { CURL* curl = curl_easy_init(); if (NULL == curl) { //return CURLE_FAILED_INIT; return false; } curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, time_out); // 设置http头部处理函数; curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, OnGetContentLength); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &file_size); if (url.find("https://") != std::string::npos) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); } // 设置文件续传的位置给curl; curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, use_resume ? local_file_len : 0); curl_easy_setopt(curl, CURLOPT_WRITEDATA, pf); //curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);//设置重定位URL,使用自动跳转,返回的头部中有Location(一般直接请求的url没找到),则继续请求Location对应的数据 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteFile); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); res = curl_easy_perform(curl); fclose(pf); curl_easy_cleanup(curl); if (res == CURLE_OK) return true; } return false; } size_t CCurlClient::OnGetContentLength(void* ptr, size_t size, size_t nmemb, void* stream) { int r; long len = 0; /* _snscanf() is Win32 specific */ // r = _snscanf(ptr, size * nmemb, "Content-Length: %ld\n", &len); r = sscanf_s((char*)ptr, "Content-Length: %ld\n", &len); if (r) /* Microsoft: we don't read the specs */ *((long*)stream) = len; return size * nmemb; } size_t CCurlClient::OnWriteFile(const void* ptr, size_t size, size_t nmemb, void* stream) { if (NULL == stream || NULL == ptr) return -1; return fwrite(ptr, size, nmemb, (FILE*)stream); } int CCurlClient::FormPosts(std::string url, std::multimap form_data, std::string& result, long time_out) { CURLcode res; CURL* curl = curl_easy_init(); if (NULL == curl) { return CURLE_FAILED_INIT; } if (m_bDebug) { curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, OnDebug); } // 表单参数; std::string post; CURLFORMcode rmcode; struct curl_httppost* formpost = NULL; struct curl_httppost* lastptr = NULL; std::multimap::iterator it = form_data.begin(); #if 0 for (; it != form_data.end(); ) { post.append(it->first); post.append("="); post.append(it->second); if (++it != form_data.end()) post.append("&"); else break; } // 设置POST参数; curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post.c_str()); // 设置POST提交方式; res = curl_easy_setopt(curl, CURLOPT_POST, 1); #else for (; it != form_data.end(); it++) { rmcode = curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, it->first.c_str(), CURLFORM_COPYCONTENTS, it->second.c_str(), CURLFORM_END); } // 设置表单参数 res = curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); // 设置表头,表头内容可能不同 //m_headers = curl_slist_append(m_headers, "Content-Type:multipart/form-data"); //m_headers = curl_slist_append(m_headers, "Expect:"); //m_headers = curl_slist_append(m_headers, "Accept-Encoding:gzip, deflate");//Accept-Encodeing冒号后面加东西就上传失败; //curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers); #endif // 设置URL地址; res = curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // 设置回调函数-读取; res = curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL); // 设置回调函数-写入; res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, OnWriteData); // 设置回调函数-写入的缓存区; res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&result); // 设置; res = curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1); // 以下3个为重定向设置 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //返回的头部中有Location(一般直接请求的url没找到),则继续请求Location对应的数据 curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 1);//查找次数,防止查找太深 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);//连接超时,这个数值如果设置太短可能导致数据请求不到就断开了 // 设置超时值; res = curl_easy_setopt(curl, CURLOPT_TIMEOUT, time_out); // 设置头; res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, m_headers); // 执行POST提交; res = curl_easy_perform(curl); // 释放资源; curl_easy_cleanup(curl); //curl_global_cleanup(); ClearHeaders(); /* free the header list */ // 释放表单 curl_formfree(formpost); return res; }