Line data Source code
1 : #pragma once 2 : 3 : // This component provides a `class`, `Curl`, that implements the `HTTPClient` 4 : // interface in terms of [libcurl][1]. `class Curl` manages a thread that is 5 : // used as the event loop for libcurl. 6 : // 7 : // If this library was built in a mode that does not include libcurl, then this 8 : // file and its implementation, `curl.cpp`, will not be included. 9 : // 10 : // [1]: https://curl.se/libcurl/ 11 : 12 : #include <curl/curl.h> 13 : 14 : #include <chrono> 15 : #include <functional> 16 : #include <memory> 17 : #include <string> 18 : #include <thread> 19 : 20 : #include "clock.h" 21 : #include "http_client.h" 22 : #include "json_fwd.hpp" 23 : 24 : namespace datadog { 25 : namespace tracing { 26 : 27 : // `class CurlLibrary` has one member function for every libcurl function used 28 : // in the implementation of this component. 29 : // 30 : // The naming convention is that `CurlLibrary::foo_bar` corresponds to 31 : // `curl_foo_bar`, with the exception of `curl_easy_getinfo` and 32 : // `curl_easy_setopt`. `curl_easy_getinfo` and `curl_easy_setopt` have multiple 33 : // corresponding member functions -- one for each `CURLINFO` value or 34 : // `CURLoption` value, respectively. 35 : // 36 : // The default implementations forward to their libcurl counterparts. Unit 37 : // tests override some of the member functions. 38 : class CurlLibrary { 39 : public: 40 : typedef size_t (*WriteCallback)(char *ptr, size_t size, size_t nmemb, 41 : void *userdata); 42 : typedef size_t (*HeaderCallback)(char *buffer, size_t size, size_t nitems, 43 : void *userdata); 44 : 45 21 : virtual ~CurlLibrary() = default; 46 : 47 : virtual void easy_cleanup(CURL *handle); 48 : virtual CURL *easy_init(); 49 : virtual CURLcode easy_getinfo_private(CURL *curl, char **user_data); 50 : virtual CURLcode easy_getinfo_response_code(CURL *curl, long *code); 51 : virtual CURLcode easy_setopt_errorbuffer(CURL *handle, char *buffer); 52 : virtual CURLcode easy_setopt_headerdata(CURL *handle, void *data); 53 : virtual CURLcode easy_setopt_headerfunction(CURL *handle, HeaderCallback); 54 : virtual CURLcode easy_setopt_httpheader(CURL *handle, curl_slist *headers); 55 : virtual CURLcode easy_setopt_post(CURL *handle, long post); 56 : virtual CURLcode easy_setopt_postfields(CURL *handle, const char *data); 57 : virtual CURLcode easy_setopt_postfieldsize(CURL *handle, long size); 58 : virtual CURLcode easy_setopt_private(CURL *handle, void *pointer); 59 : virtual CURLcode easy_setopt_unix_socket_path(CURL *handle, const char *path); 60 : virtual CURLcode easy_setopt_url(CURL *handle, const char *url); 61 : virtual CURLcode easy_setopt_writedata(CURL *handle, void *data); 62 : virtual CURLcode easy_setopt_writefunction(CURL *handle, WriteCallback); 63 : virtual CURLcode easy_setopt_timeout_ms(CURL *handle, long timeout_ms); 64 : virtual const char *easy_strerror(CURLcode error); 65 : virtual void global_cleanup(); 66 : virtual CURLcode global_init(long flags); 67 : virtual CURLMcode multi_add_handle(CURLM *multi_handle, CURL *easy_handle); 68 : virtual CURLMcode multi_cleanup(CURLM *multi_handle); 69 : virtual CURLMsg *multi_info_read(CURLM *multi_handle, int *msgs_in_queue); 70 : virtual CURLM *multi_init(); 71 : virtual CURLMcode multi_perform(CURLM *multi_handle, int *running_handles); 72 : virtual CURLMcode multi_poll(CURLM *multi_handle, curl_waitfd extra_fds[], 73 : unsigned extra_nfds, int timeout_ms, 74 : int *numfds); 75 : virtual CURLMcode multi_remove_handle(CURLM *multi_handle, CURL *easy_handle); 76 : virtual const char *multi_strerror(CURLMcode error); 77 : virtual CURLMcode multi_wakeup(CURLM *multi_handle); 78 : virtual curl_slist *slist_append(curl_slist *list, const char *string); 79 : virtual void slist_free_all(curl_slist *list); 80 : }; 81 : 82 : class CurlImpl; 83 : class Logger; 84 : 85 : class Curl : public HTTPClient { 86 : CurlImpl *impl_; 87 : 88 : public: 89 : using ThreadGenerator = std::function<std::thread(std::function<void()> &&)>; 90 : 91 : explicit Curl(const std::shared_ptr<Logger> &, const Clock &); 92 : Curl(const std::shared_ptr<Logger> &, const Clock &, CurlLibrary &); 93 : Curl(const std::shared_ptr<Logger> &, const Clock &, CurlLibrary &, 94 : const ThreadGenerator &); 95 : ~Curl(); 96 : 97 : Curl(const Curl &) = delete; 98 : 99 : Expected<void> post(const URL &url, HeadersSetter set_headers, 100 : std::string body, ResponseHandler on_response, 101 : ErrorHandler on_error, 102 : std::chrono::steady_clock::time_point deadline) override; 103 : 104 : void drain(std::chrono::steady_clock::time_point deadline) override; 105 : 106 : nlohmann::json config_json() const override; 107 : }; 108 : 109 : } // namespace tracing 110 : } // namespace datadog