llcorehttpcommon.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /**
  2. * @file llcorehttpcommon.h
  3. * @brief Public-facing declarations and definitions of common types
  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. #ifndef _LLCORE_HTTP_COMMON_H_
  27. #define _LLCORE_HTTP_COMMON_H_
  28. // @package LLCore::HTTP
  29. //
  30. // This library implements a high-level, Indra-code-free client interface to
  31. // HTTP services based on actual patterns found in the viewer and simulator.
  32. // Interfaces are similar to those supplied by the legacy classes LLCurlRequest
  33. // and LLHTTPClient. To that is added a policy scheme that allows an
  34. // application to specify connection behaviors: limits on connections, HTTP
  35. // keepalive, HTTP pipelining, retry-on-error limits, etc.
  36. //
  37. // Features of the library include:
  38. // - Single, private working thread where all transport and processing occurs.
  39. // - Support for multiple consumers running in multiple threads.
  40. // - Scatter/gather (a.k.a. buffer array) model for bulk data movement.
  41. // - Reference counting used for many object instance lifetimes.
  42. // - Minimal data sharing across threads for correctness and low latency.
  43. //
  44. // The public interface is declared in a few key header files:
  45. // - "llcorebufferarray.h"
  46. // - "llcorehttpcommon.h"
  47. // - "llcorehttphandler.h"
  48. // - "llcorehttpheaders.h"
  49. // - "llcorehttpoptions.h"
  50. // - "llcorehttprequest.h"
  51. // - "llcorehttpresponse.h"
  52. //
  53. // The library is still under development and particular users may need access
  54. // to internal implementation details that are found in the _*.h header files.
  55. // But this is a crutch to be avoided if at all possible and probably indicates
  56. // some interface work is neeeded.
  57. //
  58. // Using the library is fairly easy. Global setup needs a few steps:
  59. //
  60. // - libcurl initialization including thread-safely callbacks for SSL:
  61. // - curl_global_init(...)
  62. // - CRYPTO_set_locking_callback(...)
  63. // - CRYPTO_set_id_callback(...)
  64. // - HttpRequest::createService() called to instantiate singletons and support
  65. // objects.
  66. // - HttpRequest::startThread() to kick off the worker thread and begin
  67. // servicing requests.
  68. //
  69. // An HTTP consumer in an application, and an application may have many
  70. // consumers, does a few things:
  71. //
  72. // - Instantiate and retain an object based on HttpRequest. This object becomes
  73. // the portal into runtime services for the consumer.
  74. // - Derive or mixin the HttpHandler class if you want notification when
  75. // requests succeed or fail. This object's onCompleted() method is invoked
  76. // and an instance can be shared across requests.
  77. //
  78. // Issuing a request is straightforward:
  79. // - Construct a suitable URL.
  80. // - Configure HTTP options for the request (optional).
  81. // - Build a list of additional headers (optional).
  82. // - Invoke one of the requestXXXX() methods (requestGetByteRange, requestPost,
  83. // etc) on the HttpRequest instance supplying the above along with a policy
  84. // class, a priority and an optional pointer to an HttpHandler instance. Work
  85. // is then queued to the worker thread and occurs asynchronously.
  86. // - Periodically invoke the update() method on the HttpRequest instance which
  87. // performs completion notification to HttpHandler objects.
  88. // - Do completion processing in your onCompletion() method.
  89. #include <memory>
  90. #include <string>
  91. #include "curl/curl.h"
  92. #include "stdtypes.h"
  93. namespace LLCore
  94. {
  95. // All queued requests are represented by an HttpHandle value. The invalid
  96. // value is returned when a request failed to queue. The actual status for
  97. // these failures is then fetched with HttpRequest::getStatus().
  98. //
  99. // The handle is valid only for the life of a request. On return from any
  100. // HttpHandler notification, the handle immediately becomes invalid and may be
  101. // recycled for other queued requests.
  102. typedef void* HttpHandle;
  103. #define LLCORE_HTTP_HANDLE_INVALID (NULL)
  104. // For internal scheduling and metrics, we use a microsecond timebase
  105. // compatible with the environment.
  106. typedef U64 HttpTime;
  107. // Error codes defined by the library itself as distinct from libcurl (or any
  108. // other transport provider).
  109. enum HttpError
  110. {
  111. // Successful value compatible with the libcurl codes.
  112. HE_SUCCESS = 0,
  113. // Intended for HTTP reply codes 100-999, indicates that the reply should
  114. // be considered an error by the application.
  115. HE_REPLY_ERROR = 1,
  116. // Service is shutting down and requested operation will not be queued or
  117. // performed.
  118. HE_SHUTTING_DOWN = 2,
  119. // Operation was cancelled by request.
  120. HE_OP_CANCELLED = 3,
  121. // Invalid content range header received.
  122. HE_INV_CONTENT_RANGE_HDR = 4,
  123. // Request handle not found
  124. HE_HANDLE_NOT_FOUND = 5,
  125. // Invalid datatype for option/setting
  126. HE_INVALID_ARG = 6,
  127. // Option hasn't been explicitly set
  128. HE_OPT_NOT_SET = 7,
  129. // Option not dynamic, must be set during init phase
  130. HE_OPT_NOT_DYNAMIC = 8,
  131. // Invalid HTTP status code returned by server
  132. HE_INVALID_HTTP_STATUS = 9,
  133. // Couldn't allocate resource, typically libcurl handle
  134. HE_BAD_ALLOC = 10
  135. }; // end enum HttpError
  136. // HttpStatus encapsulates errors from libcurl (easy, multi), HTTP reply status
  137. // codes and internal errors as well. The encapsulation is not expected to
  138. // completely isolate the caller from libcurl but basic operational tests
  139. // (success or failure) are provided.
  140. //
  141. // Non-HTTP status are encoded as (type, status) with type being one of:
  142. // EXT_CURL_EASY, EXT_CURL_MULTI or LLCORE and status being the success/error
  143. // code from that domain. HTTP status is encoded as (status, error_flag).
  144. // Status should be in the range [100, 999] and error_flag is either HE_SUCCESS
  145. // or HE_REPLY_ERROR to indicate whether this should be treated as a successful
  146. // status or an error. The application is responsible for making that
  147. // determination and a range like [200, 299] is not automatically assumed to
  148. // be definitive.
  149. //
  150. // Examples:
  151. //
  152. // 1. Construct a default, successful status code:
  153. // HttpStatus();
  154. //
  155. // 2. Construct a successful, HTTP 200 status code:
  156. // HttpStatus(200);
  157. //
  158. // 3. Construct a failed, HTTP 404 not-found status code:
  159. // HttpStatus(404);
  160. //
  161. // 4. Construct a failed libcurl could not connect status code:
  162. // HttpStatus(HttpStatus::EXT_CURL_EASY, CURLE_COULDNT_CONNECT);
  163. //
  164. // 5. Construct an HTTP 301 status code to be treated as success:
  165. // HttpStatus(301, HE_SUCCESS);
  166. //
  167. // 6. Construct a failed status of HTTP Status 499 with a custom error message
  168. // HttpStatus(499, "Failed LLSD Response");
  169. struct HttpStatus
  170. {
  171. typedef S16 type_enum_t;
  172. static const type_enum_t EXT_CURL_EASY = 0; // mStatus is an error from a curl_easy_*() call
  173. static const type_enum_t EXT_CURL_MULTI = 1; // mStatus is an error from a curl_multi_*() call
  174. static const type_enum_t LLCORE = 2; // mStatus is an HE_* error code
  175. // 100-999 directly represent HTTP status codes
  176. HttpStatus();
  177. HttpStatus(type_enum_t type, short status);
  178. HttpStatus(int http_status);
  179. HttpStatus(int http_status, const std::string& message);
  180. LL_INLINE HttpStatus(const HttpStatus& rhs)
  181. {
  182. mDetails = rhs.mDetails;
  183. }
  184. ~HttpStatus()
  185. {
  186. }
  187. LL_INLINE HttpStatus& operator=(const HttpStatus& rhs)
  188. {
  189. mDetails = rhs.mDetails;
  190. return *this;
  191. }
  192. LL_INLINE HttpStatus& clone(const HttpStatus& rhs)
  193. {
  194. mDetails = std::shared_ptr<Details>(new Details(*rhs.mDetails));
  195. return *this;
  196. }
  197. // Test for successful status in the code regardless of error source
  198. // (internal, libcurl).
  199. //
  200. // @return 'true' when status is successful.
  201. //
  202. LL_INLINE operator bool() const
  203. {
  204. return mDetails && mDetails->mStatus == HE_SUCCESS;
  205. }
  206. // Inverse of previous operator.
  207. //
  208. // @return 'true' on any error condition
  209. LL_INLINE bool operator!() const
  210. {
  211. return mDetails && mDetails->mStatus != HE_SUCCESS;
  212. }
  213. // Equality and inequality tests to bypass bool conversion which will do
  214. // the wrong thing in conditional expressions.
  215. LL_INLINE bool operator==(const HttpStatus& rhs) const
  216. {
  217. if (!mDetails || !rhs.mDetails) return false;
  218. return *mDetails == *rhs.mDetails;
  219. }
  220. LL_INLINE bool operator!=(const HttpStatus& rhs) const
  221. {
  222. return !operator==(rhs);
  223. }
  224. // Convert to single numeric representation. Mainly for logging or other
  225. // informal purposes. Also creates an ambiguous second path to integer
  226. // conversion which tends to find programming errors such as formatting
  227. // the status to a stream (operator<<).
  228. operator U32() const;
  229. LL_INLINE U32 toULong() const { return operator U32(); }
  230. // And to convert to a hex string.
  231. std::string toHex() const;
  232. // Convert status to a string representation. For success, returns an empty
  233. // string. For failure statuses, a string as appropriate for the source of
  234. // the error code (libcurl easy, libcurl multi, or LLCore itself).
  235. std::string toString() const;
  236. // Convert status to a compact string representation of the form:
  237. // "<type>_<value>". The <type> will be one of: Core, Http, Easy, Multi,
  238. // Unknown. And <value> will be an unsigned integer. More easily
  239. /// interpreted than the hex representation, it's still compact and easily
  240. // searched.
  241. std::string toTerseString() const;
  242. // Returns true if the status value represents an HTTP response status
  243. // (100 - 999).
  244. LL_INLINE bool isHttpStatus() const
  245. {
  246. return mDetails && mDetails->mType >= type_enum_t(100) &&
  247. mDetails->mType <= type_enum_t(999);
  248. }
  249. // Returns true if the status is one that will be retried internally.
  250. // Provided for external consumption for cases where that logic needs to be
  251. // replicated. Only applies to failed statuses, successful statuses will
  252. // return false.
  253. bool isRetryable() const;
  254. // Returns the currently set status code as a raw number
  255. LL_INLINE short getStatus() const
  256. {
  257. return mDetails ? mDetails->mStatus : 0;
  258. }
  259. // Returns the currently set status type
  260. LL_INLINE type_enum_t getType() const
  261. {
  262. return mDetails ? mDetails->mType : 0;
  263. }
  264. // Returns an optional error message if one has been set.
  265. LL_INLINE std::string getMessage() const
  266. {
  267. return mDetails ? mDetails->mMessage : std::string();
  268. }
  269. // Sets an optional error message
  270. LL_INLINE void setMessage(const std::string& message)
  271. {
  272. if (mDetails)
  273. {
  274. mDetails->mMessage = message;
  275. }
  276. }
  277. // Retrieves an optionally recorded SSL certificate.
  278. LL_INLINE void* getErrorData() const
  279. {
  280. return mDetails ? mDetails->mErrorData : NULL;
  281. }
  282. // Optionally sets an SSL certificate on this status.
  283. LL_INLINE void setErrorData(void* data)
  284. {
  285. if (mDetails)
  286. {
  287. mDetails->mErrorData = data;
  288. }
  289. }
  290. private:
  291. struct Details
  292. {
  293. Details(type_enum_t type, short status)
  294. : mType(type),
  295. mStatus(status),
  296. mErrorData(NULL)
  297. {
  298. }
  299. Details(const Details& rhs)
  300. : mType(rhs.mType),
  301. mStatus(rhs.mStatus),
  302. mMessage(rhs.mMessage),
  303. mErrorData(rhs.mErrorData)
  304. {
  305. }
  306. LL_INLINE bool operator==(const Details& rhs) const
  307. {
  308. return mType == rhs.mType && mStatus == rhs.mStatus;
  309. }
  310. type_enum_t mType;
  311. short mStatus;
  312. void* mErrorData;
  313. std::string mMessage;
  314. };
  315. std::shared_ptr<Details> mDetails;
  316. };
  317. // A namespace for several free methods and low level utilities.
  318. namespace LLHttp
  319. {
  320. typedef std::shared_ptr<CURL> CURL_ptr;
  321. void initialize();
  322. void cleanup();
  323. CURL_ptr createEasyHandle();
  324. const std::string& getCURLVersion();
  325. void check_curl_code(CURLcode code, int curl_setopt_option);
  326. extern bool gEnabledHTTP2;
  327. }
  328. } // End namespace LLCore
  329. // Some commonly used statuses, to avoid having to construct them at each test.
  330. // HB
  331. extern const LLCore::HttpStatus gStatusPartialContent; // HTTP 206
  332. extern const LLCore::HttpStatus gStatusBadRequest; // HTTP 400
  333. extern const LLCore::HttpStatus gStatusForbidden; // HTTP 403
  334. extern const LLCore::HttpStatus gStatusNotFound; // HTTP 404
  335. extern const LLCore::HttpStatus gStatusNotSatisfiable; // HTTP 416
  336. extern const LLCore::HttpStatus gStatusInternalError; // HTTP 499
  337. extern const LLCore::HttpStatus gStatusServerInternalError; // HTTP 500
  338. extern const LLCore::HttpStatus gStatusBadGateway; // HTTP 502
  339. extern const LLCore::HttpStatus gStatusUnavailable; // HTTP 503
  340. extern const LLCore::HttpStatus gStatusCantConnect; // Curl error
  341. extern const LLCore::HttpStatus gStatusTimeout; // Curl error
  342. extern const LLCore::HttpStatus gStatusCancelled; // LLCore error
  343. #endif // _LLCORE_HTTP_COMMON_H_