curl-cpp
static c++17 wrapper for curl with -fno-exceptions support
curl.hpp
1 #ifndef __curl_cpp_curl_HPP__
2 # define __curl_cpp_curl_HPP__
3 
4 # include <cstdint>
5 # include <cstdio>
6 # include <stdexcept>
7 # include <memory>
8 
9 # include "return-exception/ret-exception.hpp"
10 
11 namespace curl {
12 /**
13  * Base class for all exceptions can throw
14  * via Ret_except in this library.
15  */
16 class Exception: public std::runtime_error {
17 public:
18  using std::runtime_error::runtime_error;
19 };
20 /**
21  * This exception mean that the libcurl found at
22  * runtime doesn't support particular feature/function
23  * you called.
24  */
25 class NotBuiltIn_error: public Exception {
26 public:
27  using Exception::Exception;
28 };
29 /**
30  * Bugs in the libcurl found at runtime!
31  */
32 class libcurl_bug: public Exception {
33 public:
34  using Exception::Exception;
35 };
36 /**
37  * You call libcurl API which perform callback from libcurl
38  * callback!
39  */
41 public:
42  using Exception::Exception;
43 };
44 
45 class Share_base;
46 template <class Shared_mutex_t>
47 class Share;
48 
49 /**
50  * It is unsafe to use any of class defined below in multithreaded environment without synchronization.
51  */
52 class Easy_ref_t;
53 class Multi_t;
54 class Url_ref_t;
55 
56 /**
57  * @warning Must be defined before any thread is created.
58  *
59  * There can be multiple instances of this object, as long as during
60  * ctor and dtor, there is only one thread in the program.
61  */
62 class curl_t {
63 public:
64  /**
65  * @example curl_version.cc
66  *
67  * This struct encapsulate operations on libcurl version.
68  */
69  struct Version {
70  std::uint32_t num;
71 
72  static constexpr Version from(std::uint8_t major, std::uint8_t minor, std::uint8_t patch) noexcept;
73 
74  constexpr std::uint8_t get_major() const noexcept;
75  constexpr std::uint8_t get_minor() const noexcept;
76  constexpr std::uint8_t get_patch() const noexcept;
77 
78  /**
79  * Check whether version x is older than version y.
80  */
81  friend constexpr bool operator < (const Version &x, const Version &y) noexcept;
82  /**
83  * Check whether version x is older than or the same as version y.
84  */
85  friend constexpr bool operator <= (const Version &x, const Version &y) noexcept;
86  /**
87  * Check whether version x is newer than version y.
88  */
89  friend constexpr bool operator > (const Version &x, const Version &y) noexcept;
90  /**
91  * Check whether version x is newer than or the same as version y.
92  */
93  friend constexpr bool operator >= (const Version &x, const Version &y) noexcept;
94  /**
95  * Check whether version x is the same as version y.
96  */
97  friend constexpr bool operator == (const Version &x, const Version &y) noexcept;
98  /**
99  * Check whether version x is not the same as version y.
100  */
101  friend constexpr bool operator != (const Version &x, const Version &y) noexcept;
102 
103  /**
104  * @param buffer is required to be at least 12 bytes long.
105  * Will be write in format "uint8_t.uint8_t.uint8_t" (with trailing '\0').
106  * @return If success, the number of characters writen to buffer (excluding trailing '\0');
107  * If failed, return negative value.
108  */
109  std::size_t to_string(char buffer[12]) const noexcept;
110  };
111 
112  /**
113  * Modification of the variable below is sure not thread-safe.
114  */
116 
117  /**
118  * Result of curl_version_info(CURLVERSION_NOW).
119  * Cached for faster access.
120  */
121  const void * const version_info;
122  /**
123  * Version of the libcurl loaded dynamically.
124  */
126 
127  /**
128  * disable_signal_handling_v is placed here to compress alignment requirement for bool
129  * and Version.
130  *
131  * @pre has_disable_signal_handling_support()
132  *
133  * If your libcurl uses standard name resolver, disable signal handling might cause timeout to never
134  * occur during name resolution.
135  *
136  * Disable signal handling makes libcurl NOT ask the system to ignore SIGPIPE signals, which otherwise
137  * are sent by the system when trying to send data to a socket which is closed in the other end.
138  *
139  * libcurl makes an effort to never cause such SIGPIPEs to trigger, but some operating systems have
140  * no way to avoid them and even on those that have there are some corner cases when they may still happen,
141  * contrary to our desire.
142  *
143  * In addition, using CURLAUTH_NTLM_WB authentication could cause a SIGCHLD signal to be raised.
144  *
145  * Modifing this would only affect Easy_t handle created after the modification.
146  */
148 
149  /**
150  * Version of the libcurl linked dynamically in string.
151  */
152  const char * const version_str;
153 
154  /**
155  * Since curl_t is designed to be usable as static variable,
156  * it would call errx on error.
157  *
158  * It would make sure that Easy_ref_t::get_response_code() is usable before initializing libcurl.
159  * <br>As a side effect, it also make sure that Easy_ref_t::getinfo_sizeof_*, getinfo_transfer_time,
160  * getinfo_effective_url must be present.
161  *
162  * This is not thread-safe.
163  */
164  curl_t(FILE *stderr_stream_arg) noexcept;
165 
166  using malloc_callback_t = void* (*)(std::size_t size);
167  using free_callback_t = void (*)(void *ptr);
168  using realloc_callback_t = void* (*)(void *old_ptr, std::size_t size);
169  using strdup_callback_t = char* (*)(const char *str);
170  using calloc_callback_t = void* (*)(std::size_t nmemb, std::size_t size);
171 
172  /**
173  * If you are using libcurl from multiple threads or libcurl was built
174  * with the threaded resolver option, then the callback functions
175  * must be thread safe.
176  *
177  * The threaded resolver is a common build option to enable
178  * (and in some cases the default) so portable application should make
179  * these callback functions thread safe.
180  *
181  * All callback arguments must be set to valid function pointers.
182  *
183  * libcurl support this from 7.12.0.
184  * <br>If this wasn't supported, you binary probably would have problem
185  * during dynamic binding.
186  * <br>NOTE: as a side effect, it also guarantees curl_t::has_buffer_size_tuning_support()
187  * to be true.
188  *
189  * it would call errx on error.
190  *
191  * It would make sure that Easy_ref_t::get_response_code() is usable before initializing libcurl.
192  * <br>As a side effect, it also make sure that Easy_ref_t::getinfo_sizeof_*, getinfo_transfer_time,
193  * getinfo_effective_url must be present.
194  *
195  * This is not thread-safe.
196  */
197  curl_t(FILE *stderr_stream_arg,
198  malloc_callback_t malloc_callback,
199  free_callback_t free_callback,
200  realloc_callback_t realloc_callback,
201  strdup_callback_t strdup_callback,
202  calloc_callback_t calloc_callback) noexcept;
203 
204  curl_t(const curl_t&) = delete;
205  curl_t(curl_t&&) = delete;
206 
207  curl_t& operator = (const curl_t&) = delete;
208  curl_t& operator = (curl_t&&) = delete;
209 
210  /**
211  * Destructor is not thread safe.
212  *
213  * You must not call it when any other thread in the program
214  * (i.e. a thread sharing the same memory) is running.
215  *
216  * This doesn't just mean no other thread that is using libcurl.
217  * Because curl_global_cleanup calls functions of other libraries that
218  * are similarly thread unsafe, it could conflict with any other thread that
219  * uses these other libraries.
220  *
221  * This dtor does not block waiting for any libcurl-created threads
222  * to terminate (such as threads used for name resolving).
223  *
224  * If a module containing libcurl is dynamically unloaded while
225  * libcurl-created threads are still running then your program
226  * may crash or other corruption may occur.
227  *
228  * We recommend you do not run libcurl from any module that may be
229  * unloaded dynamically.
230  *
231  * This behavior may be addressed in the future.
232  */
233  ~curl_t();
234 
235  bool has_compression_support() const noexcept;
236  bool has_largefile_support() const noexcept;
237  /**
238  * @param protocol should be lower-case
239  */
240  bool has_protocol(const char *protocol) const noexcept;
241  bool has_ssl_support() const noexcept;
242  bool has_ipv6_support() const noexcept;
243 
244  bool has_erase_all_cookies_in_mem_support() const noexcept;
245  bool has_erase_all_session_cookies_in_mem_support() const noexcept;
246  bool has_flush_cookies_to_jar() const noexcept;
247  bool has_reload_cookies_from_file() const noexcept;
248 
249  bool has_disable_signal_handling_support() const noexcept;
250 
251  bool has_private_ptr_support() const noexcept;
252 
253  bool has_readfunc_abort_support() const noexcept;
254  bool has_pause_support() const noexcept;
255 
256  bool has_header_option_support() const noexcept;
257  bool has_set_ip_addr_only_support() const noexcept;
258 
259  bool has_redirect_url_support() const noexcept;
260 
261  bool has_getinfo_cookie_list_support() const noexcept;
262 
263  bool has_buffer_size_tuning_support() const noexcept;
264  bool has_buffer_size_growing_support() const noexcept;
265 
266  bool has_get_active_socket_support() const noexcept;
267 
268  /**
269  * Deleter for curl::curl_t::Easy_t.
270  */
271  struct Easy_deleter {
272  void operator () (void *p) const noexcept;
273  };
274 
275  /**
276  * RAII wrapper for curl's easy handler.
277  */
278  using Easy_t = std::unique_ptr<char, Easy_deleter>;
279  /**
280  * @param buffer_size size of receiver buffer.
281  *
282  * This buffer size is by default CURL_MAX_WRITE_SIZE (16kB).
283  * The maximum buffer size allowed to be set is CURL_MAX_READ_SIZE (512kB).
284  * The minimum buffer size allowed to be set is 1024.
285  *
286  * Set to 0 to use default value.
287  *
288  * This param is just treated as a request, not an order.
289  * @return If == nullptr, then curl_easy cannot be created.
290  * - It can be no memory left;
291  * - Or, initialization code for some part of lib failed.
292  *
293  * If stderr_stream set to non-NULL, verbose info will be printed
294  * there.
295  * If disable_signal_handling_v is set, signal handling is disabled.
296  *
297  * As long as stderr_stream and disable_signal_handling_v is not modified
298  * when create_easy is called, this function is thread-safe.
299  */
300  auto create_easy(std::size_t buffer_size = 0) noexcept -> Easy_t;
301  /**
302  * @param easy must not be nullptr
303  * @param buffer_size same as create_easy
304  * @return same as create_easy
305  *
306  * All string passed into curl_easy_setopt using char* will be pointed by the
307  * new hanlde as well.
308  * Thus they must be kept around until both handles is destroyed.
309  *
310  * The new handle will not inherit any state information, no connections,
311  * no SSL sessions and no cookies.
312  *
313  * It also will not inherit any share object states or options
314  * (it will be made as if CURLOPT_SHARE was set to NULL).
315  *
316  * If stderr_stream set to non-nullptr, verbose info will be printed
317  * there.
318  * If disable_signal_handling_v is set, signal handling is disabled.
319  *
320  * easy must not be used in any way during this function call.
321  */
322  auto dup_easy(const Easy_t &easy, std::size_t buffer_size = 0) noexcept -> Easy_t;
323 
324  /**
325  * has curl::Url support
326  */
327  bool has_CURLU() const noexcept;
328 
329  /**
330  * Deleter for curl::curl_t::Url_t
331  */
332  struct Url_deleter {
333  void operator () (char *p) const noexcept;
334  };
335  /**
336  * RAII wrapper for curl's Url parser.
337  */
338  using Url_t = std::unique_ptr<char, Url_deleter>;
339 
340  /**
341  * @return nullptr if not enough memory.
342  *
343  * Since Url_ref_t doesn't have any other data except pointer to
344  * CURLU itself, returning std::unique_ptr instead of an object like Easy_t
345  * would make it easier to manage it in custom ways like std::shared_ptr.
346  *
347  * It is thread-safe.
348  */
349  auto create_Url() noexcept -> Url_t;
350  /**
351  * @param url != nullptr
352  *
353  * url must not be used during this function call.
354  */
355  auto dup_Url(const Url_t &url) noexcept -> Url_t;
356 
357  bool has_multi_poll_support() const noexcept;
358  bool has_multi_socket_support() const noexcept;
359 
360  /**
361  * http2 multiplex is turn on by default, if supported.
362  */
363  bool has_http2_multiplex_support() const noexcept;
364  bool has_max_concurrent_stream_support() const noexcept;
365 
366  /**
367  * NOTE that http1 pipeline is always disabled.
368  */
369  auto create_multi() noexcept -> Ret_except<Multi_t, curl::Exception>;
370 
371  bool has_ssl_session_sharing_support() const noexcept;
372  bool has_connection_cache_sharing_support() const noexcept;
373  bool has_psl_sharing_support() const noexcept;
374 
375  /**
376  * Deleter for curl::curl_t::Share_t
377  */
378  struct Share_deleter {
379  void operator () (char *p) const noexcept;
380  };
381  /**
382  * RAII wrapper for curl's Share handler.
383  */
384  using Share_t = std::unique_ptr<char, Share_deleter>;
385  /**
386  * Create share handler.
387  *
388  * It is thread-safe.
389  */
390  auto create_share() noexcept -> Share_t;
391 };
392 
393 using Easy_t = curl_t::Easy_t;
394 using Url_t = curl_t::Url_t;
395 using Share_t = curl_t::Share_t;
396 } /* namespace curl */
397 
398 #endif
curl::curl_t::Version::operator>
constexpr friend bool operator>(const Version &x, const Version &y) noexcept
Definition: curl.cc:40
curl::curl_t::Share_deleter
Definition: curl.hpp:378
curl::Exception
Definition: curl.hpp:16
curl::curl_t::version_str
const char *const version_str
Definition: curl.hpp:152
curl::curl_t::Version::operator!=
constexpr friend bool operator!=(const Version &x, const Version &y) noexcept
Definition: curl.cc:52
curl::curl_t::~curl_t
~curl_t()
Definition: curl.cc:265
curl::curl_t::Version::operator==
constexpr friend bool operator==(const Version &x, const Version &y) noexcept
Definition: curl.cc:48
curl::Url_ref_t
Definition: curl_url.hpp:24
curl::curl_t::disable_signal_handling_v
bool disable_signal_handling_v
Definition: curl.hpp:147
curl::curl_t::Url_deleter
Definition: curl.hpp:332
curl::curl_t::has_CURLU
bool has_CURLU() const noexcept
Definition: curl.cc:227
curl::Easy_ref_t
Definition: curl_easy.hpp:53
curl::curl_t::Version::to_string
std::size_t to_string(char buffer[12]) const noexcept
Definition: curl.cc:57
curl::curl_t::dup_Url
auto dup_Url(const Url_t &url) noexcept -> Url_t
Definition: curl_url.cc:15
curl::curl_t::version_info
const void *const version_info
Definition: curl.hpp:121
curl::curl_t::curl_t
curl_t(FILE *stderr_stream_arg) noexcept
Definition: curl.cc:70
curl::Multi_t
Definition: curl_multi.hpp:29
curl::curl_t::create_share
auto create_share() noexcept -> Share_t
Definition: curl_share.cc:10
curl::curl_t::stderr_stream
FILE * stderr_stream
Definition: curl.hpp:115
curl::curl_t
Definition: curl.hpp:62
curl::curl_t::version
const Version version
Definition: curl.hpp:125
curl::NotBuiltIn_error
Definition: curl.hpp:25
curl::curl_t::curl_t
curl_t(FILE *stderr_stream_arg, malloc_callback_t malloc_callback, free_callback_t free_callback, realloc_callback_t realloc_callback, strdup_callback_t strdup_callback, calloc_callback_t calloc_callback) noexcept
Definition: curl.cc:105
curl::Recursive_api_call_Exception
Definition: curl.hpp:40
curl::curl_t::create_Url
auto create_Url() noexcept -> Url_t
Definition: curl_url.cc:11
curl::curl_t::has_http2_multiplex_support
bool has_http2_multiplex_support() const noexcept
Definition: curl.cc:241
curl::Share_base
Definition: curl_share.hpp:21
curl::curl_t::create_multi
auto create_multi() noexcept -> Ret_except< Multi_t, curl::Exception >
Definition: curl_multi.cc:7
curl::curl_t::dup_easy
auto dup_easy(const Easy_t &easy, std::size_t buffer_size=0) noexcept -> Easy_t
Definition: curl_easy.cc:43
curl::curl_t::has_protocol
bool has_protocol(const char *protocol) const noexcept
Definition: curl.cc:136
curl::curl_t::Easy_deleter
Definition: curl.hpp:271
curl::curl_t::Version::operator<=
constexpr friend bool operator<=(const Version &x, const Version &y) noexcept
Definition: curl.cc:36
curl::curl_t::Version::operator<
constexpr friend bool operator<(const Version &x, const Version &y) noexcept
Definition: curl.cc:32
curl::curl_t::Version
Definition: curl.hpp:69
curl::curl_t::Version::operator>=
constexpr friend bool operator>=(const Version &x, const Version &y) noexcept
Definition: curl.cc:44
curl::curl_t::create_easy
auto create_easy(std::size_t buffer_size=0) noexcept -> Easy_t
Definition: curl_easy.cc:20
curl::libcurl_bug
Definition: curl.hpp:32