PageRenderTime 40ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llcurl.h

https://bitbucket.org/lindenlab/viewer-beta/
C Header | 456 lines | 279 code | 100 blank | 77 comment | 3 complexity | c77417dc6e9c9d1858fb092bfbcef16e MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llcurl.h
  3. * @author Zero / Donovan
  4. * @date 2006-10-15
  5. * @brief A wrapper around libcurl.
  6. *
  7. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. #ifndef LL_LLCURL_H
  29. #define LL_LLCURL_H
  30. #include "linden_common.h"
  31. #include <sstream>
  32. #include <string>
  33. #include <vector>
  34. #include <boost/intrusive_ptr.hpp>
  35. #include <curl/curl.h> // TODO: remove dependency
  36. #include "llbuffer.h"
  37. #include "lliopipe.h"
  38. #include "llsd.h"
  39. #include "llthread.h"
  40. #include "llqueuedthread.h"
  41. #include "llframetimer.h"
  42. class LLMutex;
  43. class LLCurlThread;
  44. // For whatever reason, this is not typedef'd in curl.h
  45. typedef size_t (*curl_header_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
  46. class LLCurl
  47. {
  48. LOG_CLASS(LLCurl);
  49. public:
  50. class Easy;
  51. class Multi;
  52. struct TransferInfo
  53. {
  54. TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
  55. F64 mSizeDownload;
  56. F64 mTotalTime;
  57. F64 mSpeedDownload;
  58. };
  59. class Responder
  60. {
  61. //LOG_CLASS(Responder);
  62. public:
  63. Responder();
  64. virtual ~Responder();
  65. /**
  66. * @brief return true if the status code indicates success.
  67. */
  68. static bool isGoodStatus(U32 status)
  69. {
  70. return((200 <= status) && (status < 300));
  71. }
  72. virtual void errorWithContent(
  73. U32 status,
  74. const std::string& reason,
  75. const LLSD& content);
  76. //< called by completed() on bad status
  77. virtual void error(U32 status, const std::string& reason);
  78. //< called by default error(status, reason, content)
  79. virtual void result(const LLSD& content);
  80. //< called by completed for good status codes.
  81. virtual void completedRaw(
  82. U32 status,
  83. const std::string& reason,
  84. const LLChannelDescriptors& channels,
  85. const LLIOPipe::buffer_ptr_t& buffer);
  86. /**< Override point for clients that may want to use this
  87. class when the response is some other format besides LLSD
  88. */
  89. virtual void completed(
  90. U32 status,
  91. const std::string& reason,
  92. const LLSD& content);
  93. /**< The default implemetnation calls
  94. either:
  95. * result(), or
  96. * error()
  97. */
  98. // Override to handle parsing of the header only. Note: this is the only place where the contents
  99. // of the header can be parsed. In the ::completed call above only the body is contained in the LLSD.
  100. virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content);
  101. // Used internally to set the url for debugging later.
  102. void setURL(const std::string& url);
  103. virtual bool followRedir()
  104. {
  105. return false;
  106. }
  107. public: /* but not really -- don't touch this */
  108. U32 mReferenceCount;
  109. private:
  110. std::string mURL;
  111. };
  112. typedef boost::intrusive_ptr<Responder> ResponderPtr;
  113. /**
  114. * @ brief Set certificate authority file used to verify HTTPS certs.
  115. */
  116. static void setCAFile(const std::string& file);
  117. /**
  118. * @ brief Set certificate authority path used to verify HTTPS certs.
  119. */
  120. static void setCAPath(const std::string& path);
  121. /**
  122. * @ brief Return human-readable string describing libcurl version.
  123. */
  124. static std::string getVersionString();
  125. /**
  126. * @ brief Get certificate authority file used to verify HTTPS certs.
  127. */
  128. static const std::string& getCAFile() { return sCAFile; }
  129. /**
  130. * @ brief Get certificate authority path used to verify HTTPS certs.
  131. */
  132. static const std::string& getCAPath() { return sCAPath; }
  133. /**
  134. * @ brief Initialize LLCurl class
  135. */
  136. static void initClass(F32 curl_reuest_timeout = 120.f, S32 max_number_handles = 256, bool multi_threaded = false);
  137. /**
  138. * @ brief Cleanup LLCurl class
  139. */
  140. static void cleanupClass();
  141. /**
  142. * @ brief curl error code -> string
  143. */
  144. static std::string strerror(CURLcode errorcode);
  145. // For OpenSSL callbacks
  146. static std::vector<LLMutex*> sSSLMutex;
  147. // OpenSSL callbacks
  148. static void ssl_locking_callback(int mode, int type, const char *file, int line);
  149. static unsigned long ssl_thread_id(void);
  150. static LLCurlThread* getCurlThread() { return sCurlThread ;}
  151. static CURLM* newMultiHandle() ;
  152. static CURLMcode deleteMultiHandle(CURLM* handle) ;
  153. static CURL* newEasyHandle() ;
  154. static void deleteEasyHandle(CURL* handle) ;
  155. private:
  156. static std::string sCAPath;
  157. static std::string sCAFile;
  158. static const unsigned int MAX_REDIRECTS;
  159. static LLCurlThread* sCurlThread;
  160. static LLMutex* sHandleMutexp ;
  161. static S32 sTotalHandles ;
  162. static S32 sMaxHandles;
  163. public:
  164. static bool sNotQuitting;
  165. static F32 sCurlRequestTimeOut;
  166. };
  167. class LLCurl::Easy
  168. {
  169. LOG_CLASS(Easy);
  170. private:
  171. Easy();
  172. public:
  173. static Easy* getEasy();
  174. ~Easy();
  175. CURL* getCurlHandle() const { return mCurlEasyHandle; }
  176. void setErrorBuffer();
  177. void setCA();
  178. void setopt(CURLoption option, S32 value);
  179. // These assume the setter does not free value!
  180. void setopt(CURLoption option, void* value);
  181. void setopt(CURLoption option, char* value);
  182. // Copies the string so that it is guaranteed to stick around
  183. void setoptString(CURLoption option, const std::string& value);
  184. void slist_append(const char* str);
  185. void setHeaders();
  186. U32 report(CURLcode);
  187. void getTransferInfo(LLCurl::TransferInfo* info);
  188. void prepRequest(const std::string& url, const std::vector<std::string>& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false);
  189. const char* getErrorBuffer();
  190. std::stringstream& getInput() { return mInput; }
  191. std::stringstream& getHeaderOutput() { return mHeaderOutput; }
  192. LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
  193. const LLChannelDescriptors& getChannels() { return mChannels; }
  194. void resetState();
  195. static CURL* allocEasyHandle();
  196. static void releaseEasyHandle(CURL* handle);
  197. private:
  198. friend class LLCurl;
  199. friend class LLCurl::Multi;
  200. CURL* mCurlEasyHandle;
  201. struct curl_slist* mHeaders;
  202. std::stringstream mRequest;
  203. LLChannelDescriptors mChannels;
  204. LLIOPipe::buffer_ptr_t mOutput;
  205. std::stringstream mInput;
  206. std::stringstream mHeaderOutput;
  207. char mErrorBuffer[CURL_ERROR_SIZE];
  208. // Note: char*'s not strings since we pass pointers to curl
  209. std::vector<char*> mStrings;
  210. LLCurl::ResponderPtr mResponder;
  211. static std::set<CURL*> sFreeHandles;
  212. static std::set<CURL*> sActiveHandles;
  213. static LLMutex* sHandleMutexp ;
  214. };
  215. class LLCurl::Multi
  216. {
  217. LOG_CLASS(Multi);
  218. friend class LLCurlThread ;
  219. private:
  220. ~Multi();
  221. void markDead() ;
  222. bool doPerform();
  223. public:
  224. typedef enum
  225. {
  226. STATE_READY=0,
  227. STATE_PERFORMING=1,
  228. STATE_COMPLETED=2
  229. } ePerformState;
  230. Multi(F32 idle_time_out = 0.f);
  231. LLCurl::Easy* allocEasy();
  232. bool addEasy(LLCurl::Easy* easy);
  233. void removeEasy(LLCurl::Easy* easy);
  234. void lock() ;
  235. void unlock() ;
  236. void setState(ePerformState state) ;
  237. ePerformState getState() ;
  238. bool isCompleted() ;
  239. bool isValid() {return mCurlMultiHandle != NULL ;}
  240. bool isDead() {return mDead;}
  241. bool waitToComplete() ;
  242. S32 process();
  243. CURLMsg* info_read(S32* msgs_in_queue);
  244. S32 mQueued;
  245. S32 mErrorCount;
  246. private:
  247. void easyFree(LLCurl::Easy*);
  248. void cleanup() ;
  249. CURLM* mCurlMultiHandle;
  250. typedef std::set<LLCurl::Easy*> easy_active_list_t;
  251. easy_active_list_t mEasyActiveList;
  252. typedef std::map<CURL*, LLCurl::Easy*> easy_active_map_t;
  253. easy_active_map_t mEasyActiveMap;
  254. typedef std::set<LLCurl::Easy*> easy_free_list_t;
  255. easy_free_list_t mEasyFreeList;
  256. LLQueuedThread::handle_t mHandle ;
  257. ePerformState mState;
  258. BOOL mDead ;
  259. LLMutex* mMutexp ;
  260. LLMutex* mDeletionMutexp ;
  261. LLMutex* mEasyMutexp ;
  262. LLFrameTimer mIdleTimer ;
  263. F32 mIdleTimeOut;
  264. };
  265. class LLCurlThread : public LLQueuedThread
  266. {
  267. public:
  268. class CurlRequest : public LLQueuedThread::QueuedRequest
  269. {
  270. protected:
  271. virtual ~CurlRequest(); // use deleteRequest()
  272. public:
  273. CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread);
  274. /*virtual*/ bool processRequest();
  275. /*virtual*/ void finishRequest(bool completed);
  276. private:
  277. // input
  278. LLCurl::Multi* mMulti;
  279. LLCurlThread* mCurlThread;
  280. };
  281. friend class CurlRequest;
  282. public:
  283. LLCurlThread(bool threaded = true) ;
  284. virtual ~LLCurlThread() ;
  285. S32 update(F32 max_time_ms);
  286. void addMulti(LLCurl::Multi* multi) ;
  287. void killMulti(LLCurl::Multi* multi) ;
  288. private:
  289. bool doMultiPerform(LLCurl::Multi* multi) ;
  290. void deleteMulti(LLCurl::Multi* multi) ;
  291. void cleanupMulti(LLCurl::Multi* multi) ;
  292. } ;
  293. namespace boost
  294. {
  295. void intrusive_ptr_add_ref(LLCurl::Responder* p);
  296. void intrusive_ptr_release(LLCurl::Responder* p);
  297. };
  298. class LLCurlRequest
  299. {
  300. public:
  301. typedef std::vector<std::string> headers_t;
  302. LLCurlRequest();
  303. ~LLCurlRequest();
  304. void get(const std::string& url, LLCurl::ResponderPtr responder);
  305. bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
  306. bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
  307. bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder, S32 time_out = 0);
  308. S32 process();
  309. S32 getQueued();
  310. private:
  311. void addMulti();
  312. LLCurl::Easy* allocEasy();
  313. bool addEasy(LLCurl::Easy* easy);
  314. private:
  315. typedef std::set<LLCurl::Multi*> curlmulti_set_t;
  316. curlmulti_set_t mMultiSet;
  317. LLCurl::Multi* mActiveMulti;
  318. S32 mActiveRequestCount;
  319. BOOL mProcessing;
  320. };
  321. class LLCurlEasyRequest
  322. {
  323. public:
  324. LLCurlEasyRequest();
  325. ~LLCurlEasyRequest();
  326. void setopt(CURLoption option, S32 value);
  327. void setoptString(CURLoption option, const std::string& value);
  328. void setPost(char* postdata, S32 size);
  329. void setHeaderCallback(curl_header_callback callback, void* userdata);
  330. void setWriteCallback(curl_write_callback callback, void* userdata);
  331. void setReadCallback(curl_read_callback callback, void* userdata);
  332. void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata);
  333. void slist_append(const char* str);
  334. void sendRequest(const std::string& url);
  335. void requestComplete();
  336. bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL);
  337. std::string getErrorString();
  338. bool isCompleted() {return mMulti->isCompleted() ;}
  339. bool wait() { return mMulti->waitToComplete(); }
  340. bool isValid() {return mMulti && mMulti->isValid(); }
  341. LLCurl::Easy* getEasy() const { return mEasy; }
  342. private:
  343. CURLMsg* info_read(S32* queue, LLCurl::TransferInfo* info);
  344. private:
  345. LLCurl::Multi* mMulti;
  346. LLCurl::Easy* mEasy;
  347. bool mRequestSent;
  348. bool mResultReturned;
  349. };
  350. // Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
  351. namespace LLCurlFF
  352. {
  353. void check_easy_code(CURLcode code);
  354. void check_multi_code(CURLMcode code);
  355. }
  356. #endif // LL_LLCURL_H