HTTPClient.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /*
  2. * @file HTTPClient.h
  3. * @brief libcurl wrapper for HTTP requests
  4. *
  5. * @author Mohamed Amine Mzoughi <mohamed-amine.mzoughi@laposte.net>
  6. * @date 2017-01-04
  7. */
  8. #pragma once
  9. #ifndef INCLUDE_HTTPCLIENT_H_
  10. #define INCLUDE_HTTPCLIENT_H_
  11. #include "IHttpFunc.h"
  12. #define CLIENT_USERAGENT "httpclientcpp-agent/1.0"
  13. #include <algorithm>
  14. #include <cstddef> // std::size_t
  15. #include <cstdio> // snprintf
  16. #include <cstdlib>
  17. #include <cstring> // strerror, strlen, memcpy, strcpy
  18. #include <ctime>
  19. #include <curl/curl.h>
  20. #include <fstream>
  21. #include <functional>
  22. #include <iostream>
  23. #include <memory> // std::unique_ptr
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <sstream>
  27. #include <stdarg.h> // va_start, etc.
  28. #include <string>
  29. #include <sys/stat.h>
  30. #include <sys/types.h>
  31. #include <unordered_map>
  32. #include <vector>
  33. #if defined(_MSC_VER)
  34. #include <WinSock2.h>
  35. #include <Windows.h>
  36. #endif //_MSC_VER
  37. //typedef std::function<void(const std::string&)> LogFnCallback;
  38. class CHTTPClient : public IHttpFunc
  39. {
  40. public:
  41. // Public definitions
  42. typedef int (*ProgressFnCallback)(void*, double, double, double, double);
  43. typedef std::unordered_map<std::string, std::string> HeadersMap;
  44. typedef std::vector<char> ByteBuffer;
  45. /* This struct represents the form information to send on POST Form requests */
  46. struct PostFormInfo
  47. {
  48. PostFormInfo();
  49. ~PostFormInfo();
  50. /* Fill in the file upload field */
  51. void AddFormFile(const std::string& fieldName, const std::string& fieldValue);
  52. /* Fill in the filename or the submit field */
  53. void AddFormContent(const std::string& fieldName, const std::string& fieldValue);
  54. struct curl_httppost* m_pFormPost;
  55. struct curl_httppost* m_pLastFormptr;
  56. };
  57. // Progress Function Data Object - parameter void* of ProgressFnCallback references it
  58. struct ProgressFnStruct
  59. {
  60. ProgressFnStruct() : dLastRunTime(0), pCurl(nullptr), pOwner(nullptr) {}
  61. double dLastRunTime;
  62. CURL* pCurl;
  63. /* owner of the CHTTPClient object. can be used in the body of the progress
  64. * function to send signals to the owner (e.g. to update a GUI's progress bar)
  65. */
  66. void* pOwner;
  67. };
  68. // HTTP response data
  69. struct HttpResponse
  70. {
  71. HttpResponse() : iCode(0) {}
  72. int iCode; // HTTP response code
  73. HeadersMap mapHeaders; // HTTP response headers fields
  74. std::string strBody; // HTTP response body
  75. };
  76. /* Please provide your logger thread-safe routine, otherwise, you can turn off
  77. * error log messages printing by not using the flag ALL_FLAGS or ENABLE_LOG */
  78. explicit CHTTPClient(LogFnCallback oLogger);
  79. virtual ~CHTTPClient();
  80. void Destory(){delete this;} //销毁改对象
  81. // Setters - Getters (for unit tests)
  82. /*inline*/ void SetProgressFnCallback(void* pOwner, const ProgressFnCallback& fnCallback);
  83. /*inline*/ void SetProxy(const std::string& strProxy);
  84. inline void SetTimeout(const int& iTimeout) { m_iCurlTimeout = iTimeout; }
  85. inline void SetNoSignal(const bool& bNoSignal) { m_bNoSignal = bNoSignal; }
  86. inline void SetHTTPS(const bool& bEnableHTTPS) { m_bHTTPS = bEnableHTTPS; }
  87. inline ProgressFnCallback GetProgressFnCallback() const
  88. {
  89. return m_fnProgressCallback;
  90. }
  91. inline void* GetProgressFnCallbackOwner() const { return m_ProgressStruct.pOwner; }
  92. inline const std::string& GetProxy() const { return m_strProxy; }
  93. inline const int GetTimeout() const { return m_iCurlTimeout; }
  94. inline const bool GetNoSignal() const { return m_bNoSignal; }
  95. inline const std::string& GetURL() const { return m_strURL; }
  96. inline const unsigned char GetSettingsFlags() const { return m_eSettingsFlags; }
  97. inline const bool GetHTTPS() const { return m_bHTTPS; }
  98. // Session
  99. const bool InitSession(const bool& bHTTPS = false, const SettingsFlag& SettingsFlags = ALL_FLAGS);
  100. virtual const bool CleanupSession();
  101. static int GetCurlSessionCount() { return s_iCurlSession; }
  102. const CURL* GetCurlPointer() const { return m_pCurlSession; }
  103. // HTTP requests
  104. const bool GetText(const std::string& strURL,
  105. std::string& strText,
  106. long& lHTTPStatusCode);
  107. private:
  108. const bool DownloadFile(const std::string& strLocalFile,
  109. const std::string& strURL,
  110. long& lHTTPStatusCode);
  111. const bool UploadForm(const std::string& strURL,
  112. const PostFormInfo& data,
  113. long& lHTTPStatusCode);
  114. public:
  115. inline void AddHeader(const std::string& strHeader)
  116. {
  117. m_pHeaderlist = curl_slist_append(m_pHeaderlist, strHeader.c_str());
  118. }
  119. // REST requests
  120. const bool Head(const std::string& strUrl, const HeadersMap& Headers, HttpResponse& Response);
  121. const bool Get(const std::string& strUrl, const HeadersMap& Headers, HttpResponse& Response);
  122. const bool Del(const std::string& strUrl, const HeadersMap& Headers, HttpResponse& Response);
  123. const bool Post(const std::string& strUrl, const HeadersMap& Headers,
  124. const std::string& strPostData, HttpResponse& Response);
  125. const bool Put(const std::string& strUrl, const HeadersMap& Headers,
  126. const std::string& strPutData, HttpResponse& Response);
  127. const bool Put(const std::string& strUrl, const HeadersMap& Headers,
  128. const ByteBuffer& Data, HttpResponse& Response);
  129. //add by cfq override IHttpFunc
  130. virtual const bool Get(CHTTPReq &req, CHTTPRet &ret, HttpClientTraceLink* pTrace);
  131. virtual const bool Post(CHTTPReq &req, CHTTPRet &ret, HttpClientTraceLink* pTrace);
  132. virtual const bool UploadFileBlock(CHTTPUploadReq &req, CHTTPUploadRet &ret, HttpClientTraceLink* pTrace);
  133. virtual const bool DownloadFileBlock(const char* url, const char* jsonReqStr, fileContentArray& content,
  134. long &httpCode, unordered_map<string, string>& responseHeaders, long timeout, HttpClientTraceLink* pTrace);
  135. private:
  136. // SSL certs
  137. static const std::string& GetCertificateFile() { return s_strCertificationAuthorityFile; }
  138. static void SetCertificateFile(const std::string& strPath) { s_strCertificationAuthorityFile = strPath; }
  139. void SetSSLCertFile(const std::string& strPath) { m_strSSLCertFile = strPath; }
  140. const std::string& GetSSLCertFile() const { return m_strSSLCertFile; }
  141. void SetSSLKeyFile(const std::string& strPath) { m_strSSLKeyFile = strPath; }
  142. const std::string& GetSSLKeyFile() const { return m_strSSLKeyFile; }
  143. void SetSSLKeyPassword(const std::string& strPwd) { m_strSSLKeyPwd = strPwd; }
  144. const std::string& GetSSLKeyPwd() const { return m_strSSLKeyPwd; }
  145. #ifdef DEBUG_CURL
  146. static void SetCurlTraceLogDirectory(const std::string& strPath);
  147. #endif
  148. protected:
  149. // payload to upload on POST requests.
  150. struct UploadObject
  151. {
  152. UploadObject() : pszData(nullptr), usLength(0) {}
  153. const char* pszData; // data to upload
  154. size_t usLength; // length of the data to upload
  155. };
  156. /* common operations are performed here */
  157. inline const CURLcode Perform();
  158. inline void CheckURL(const std::string& strURL);
  159. inline const bool InitRestRequest(const std::string& strUrl, const HeadersMap& Headers,
  160. HttpResponse& Response);
  161. inline const bool PostRestRequest(const CURLcode ePerformCode, HttpResponse& Response);
  162. // Curl callbacks
  163. static size_t WriteInStringCallback(void* ptr, size_t size, size_t nmemb, void* data);
  164. static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, void* data);
  165. static size_t ReadFromFileCallback(void* ptr, size_t size, size_t nmemb, void* stream);
  166. static size_t ThrowAwayCallback(void* ptr, size_t size, size_t nmemb, void* data);
  167. static size_t RestWriteCallback(void* ptr, size_t size, size_t nmemb, void* userdata);
  168. static size_t RestHeaderCallback(void* ptr, size_t size, size_t nmemb, void* userdata);
  169. static size_t RestReadCallback(void* ptr, size_t size, size_t nmemb, void* userdata);
  170. //add by cfq
  171. static size_t HeaderCallback(void* ptr, size_t size, size_t nmemb, void* userdata);
  172. static size_t WriteInByteCallback(void* ptr, size_t size, size_t nmemb, void* userdata);
  173. // String Helpers
  174. static std::string StringFormat(const std::string strFormat, ...);
  175. static inline void TrimSpaces(std::string& str);
  176. // Curl Debug informations
  177. #ifdef DEBUG_CURL
  178. static int DebugCallback(CURL* curl, curl_infotype curl_info_type, char* strace, size_t nSize, void* pFile);
  179. inline void StartCurlDebug() const;
  180. inline void EndCurlDebug() const;
  181. #endif
  182. std::string m_strURL;
  183. std::string m_strProxy;
  184. bool m_bNoSignal;
  185. bool m_bHTTPS;
  186. SettingsFlag m_eSettingsFlags;
  187. struct curl_slist* m_pHeaderlist;
  188. // SSL
  189. static std::string s_strCertificationAuthorityFile;
  190. std::string m_strSSLCertFile;
  191. std::string m_strSSLKeyFile;
  192. std::string m_strSSLKeyPwd;
  193. static HANDLE s_mtxCurlSession; // mutex used to manage API global operations
  194. volatile static int s_iCurlSession; // Count of the actual sessions
  195. CURL* m_pCurlSession;
  196. int m_iCurlTimeout;
  197. // Progress function
  198. ProgressFnCallback m_fnProgressCallback;
  199. ProgressFnStruct m_ProgressStruct;
  200. bool m_bProgressCallbackSet;
  201. // Log printer callback
  202. LogFnCallback m_oLog;
  203. private:
  204. #ifdef DEBUG_CURL
  205. static std::string s_strCurlTraceLogDirectory;
  206. mutable std::ofstream m_ofFileCurlTrace;
  207. #endif
  208. static HANDLE m_hLock;
  209. static BOOL Lock(DWORD dwTime);
  210. static void Unlock();
  211. // copy constructor and assignment operator are disabled
  212. CHTTPClient(const CHTTPClient& Copy);
  213. CHTTPClient& operator=(const CHTTPClient& Copy);
  214. };
  215. ///*TODO(80374374@3/9/2023): 抽出作为公共函数 */
  216. #if defined(_MSC_VER)
  217. char* ConvertUtf8ToGBK(const char* strUtf8)
  218. {
  219. int len = MultiByteToWideChar(CP_UTF8, 0, strUtf8, -1, NULL, 0);
  220. WCHAR* wszGBK = new WCHAR[len + 1];
  221. memset(wszGBK, 0, len * 2 + 2);
  222. MultiByteToWideChar(CP_UTF8, 0, strUtf8, -1, wszGBK, len);
  223. len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
  224. char* szGBK = new char[len + 1];
  225. memset(szGBK, 0, len + 1);
  226. WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
  227. delete[] wszGBK;
  228. return szGBK;
  229. }
  230. void ConvertUtf8ToGBK(std::string& str)
  231. {
  232. char* dst = ConvertUtf8ToGBK(str.c_str());
  233. str = dst;
  234. delete[] dst;
  235. }
  236. char* ConvertGBKToUtf8(const char* gbk, int* n)
  237. {
  238. int len = MultiByteToWideChar(CP_ACP, 0, gbk, -1, NULL, 0);
  239. WCHAR* wszGBK = new WCHAR[len + 1];
  240. memset(wszGBK, 0, len * 2 + 2);
  241. MultiByteToWideChar(CP_ACP, 0, gbk, -1, wszGBK, len);
  242. len = WideCharToMultiByte(CP_UTF8, 0, wszGBK, -1, NULL, 0, NULL, NULL);
  243. char* szUtf8 = new char[len + 1];
  244. memset(szUtf8, 0, len + 1);
  245. WideCharToMultiByte(CP_UTF8, 0, wszGBK, -1, szUtf8, len, NULL, NULL);
  246. delete[] wszGBK;
  247. *n = len - 1;
  248. return szUtf8;
  249. }
  250. void ConvertGBKToUtf8(std::string& str)
  251. {
  252. int len = 0;
  253. char* dst = ConvertGBKToUtf8(str.c_str(), &len);
  254. str = dst;
  255. delete[] dst;
  256. }
  257. #endif //_MSC_VER
  258. RVCCOMM_API IHttpFunc* create_http(LogFnCallback oLogger)
  259. {
  260. return new CHTTPClient(oLogger);
  261. }
  262. // Logs messages
  263. #define LOG_ERROR_EMPTY_HOST_MSG "[HTTPClient][Error] Empty hostname."
  264. #define LOG_WARNING_OBJECT_NOT_CLEANED "[HTTPClient][Warning] Object was freed before calling " \
  265. "CHTTPClient::CleanupSession(). The API session was cleaned though."
  266. #define LOG_ERROR_CURL_ALREADY_INIT_MSG "[HTTPClient][Error] Curl session is already initialized ! " \
  267. "Use CleanupSession() to clean the present one."
  268. #define LOG_ERROR_CURL_NOT_INIT_MSG "[HTTPClient][Error] Curl session is not initialized ! Use InitSession() before."
  269. #define LOG_ERROR_CURL_REQ_FAILURE_FORMAT "[HTTPClient][Error] Unable to perform request from '%s' " \
  270. "(Error = %d | %s) (HTTP_Status = %ld)"
  271. #define LOG_ERROR_CURL_REST_FAILURE_FORMAT "[HTTPClient][Error] Unable to perform a REST request from '%s' " \
  272. "(Error = %d | %s)"
  273. #define LOG_ERROR_CURL_DOWNLOAD_FAILURE_FORMAT "[HTTPClient][Error] Unable to perform a request - '%s' from '%s' " \
  274. "(Error = %d | %s) (HTTP_Status = %ld)"
  275. #define LOG_ERROR_DOWNLOAD_FILE_FORMAT "[HTTPClient][Error] Unable to open local file %s"
  276. #define LOG_ERROR_LOAD_SETTINGS_FAILTURE_MSG "[HTTPClient][Error] unable to open/read Config_CenterSetting"
  277. #define LOG_ERROR_PATH_NULL_MSG "[HTTPClient][Error] url is NULL"
  278. #define LOG_ERROR_GET_JSON_FAILTURE_MSG "[HTTPClient][Error] ToJson method have exception"
  279. #define LOG_ERROR_PARSE_JSON_FAILTURE_MSG "[HTTPClient][Error] ParseJson method have exception"
  280. #define LOG_ERROR_RESPONSE_FORMAT_FAILTURE_MSG "[HTTPClient][Error] Response format is wrong(%s)"
  281. #endif