llcorehttpcommon.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /**
  2. * @file llcorehttpcommon.cpp
  3. * @brief
  4. *
  5. * $LicenseInfo:firstyear=2012&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2012-2013, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include <sstream>
  28. #include "openssl/opensslv.h"
  29. #if OPENSSL_VERSION_NUMBER < 0x101000bfL
  30. # define SAFE_SSL 1
  31. # include "openssl/crypto.h"
  32. #endif
  33. #include "curl/curlver.h"
  34. #include "llcorehttpcommon.h"
  35. #include "llhttpconstants.h"
  36. #include "llmutex.h"
  37. #include "llstring.h"
  38. #include "llthread.h"
  39. // Some commonly used statuses, defined as globals, so to avoid having to
  40. // construct and destruct them each time we need them in tests...
  41. const LLCore::HttpStatus gStatusPartialContent(HTTP_PARTIAL_CONTENT);
  42. const LLCore::HttpStatus gStatusBadRequest(HTTP_BAD_REQUEST);
  43. const LLCore::HttpStatus gStatusForbidden(HTTP_FORBIDDEN);
  44. const LLCore::HttpStatus gStatusNotFound(HTTP_NOT_FOUND);
  45. const LLCore::HttpStatus gStatusNotSatisfiable(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE);
  46. const LLCore::HttpStatus gStatusInternalError(HTTP_INTERNAL_ERROR);
  47. const LLCore::HttpStatus gStatusServerInternalError(HTTP_INTERNAL_SERVER_ERROR);
  48. const LLCore::HttpStatus gStatusBadGateway(HTTP_BAD_GATEWAY);
  49. const LLCore::HttpStatus gStatusUnavailable(HTTP_SERVICE_UNAVAILABLE);
  50. const LLCore::HttpStatus gStatusCantConnect(LLCore::HttpStatus::EXT_CURL_EASY,
  51. CURLE_COULDNT_CONNECT);
  52. const LLCore::HttpStatus gStatusTimeout(LLCore::HttpStatus::EXT_CURL_EASY,
  53. CURLE_OPERATION_TIMEDOUT);
  54. const LLCore::HttpStatus gStatusCancelled(LLCore::HttpStatus::LLCORE,
  55. LLCore::HE_OP_CANCELLED);
  56. namespace LLCore
  57. {
  58. HttpStatus::type_enum_t EXT_CURL_EASY;
  59. HttpStatus::type_enum_t EXT_CURL_MULTI;
  60. HttpStatus::type_enum_t LLCORE;
  61. HttpStatus::HttpStatus()
  62. {
  63. constexpr type_enum_t type = LLCORE;
  64. mDetails = std::make_shared<Details>(type, HE_SUCCESS);
  65. }
  66. HttpStatus::HttpStatus(type_enum_t type, short status)
  67. {
  68. mDetails = std::make_shared<Details>(type, status);
  69. }
  70. HttpStatus::HttpStatus(int http_status)
  71. {
  72. mDetails =
  73. std::make_shared<Details>(http_status,
  74. http_status >= 200 &&
  75. http_status <= 299 ? HE_SUCCESS
  76. : HE_REPLY_ERROR);
  77. llassert(http_status >= 100 && http_status <= 999);
  78. }
  79. HttpStatus::HttpStatus(int http_status, const std::string& message)
  80. {
  81. mDetails =
  82. std::make_shared<Details>(http_status,
  83. http_status >= 200 &&
  84. http_status <= 299 ? HE_SUCCESS
  85. : HE_REPLY_ERROR);
  86. llassert(http_status >= 100 && http_status <= 999);
  87. mDetails->mMessage = message;
  88. }
  89. HttpStatus::operator U32() const
  90. {
  91. // Effectively, concatenate mType (high) with mStatus (low).
  92. static const int shift = 8 * sizeof(mDetails->mStatus);
  93. return U32(mDetails->mType) << shift | U32((int)mDetails->mStatus);
  94. }
  95. std::string HttpStatus::toHex() const
  96. {
  97. std::ostringstream result;
  98. result.width(8);
  99. result.fill('0');
  100. result << std::hex << operator U32();
  101. return result.str();
  102. }
  103. std::string HttpStatus::toString() const
  104. {
  105. static const char* llcore_errors[] = {
  106. "",
  107. "HTTP error reply status",
  108. "Services shutting down",
  109. "Operation cancelled",
  110. "Invalid Content-Range header encountered",
  111. "Request handle not found",
  112. "Invalid datatype for argument or option",
  113. "Option has not been explicitly set",
  114. "Option is not dynamic and must be set early",
  115. "Invalid HTTP status code received from server",
  116. "Could not allocate required resource"
  117. };
  118. constexpr S32 llcore_errors_count = LL_ARRAY_SIZE(llcore_errors);
  119. static const struct
  120. {
  121. type_enum_t mCode;
  122. const char* mText;
  123. }
  124. http_errors[] = {
  125. // Keep sorted by mCode, we binary search this list.
  126. { 100, "Continue" },
  127. { 101, "Switching Protocols" },
  128. { 200, "OK" },
  129. { 201, "Created" },
  130. { 202, "Accepted" },
  131. { 203, "Non-Authoritative Information" },
  132. { 204, "No Content" },
  133. { 205, "Reset Content" },
  134. { 206, "Partial Content" },
  135. { 300, "Multiple Choices" },
  136. { 301, "Moved Permanently" },
  137. { 302, "Found" },
  138. { 303, "See Other" },
  139. { 304, "Not Modified" },
  140. { 305, "Use Proxy" },
  141. { 307, "Temporary Redirect" },
  142. { 400, "Bad Request" },
  143. { 401, "Unauthorized" },
  144. { 402, "Payment Required" },
  145. { 403, "Forbidden" },
  146. { 404, "Not Found" },
  147. { 405, "Method Not Allowed" },
  148. { 406, "Not Acceptable" },
  149. { 407, "Proxy Authentication Required" },
  150. { 408, "Request Time-out" },
  151. { 409, "Conflict" },
  152. { 410, "Gone" },
  153. { 411, "Length Required" },
  154. { 412, "Precondition Failed" },
  155. { 413, "Request Entity Too Large" },
  156. { 414, "Request-URI Too Large" },
  157. { 415, "Unsupported Media Type" },
  158. { 416, "Requested range not satisfiable" },
  159. { 417, "Expectation Failed" },
  160. { 499, "Malformed response contents" },
  161. { 500, "Internal Server Error" },
  162. { 501, "Not Implemented" },
  163. { 502, "Bad Gateway" },
  164. { 503, "Service Unavailable" },
  165. { 504, "Gateway Time-out" },
  166. { 505, "HTTP Version not supported" }
  167. };
  168. constexpr S32 http_errors_count = LL_ARRAY_SIZE(http_errors);
  169. if (*this)
  170. {
  171. return std::string("");
  172. }
  173. type_enum_t type = getType();
  174. switch (type)
  175. {
  176. case EXT_CURL_EASY:
  177. return std::string(curl_easy_strerror(CURLcode(getStatus())));
  178. case EXT_CURL_MULTI:
  179. return std::string(curl_multi_strerror(CURLMcode(getStatus())));
  180. case LLCORE:
  181. {
  182. short status = getStatus();
  183. if (status >= 0 && status < llcore_errors_count)
  184. {
  185. return std::string(llcore_errors[status]);
  186. }
  187. break;
  188. }
  189. default:
  190. {
  191. if (isHttpStatus())
  192. {
  193. // special handling for status 499 "Linden Catchall"
  194. if (type == 499 && !getMessage().empty())
  195. {
  196. return getMessage();
  197. }
  198. // Binary search for the error code and string
  199. S32 bottom = 0;
  200. S32 top = http_errors_count;
  201. while (true)
  202. {
  203. S32 at = (bottom + top) / 2;
  204. if (type == http_errors[at].mCode)
  205. {
  206. return std::string(http_errors[at].mText);
  207. }
  208. if (at == bottom)
  209. {
  210. break;
  211. }
  212. else if (type < http_errors[at].mCode)
  213. {
  214. top = at;
  215. }
  216. else
  217. {
  218. bottom = at;
  219. }
  220. }
  221. }
  222. }
  223. }
  224. return std::string("Unknown error");
  225. }
  226. std::string HttpStatus::toTerseString() const
  227. {
  228. std::ostringstream result;
  229. short error_value = getStatus();
  230. type_enum_t type = getType();
  231. switch (type)
  232. {
  233. case EXT_CURL_EASY:
  234. result << "Easy_";
  235. break;
  236. case EXT_CURL_MULTI:
  237. result << "Multi_";
  238. break;
  239. case LLCORE:
  240. result << "Core_";
  241. break;
  242. default:
  243. if (isHttpStatus())
  244. {
  245. result << "Http_";
  246. error_value = type;
  247. }
  248. else
  249. {
  250. result << "Unknown_";
  251. }
  252. break;
  253. }
  254. result << error_value;
  255. return result.str();
  256. }
  257. // Pass true on statuses that might actually be cleared by a retry. Library
  258. // failures, calling problems, etc aren't going to be fixed by squirting bits
  259. // all over the Net.
  260. bool HttpStatus::isRetryable() const
  261. {
  262. static const HttpStatus bad_proxy(EXT_CURL_EASY,
  263. CURLE_COULDNT_RESOLVE_PROXY);
  264. static const HttpStatus bad_host(EXT_CURL_EASY,
  265. CURLE_COULDNT_RESOLVE_HOST);
  266. static const HttpStatus send_error(EXT_CURL_EASY, CURLE_SEND_ERROR);
  267. static const HttpStatus recv_error(EXT_CURL_EASY, CURLE_RECV_ERROR);
  268. static const HttpStatus upload_failed(EXT_CURL_EASY, CURLE_UPLOAD_FAILED);
  269. static const HttpStatus post_error(EXT_CURL_EASY, CURLE_HTTP_POST_ERROR);
  270. static const HttpStatus partial_file(EXT_CURL_EASY, CURLE_PARTIAL_FILE);
  271. static const HttpStatus bad_range(LLCORE, HE_INV_CONTENT_RANGE_HDR);
  272. // HE_INVALID_HTTP_STATUS is special. As of 7.37.0, there are some
  273. // scenarios where response processing in libcurl appear to go wrong and
  274. // response data is corrupted. A side-effect of this is that the HTTP
  275. // status is read as 0 from the library. See libcurl bug report 1420
  276. // (https://sourceforge.net/p/curl/bugs/1420/) for details.
  277. static const HttpStatus inv_status(HttpStatus::LLCORE,
  278. HE_INVALID_HTTP_STATUS);
  279. // vvv Include special 499 in retryables
  280. return ((isHttpStatus() && getType() >= 499 && getType() <= 599) ||
  281. *this == gStatusCantConnect || // Connection reset/endpoint problems
  282. *this == bad_proxy || // DNS problems
  283. *this == bad_host || // DNS problems
  284. *this == send_error || // General socket problems
  285. *this == recv_error || // General socket problems
  286. *this == upload_failed || // Transport problem
  287. *this == gStatusTimeout || // Timer expired
  288. *this == post_error || // Transport problem
  289. *this == partial_file || // Data inconsistency in response
  290. #if 1 // disable for "[curl:bugs] #1420" tests.
  291. *this == inv_status || // Inv status can reflect internal state problem in libcurl
  292. #endif
  293. *this == bad_range); // Short data read disagrees with content-range
  294. }
  295. namespace LLHttp
  296. {
  297. bool gEnabledHTTP2 = false;
  298. namespace
  299. {
  300. static LLMutex sHandleMutex;
  301. CURL* getCurlTemplateHandle()
  302. {
  303. static CURL* template_handlep = NULL;
  304. if (!template_handlep)
  305. {
  306. // Late creation of the template curl handle
  307. template_handlep = curl_easy_init();
  308. if (template_handlep)
  309. {
  310. CURLcode result = curl_easy_setopt(template_handlep,
  311. CURLOPT_IPRESOLVE,
  312. CURL_IPRESOLVE_V4);
  313. check_curl_code(result, CURLOPT_IPRESOLVE);
  314. result = curl_easy_setopt(template_handlep,
  315. CURLOPT_NOSIGNAL, 1);
  316. check_curl_code(result, CURLOPT_NOSIGNAL);
  317. result = curl_easy_setopt(template_handlep,
  318. CURLOPT_NOPROGRESS, 1);
  319. check_curl_code(result, CURLOPT_NOPROGRESS);
  320. #if LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR < 60
  321. result = curl_easy_setopt(template_handlep,
  322. CURLOPT_ENCODING, "");
  323. check_curl_code(result, CURLOPT_ENCODING);
  324. #endif
  325. result = curl_easy_setopt(template_handlep,
  326. CURLOPT_AUTOREFERER, 1);
  327. check_curl_code(result, CURLOPT_AUTOREFERER);
  328. result = curl_easy_setopt(template_handlep,
  329. CURLOPT_FOLLOWLOCATION, 1);
  330. check_curl_code(result, CURLOPT_FOLLOWLOCATION);
  331. result = curl_easy_setopt(template_handlep,
  332. CURLOPT_SSL_VERIFYPEER, 1);
  333. check_curl_code(result, CURLOPT_SSL_VERIFYPEER);
  334. result = curl_easy_setopt(template_handlep,
  335. CURLOPT_SSL_VERIFYHOST, 0);
  336. check_curl_code(result, CURLOPT_SSL_VERIFYHOST);
  337. // The Linksys WRT54G V5 router has an issue with frequent DNS
  338. // lookups from LAN machines. If they happen too often, like for
  339. // every HTTP request, the router gets annoyed after about 700 or
  340. // so requests and starts issuing TCP RSTs to new connections.
  341. // Reuse the DNS lookups for even a few seconds and no RSTs.
  342. result = curl_easy_setopt(template_handlep,
  343. CURLOPT_DNS_CACHE_TIMEOUT, 15);
  344. check_curl_code(result, CURLOPT_DNS_CACHE_TIMEOUT);
  345. }
  346. else
  347. {
  348. llwarns << "Cannot create the template curl handle !" << llendl;
  349. }
  350. }
  351. return template_handlep;
  352. }
  353. void deallocateEasyCurl(CURL* curlp)
  354. {
  355. sHandleMutex.lock();
  356. curl_easy_cleanup(curlp);
  357. sHandleMutex.unlock();
  358. }
  359. #if SAFE_SSL
  360. typedef std::shared_ptr<LLMutex> LLMutex_ptr;
  361. std::vector<LLMutex_ptr> sSSLMutex;
  362. //static
  363. void ssl_locking_callback(int mode, int type, const char* file, int line)
  364. {
  365. if ((size_t)type >= sSSLMutex.size())
  366. {
  367. llwarns << "Attempt to get unknown MUTEX in SSL Lock." << llendl;
  368. }
  369. if (mode & CRYPTO_LOCK)
  370. {
  371. sSSLMutex[type]->lock();
  372. }
  373. else
  374. {
  375. sSSLMutex[type]->unlock();
  376. }
  377. }
  378. //static
  379. unsigned long ssl_thread_id()
  380. {
  381. return LLThread::thisThreadIdHash();
  382. }
  383. #endif
  384. }
  385. void initialize()
  386. {
  387. // Do not change this "unless you are familiar with and mean to control
  388. // internal operations of libcurl"
  389. // - http://curl.haxx.se/libcurl/c/curl_global_init.html
  390. CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
  391. check_curl_code(code, CURL_GLOBAL_ALL);
  392. #if SAFE_SSL
  393. S32 mutex_count = CRYPTO_num_locks();
  394. for (S32 i = 0; i < mutex_count; ++i)
  395. {
  396. sSSLMutex.push_back(LLMutex_ptr(new LLMutex()));
  397. }
  398. CRYPTO_set_id_callback(&ssl_thread_id);
  399. CRYPTO_set_locking_callback(&ssl_locking_callback);
  400. #endif
  401. }
  402. void cleanup()
  403. {
  404. #if SAFE_SSL
  405. CRYPTO_set_id_callback(NULL);
  406. CRYPTO_set_locking_callback(NULL);
  407. sSSLMutex.clear();
  408. #endif
  409. curl_global_cleanup();
  410. }
  411. CURL_ptr createEasyHandle()
  412. {
  413. LLMutexLock lock(sHandleMutex);
  414. CURL* handle = curl_easy_duphandle(getCurlTemplateHandle());
  415. return CURL_ptr(handle, &deallocateEasyCurl);
  416. }
  417. const std::string& getCURLVersion()
  418. {
  419. static std::string version;
  420. if (version.empty())
  421. {
  422. version.assign(curl_version());
  423. // Cleanup the version string to have it showing slashes in beetween
  424. // components instead of between each component name and component
  425. // version. HB
  426. LLStringUtil::replaceChar(version, ' ', ';');
  427. LLStringUtil::replaceChar(version, '/', ' ');
  428. LLStringUtil::replaceChar(version, ';', '/');
  429. }
  430. return version;
  431. }
  432. void check_curl_code(CURLcode code, int curl_setopt_option)
  433. {
  434. if (code != CURLE_OK)
  435. {
  436. // Comment from old llcurl code which may no longer apply:
  437. //
  438. // linux appears to throw a curl error once per session for a bad
  439. // initialization at a pretty random time (when enabling cookies).
  440. llwarns << "curl error detected: " << curl_easy_strerror(code)
  441. << " - curl_easy_setopt option: " << curl_setopt_option
  442. << llendl;
  443. }
  444. }
  445. }
  446. } // End namespace LLCore