curl-cpp
static c++17 wrapper for curl with -fno-exceptions support
curl_easy.hpp
1 #ifndef __curl_cpp_curl_easy_HPP__
2 # define __curl_cpp_curl_easy_HPP__
3 
4 # include <cstddef>
5 # include <utility>
6 # include <string>
7 
8 # include "curl.hpp"
9 # include "utils/curl_slist.hpp"
10 
11 # include <curl/curl.h>
12 
13 namespace curl {
14 /**
15  * @example curl_easy_get.cc
16  *
17  * Why make Easy_ref_t RAII-less?
18  *
19  * It would simplify design of Easy_ref_t, since it doesn't need to
20  * implement RAII-part logic.
21  *
22  * It would also make it easier to use member function of Easy_ref_t in Multi_t,
23  * provided that libcurl callback provides CURL* and that option CURLOPT_PRIVATE
24  * which enables storing any object, isn't support until 7.10.3.
25  *
26  * Easy_ref_t's member function cannot be called in multiple threads simultaneously.
27  *
28  * ### PERSISTENT CONNECTIONS
29  *
30  * Persistent connections means that libcurl can re-use the same connection for several transfers,
31  * if the conditions are right.
32  *
33  * libcurl will always attempt to use persistent connections. It will by default, cache 5 connections.
34  *
35  * Whenever you use Easy_ref_t::perform or Multi::perform/Multi::socket_action,
36  * libcurl will attempt to use an existing connection to do the transfer, and if none exists it'll
37  * open a new one that will be subject for re-use on a possible following call to these functions.
38  *
39  * To allow libcurl to take full advantage of persistent connections, you should do
40  * as many of your file transfers as possible using the same handle.
41  *
42  * If you use the easy interface, and the Easy_t get destroyed, all the possibly
43  * open connections held by libcurl will be closed and forgotten.
44  *
45  * When you've created a multi handle and are using the multi interface, the connection pool is
46  * instead kept in the multi handle so closing and creating new easy handles to do transfers
47  * will not affect them.
48  * Instead all added easy handles can take advantage of the single shared pool.
49  *
50  * It can also be archieved by using curl::Share_base or curl::Share and
51  * enable_sharing(Share_base::Options::connection_cache).
52  */
53 class Easy_ref_t {
54 public:
55  char *curl_easy = nullptr;
56 
57  friend Multi_t;
58 
59  /**
60  * Base class for any exception thrown via
61  * Ret_except in this class -- except for
62  * cookie-related function, which can throw
63  * curl::NotBuiltIn_error.
64  */
65  class Exception: public curl::Exception {
66  public:
67  const long error_code;
68 
69  Exception(long err_code_arg);
70  Exception(const Exception&) = default;
71 
72  auto what() const noexcept -> const char*;
73  };
74  /**
75  * It means that
76  *
77  * > A requested feature, protocol or option was not found built-in in this libcurl
78  * > due to a build-time decision.
79  * > This means that a feature or option was not enabled or explicitly disabled
80  * > when libcurl was built and in order to get it to function you have to get a rebuilt libcurl.
81  *
82  * From https://curl.haxx.se/libcurl/c/libcurl-errors.html
83  */
84  class NotBuiltIn_error: public Exception {
85  public:
86  using Exception::Exception;
87  };
88  /**
89  * Internal error in protocol layer.
90  *
91  * If you have error buffer set via set_error_buffer,
92  * you can check that for an in-detail error message.
93  */
95  public:
96  using Exception::Exception;
97  };
98 
99  /**
100  * @param stderr_stream_arg if not null, enable verbose mode and
101  * print them onto stderr_stream_arg.
102  */
103  void set_verbose(FILE *stderr_stream_arg) noexcept;
104 
105  /**
106  * Minimum length for error buffer.
107  */
108  static std::size_t get_error_buffer_size() noexcept;
109 
110  /**
111  * @param buffer either nullptr to disable error buffer,
112  * or at least get_error_buffer_size() big.
113  *
114  * The error buffer must be kept around until call set_error_buffer again
115  * or curl::Easy_t is destroyed.
116  *
117  * The error buffer is only set if ProtocolInternal_error is thrown.
118  */
119  void set_error_buffer(char *error_buffer) noexcept;
120 
121  /**
122  * @pre curl_t::has_private_ptr_support()
123  * @param userp any user-defined pointer. Default to nullptr.
124  */
125  void set_private(void *userp) noexcept;
126  /**
127  * @pre curl_t::has_private_ptr_support()
128  * @return pointer set via set_private or nullptr if not set at all.
129  */
130  void* get_private() const noexcept;
131 
132  /**
133  * @param buffer not null-terminated
134  * @param size at most CURL_MAX_WRITE_SIZE
135  *
136  * @ return if less than size, then it will singal an err cond to libcurl.
137  * <br>This will cause the transfer to get aborted and the libcurl function used will return
138  * code::writeback_error.
139  * <br>If curl_t::has_pause_support() == true, and CURL_WRITEFUNC_PAUSE is returned,
140  * it will cause transfer to be paused.
141  * See curl_easy_pause for more details.
142  *
143  * **It would be undefined behavior to call any easy member function in writeback.**
144  */
145  using writeback_t = std::size_t (*)(char *buffer, std::size_t _, std::size_t size, void *userp);
146 
147  /**
148  * By default, writeback == std::fwrite, userp == stdout
149  */
150  void set_writeback(writeback_t writeback, void *userp) noexcept;
151 
152  /**
153  * @pre curl_t::has_CURLU()
154  * @param url content of it must not be changed during call to perform(),
155  * but can be changed once it is finished.
156  */
157  void set_url(const Url_ref_t &url) noexcept;
158  /**
159  * @param url would be dupped, thus it can be freed up after this function call.
160  */
161  auto set_url(const char *url) noexcept -> Ret_except<void, std::bad_alloc>;
162 
163  /**
164  * @pre url set to use TLS based protocols: HTTPS, FTPS, IMAPS, POP3S, SMTPS etc &&
165  * curl_t::has_protocol(protolcol)
166  *
167  * @param pubkey null-terminated string.
168  * The string can be the file name of your pinned public key.
169  * The file format expected is "PEM" or "DER".
170  * <br>The string can also be any number of base64 encoded
171  * sha256 hashes preceded by "sha256//" and separated by ";".
172  * <br>The application does not have to keep the string around after setting this option.
173  *
174  * @return note that whether this is supported depend on:
175  * - ssl lib
176  * - libcurl version
177  * - whether pubkey is a path to file or sha256.
178  *
179  * When negotiating a TLS or SSL connection, the server sends a certificate indicating its identity.
180  * A public key is extracted from this certificate and if it does not exactly match
181  * the public key provided to this option, curl will abort the connection before sending
182  * or receiving any data.
183  *
184  * On mismatch, code::ssl_pinned_pubkey_mismatch is returned.
185  */
186  auto pin_publickey(const char *pubkey) ->
187  Ret_except<void, std::bad_alloc, curl::NotBuiltIn_error>;
188 
189  /**
190  * @pre url is set to use http(s) && curl_t::has_protocol("http")
191  * @param cookies null-terminated string, in format "name1=content1; name2=content2;"
192  * <br>This string will be strdup-ed and override previous call.
193  * <br>This is defaulted to nullptr.
194  * @return note that libcurl can be built with cookies disabled, thus this library
195  * can return exception curl::NotBuiltIn_error.
196  *
197  * This option sets the cookie header explicitly in the outgoing request(s).
198  * <br>If multiple requests are done due to authentication, followed redirections or similar,
199  * they will all get this cookie passed on.
200  *
201  * The cookies set by this option are separate from the internal cookie storage held
202  * by the cookie engine and will not be modified by it.
203  *
204  * If you enable the cookie engine and either you've imported a cookie of the same name
205  * (e.g. 'foo') or the server has set one, it will have no effect on the cookies you set here.
206  *
207  * A request to the server will send both the 'foo' held by the cookie engine and
208  * the 'foo' held by this option.
209  * <br>To set a cookie that is instead held by the cookie engine and can be modified by the
210  * server use set_cookielist.
211  *
212  * This option will not enable the cookie engine.
213  * Use set_cookiefile or set_cookiejar to enable parsing and sending cookies automatically.
214  */
215  auto set_cookie(const char *cookies) noexcept ->
216  Ret_except<void, std::bad_alloc, curl::NotBuiltIn_error>;
217 
218  /**
219  * @pre url is set to use http(s) && curl_t::has_protocol("http")
220  * @param cookie_filename null-terminte string for the filename of the cookie file;
221  * <br>"" to enable cookie engine without any initial cookies;
222  * <br>"-" to read the cookie from stdin;
223  * <br>Does not have to keep around after this call.
224  * <br>This is default to nullptr.
225  * @return note that libcurl can be built with cookies disabled, thus this library
226  * can return exception curl::NotBuiltIn_error.
227  *
228  * The cookie data can be in either the old Netscape / Mozilla cookie data format or
229  * just regular HTTP headers (Set-Cookie style) dumped to a file.
230  *
231  * It enables the cookie engine, making libcurl parse response and send cookies on
232  * subsequent requests with this handle.
233  *
234  * This function can be used with set_cookielist.
235  *
236  * It only reads cookies right before a transfer is started.
237  * <br>To make libcurl write cookies to file, see set_cookiejar.
238  *
239  * Exercise caution if you are using this option and multiple transfers may occur
240  * due to redirect:
241  *
242  * If you use the Set-Cookie format: "name1=content1; name2=content2;" and don't specify a domain
243  * then
244  * the cookie is sent for any domain (even after redirects are followed)
245  * and cannot be modified by a server-set cookie.
246  *
247  * If a server sets a cookie of the same name then both will be sent
248  * on a future transfer to that server, likely not what you intended.
249  * To address these issues set a domain in Set-Cookie HTTP header
250  * (doing that will include sub-domains) or use the Netscape format:
251  *
252  * char *my_cookie =
253  * "example.com" // Hostname
254  * "\t" "FALSE" // Include subdomains
255  * "\t" "/" // Path
256  * "\t" "FALSE" // Secure
257  * "\t" "0" // Expiry in epoch time format. 0 == Session
258  * "\t" "foo" // Name
259  * "\t" "bar"; // Value
260  *
261  * If you call this function multiple times, you just add more files to read.
262  * Subsequent files will add more cookies.
263  */
264  auto set_cookiefile(const char *cookie_filename) noexcept ->
265  Ret_except<void, curl::NotBuiltIn_error>;
266 
267  /**
268  * @pre url is set to use http(s) && curl_t::has_protocol("http")
269  * @param cookie_filename null-terminated string;
270  * <br>"-" write cookies to stdout;
271  * <br>Does not have to keep around after this call.
272  * <br>This is default to nullptr.
273  * @return note that libcurl can be built with cookies disabled, thus this library
274  * can return exception curl::NotBuiltIn_error.
275  *
276  * This will make libcurl write all internally known cookies to
277  * the specified file when curl::Easy_t is destroyed.
278  *
279  * If no cookies, then no file will be created.
280  *
281  * Using this option also enables cookies for this session, so if you
282  * for example follow a location it will make matching cookies get sent accordingly.
283  *
284  * Note that libcurl doesn't read any cookies from the cookie jar.
285  * <br>If you want to read cookies from a file, use set_cookiefile.
286  *
287  * If the cookie jar file can't be created or written to, libcurl will not
288  * and cannot report an error for this.
289  * <br>Using set_verbose, set curl::stderr_stream to non-null before creating curl::Easy_t
290  * or CURLOPT_DEBUGFUNCTION will get a warning to display,
291  * but that is the only visible feedback you get about this possibly lethal situation.
292  *
293  * Since 7.43.0 cookies that were imported in the Set-Cookie format without
294  * a domain name are not exported by this function.
295  */
296  auto set_cookiejar(const char *cookie_filename) noexcept ->
297  Ret_except<void, std::bad_alloc, curl::NotBuiltIn_error>;
298 
299  /**
300  * @pre url is set to use http(s) && curl_t::has_protocol("http")
301  * @param cookie_filename null-terminte string for the filename of the cookie file;
302  * <br>Does not have to keep around after this call.
303  * <br>This is default to nullptr.
304  * @return note that libcurl can be built with cookies disabled, thus this library
305  * can return exception curl::NotBuiltIn_error.
306  *
307  * The cookie will be immediately loaded, and this function can be mixed with
308  * set_cookiefile.
309  *
310  * Such a cookie can be either a single line in Netscape / Mozilla format or
311  * just regular HTTP-style header (Set-Cookie: ...) format.
312  *
313  * This will also enable the cookie engine and adds that single cookie
314  * to the internal cookie store.
315  *
316  * Exercise caution if you are using this option and multiple transfers may occur
317  * due to redirect:
318  *
319  * If you use the Set-Cookie format: "name1=content1; name2=content2;" and don't specify a domain
320  * then
321  * the cookie is sent for any domain (even after redirects are followed)
322  * and cannot be modified by a server-set cookie.
323  *
324  * If a server sets a cookie of the same name then both will be sent
325  * on a future transfer to that server, likely not what you intended.
326  * To address these issues set a domain in Set-Cookie HTTP header
327  * (doing that will include sub-domains) or use the Netscape format:
328  *
329  * char *my_cookie =
330  * "example.com" // Hostname
331  * "\t" "FALSE" // Include subdomains
332  * "\t" "/" // Path
333  * "\t" "FALSE" // Secure
334  * "\t" "0" // Expiry in epoch time format. 0 == Session
335  * "\t" "foo" // Name
336  * "\t" "bar"; // Value
337  *
338  */
339  auto set_cookielist(const char *cookie) noexcept ->
340  Ret_except<void, std::bad_alloc, curl::NotBuiltIn_error>;
341 
342  /**
343  * @pre url is set to use http(s) && curl_t::has_protocol("http")
344  *
345  * It will force libcurl to ignore all cookies it is about to load that
346  * are "session cookies" from the previous session.
347  *
348  * Session cookies are cookies without expiry date and they are meant
349  * to be alive and existing for this "session" only.
350  *
351  * A "session" is usually defined in browser land for as long as
352  * you have your browser up, more or less.
353  *
354  * By default, libcurl always stores and loads all cookies, independent
355  * if they are session cookies or not.
356  *
357  * NOTE that cookie support can be removed in compile time of libcurl, there is
358  * no guarantee this would work.
359  */
360  void start_new_cookie_session() noexcept;
361 
362  /**
363  * @pre url is set to use http(s) && curl_t::has_protocol("http") &&
364  * curl_t::has_erase_all_cookies_in_mem_support().
365  * @return note that libcurl can be built with cookies disabled, thus this library
366  * can return exception curl::NotBuiltIn_error.
367  */
368  auto erase_all_cookies_in_mem() noexcept ->
369  Ret_except<void, std::bad_alloc, curl::NotBuiltIn_error>;
370 
371  /**
372  * @pre url is set to use http(s) && curl_t::has_protocol("http") &&
373  * curl_t::has_erase_all_session_cookies_in_mem_support()
374  * @return note that libcurl can be built with cookies disabled, thus this library
375  * can return exception curl::NotBuiltIn_error.
376  *
377  * Session cookies are cookies without expiry date and they are meant
378  * to be alive and existing for this "session" only.
379  *
380  * A "session" is usually defined in browser land for as long as
381  * you have your browser up, more or less.
382  */
383  auto erase_all_session_cookies_in_mem() noexcept ->
384  Ret_except<void, std::bad_alloc, curl::NotBuiltIn_error>;
385 
386  /**
387  * @pre url is set to use http(s) && curl_t::has_protocol("http") &&
388  * curl_t::has_flush_cookies_to_jar()
389  * @return note that libcurl can be built with cookies disabled, thus this library
390  * can return exception curl::NotBuiltIn_error.
391  *
392  * writes all known cookies to the file specified by set_cookiejar.
393  */
394  auto flush_cookies_to_jar() noexcept ->
395  Ret_except<void, std::bad_alloc, curl::NotBuiltIn_error>;
396 
397  /**
398  * @pre url is set to use http(s) && curl_t::has_protocol("http") &&
399  * curl_t::has_reload_cookies_from_file()
400  * @return note that libcurl can be built with cookies disabled, thus this library
401  * can return exception curl::NotBuiltIn_error.
402  *
403  * loads all cookies from the files specified by set_cookiefile.
404  */
405  auto reload_cookies_from_file() noexcept ->
406  Ret_except<void, std::bad_alloc, curl::NotBuiltIn_error>;
407 
408  /**
409  * @pre url is set to use http(s) && curl_t::has_protocol("http")
410  * @param redir set to 0 to disable redirection.
411  * set to -1 to allow infinite number of redirections.
412  * Other number enables redir number of redirections.
413  */
414  void set_follow_location(long redir) noexcept;
415 
416  /**
417  * @pre url is set to use http(s) && curl_t::has_protocol("http")
418  * @param useragent pass nullptr for no useragent (default)
419  */
420  auto set_useragent(const char *useragent) noexcept -> Ret_except<void, std::bad_alloc>;
421  /**
422  * @pre url is set to use http(s) && curl_t::has_protocol("http")
423  * @param encoding "" for enable all (default);
424  * nullptr for disable all (including auto decompression).
425  */
426  auto set_encoding(const char *encoding) noexcept -> Ret_except<void, std::bad_alloc>;
427 
428  /**
429  * @param value can be ipv4 or ipv6 address/hostname/interface.
430  * If it is nullptr, then set to whatever TCP stack find available (default).
431  */
432  auto set_interface(const char *value) noexcept -> Ret_except<void, std::bad_alloc>;
433 
434  /**
435  * @pre curl_t::has_set_ip_addr_only_support()
436  * @param ip_addr ipv4/ipv6 address
437  * If it is nullptr, then set to whatever TCP stack find available (default).
438  */
439  auto set_ip_addr_only(const char *ip_addr) noexcept -> Ret_except<void, std::bad_alloc>;
440 
441  /**
442  * @param timeout in milliseconds. Set to 0 to disable (default);
443  * should be less than std::numeric_limits<long>::max().
444  */
445  void set_timeout(unsigned long timeout) noexcept;
446 
447  enum class header_option {
448  /**
449  * If unspecified is passed to set_http_header, then the
450  * previous header_option (or default) will be used.
451  *
452  * If curl_t::has_header_option_support() == false, then
453  * it is default to unified.
454  *
455  * Before 7.42.1, default is unified.
456  * After 7.42.1, default is separate.
457  */
458  unspecified,
459  /**
460  * The following options only take effect when
461  * curl_t::has_header_option_support() == true.
462  */
463  unified, // header specified with set_http_header will also be used for proxy
464  separate, // reverse of unified
465  };
466  /**
467  * @pre url is set to use http(s)
468  * @param l will not be copied, thus it is required to be kept
469  * around until another set_http_header is issued or
470  * this Easy_t is destroyed.
471  *
472  * Must not be CRLF-terminated.
473  * @param option control whether header set here will also sent to
474  * proxy
475  *
476  * Example:
477  * - Replace hedaer 'Accept:'
478  *
479  * utils::slist l;
480  * l.push_back("Accept: deflate");
481  * easy.set_http_header(l);
482  *
483  * - Remove header 'Accept:'
484  *
485  * easy.set_http_header(utils::slist{});
486  *
487  * Starting in 7.58.0, libcurl will specifically prevent
488  * "Authorization:" headers from being sent to hosts other
489  * than the first used one, unless specifically permitted
490  * with the CURLOPT_UNRESTRICTED_AUTH option.
491  *
492  * Starting in 7.64.0, libcurl will specifically prevent
493  * "Cookie:" headers from being sent to hosts other than
494  * the first used one, unless specifically permitted with
495  * the CURLOPT_UNRESTRICTED_AUTH option.
496  */
497  void set_http_header(const utils::slist &l, header_option option = header_option::unspecified) noexcept;
498 
499  /**
500  * @param enable if true, then it would not request body data to be transfered;
501  * if false, then a normal request (default).
502  */
503  void set_nobody(bool enable) noexcept;
504 
505  /**
506  * @pre url is set to use http(s) && curl_t::has_protocol("http")
507  *
508  * This is the default for http, and would also set_nobody(false).
509  */
510  void request_get() noexcept;
511  /**
512  * @pre url is set to use http(s) && curl_t::has_protocol("http")
513  * @param len if set to -1, then libcurl would strlen(data) to determine its length.
514  *
515  * The data pointed to is NOT copied by the library: as a consequence, it must be preserved by
516  * the calling application until the associated transfer finishes.
517  */
518  void request_post(const void *data, std::size_t len) noexcept;
519 
520  /**
521  * The length of buffer is size * nitems.
522  *
523  * @return bytes writen to the buffer.
524  * <br>0 to signal end-of-file to the library and cause it to stop the current transfer.
525  * <br>CURL_READFUNC_ABORT (requires curl_t::has_readfunc_abort_support()) to
526  * stop immediately, result code::aborted_by_callback.
527  * <br>If curl_t::has_pause_support() == true, and CURL_READFUNC_PAUSE is returned,
528  * it would cause reading from this connection to pause.
529  * See curl_easy_pause for further details.
530  * <br>Bugs: when doing TFTP uploads, you must return the exact amount of data that
531  * the callback wants, or it will be considered the final packet by the server end and
532  * the transfer will end there.
533  *
534  * If you stop the current transfer by returning 0 "pre-maturely"
535  * (i.e before the server expected it, like when you've said you will
536  * upload N bytes and you upload less than N bytes), you may experience
537  * that the server "hangs" waiting for the rest of the data that won't come.
538  */
539  using readback_t = std::size_t (*)(char *buffer, std::size_t size, std::size_t nitems, void *userp);
540 
541  /**
542  * @pre url is set to use http(s) && curl_t::has_protocol("http")
543  * @param len optional. Set to -1 means length of data is not known ahead of time.
544  */
545  void request_post(readback_t readback, void *userp, std::size_t len = -1) noexcept;
546 
547  /**
548  * @pre curl_t::has_protocol(protocol you use in url)
549  * @exception NotSupported_error, std::bad_alloc or any exception defined in this class
550  */
551  enum class code {
552  ok = 0,
553  unsupported_protocol,
554  url_malformat,
555  cannot_resolve_proxy,
556  cannot_resolve_host,
557  cannot_connect, // Cannot connect to host or proxy
558  remote_access_denied,
559  writeback_error,
560  upload_failure, // Failed starting the upload
561  timedout,
562  aborted_by_callback, // If readback return CURL_READFUNC_ABORT.
563  too_many_redirects,
564  ssl_pinned_pubkey_mismatch,
565  };
566  using perform_ret_t = Ret_except<code, std::bad_alloc, std::invalid_argument, std::length_error,
569 
570  auto perform() noexcept -> perform_ret_t;
571 
572  enum class PauseOptions {
573  /**
574  * Pause receiving data.
575  * <br>There will be no data received on this connection until this function is called again
576  * without this bit set.
577  * <br>Thus, the writeback won't be called.
578  */
579  recv = 1 << 0,
580  /**
581  * Pause sending data.
582  * <br>There will be no data sent on this connection until this function is called again
583  * without this bit set.
584  * <br>Thus, the readback won't be called/the data registered with request_post won't be copied.
585  */
586  send = 1 << 2, // Make value of pause_send the same as stock libcurl
587  /**
588  * Convenience define that pauses both directions.
589  */
590  all = recv | send,
591  /**
592  * Convenience define that unpauses both directions.
593  */
594  cont = 0,
595  };
596 
597  /**
598  * @pre curl_t::has_pause_support() and there's an ongoing transfer
599  * @return If no exception is thrown, then it is either code::ok or code::writeback_error.
600  *
601  * **The pausing of transfers does not work with protocols that work without
602  * network connectivity, like FILE://.
603  * Trying to pause such a transfer, in any direction, will cause problems in the worst case
604  * or an error in the best case.**
605  *
606  * ### Use of set_pause with multi_socket_action interface
607  *
608  * Before libcurl 7.32.0, when a specific handle was unpaused with this function,
609  * there was no particular forced rechecking or similar of the socket's state,
610  * which made the continuation of the transfer get delayed until next multi-socket call invoke
611  * or even longer.
612  * <br>Alternatively, the user could forcibly call for example curl_multi_socket_all -
613  * with a rather hefty performance penalty.
614  *
615  * Starting in libcurl 7.32.0, unpausing a transfer will schedule a timeout trigger for that handle
616  * 1 millisecond into the future, so that a curl_multi_socket_action( ... CURL_SOCKET_TIMEOUT) can be used
617  * immediately afterwards to get the transfer going again as desired.
618  *
619  * If you use multi interface, you can use multi_socket_action to have a more in-detail
620  * control of pausing the easy.
621  *
622  * ### MEMORY USE
623  *
624  * When pausing a read by returning the magic return code from a write callback, the read data
625  * is already in libcurl's internal buffers so it'll have to keep it in an allocated buffer
626  * until the reading is again unpaused using this function.
627  *
628  * If the downloaded data is compressed and is asked to get uncompressed automatically on download,
629  * libcurl will continue to uncompress the entire downloaded chunk and it will cache the data uncompressed.
630  * This has the side-effect that if you download something that is compressed a lot, it can result in a
631  * very large amount of data required to be allocated to be kept around during the pause.
632  *
633  * This said, you should probably consider not using paused reading if you allow libcurl to
634  * uncompress data automatically.
635  */
636  auto set_pause(PauseOptions option) noexcept -> Ret_except<code, std::bad_alloc, Exception>;
637 
638  long get_response_code() const noexcept;
639 
640  /**
641  * @pre url is set to use http(s) && curl_t::has_protocol("http")
642  * @return size of issued request headers in bytes, including headers sent in redirection.
643  */
644  std::size_t getinfo_sizeof_request() const noexcept;
645  /**
646  * @return in bytes
647  */
648  std::size_t getinfo_sizeof_uploaded() const noexcept;
649  /**
650  * @return in bytes
651  */
652  std::size_t getinfo_sizeof_response_header() const noexcept;
653  /**
654  * @return in bytes, does not include response from redirection
655  */
656  std::size_t getinfo_sizeof_response_body() const noexcept;
657 
658  /**
659  * @return transfer time in ms
660  *
661  * What transfer time really measures:
662  *
663  * |
664  * |--NAMELOOKUP
665  * |--|--CONNECT
666  * |--|--|--APPCONNECT
667  * |--|--|--|--PRETRANSFER
668  * |--|--|--|--|--STARTTRANSFER
669  * |--|--|--|--|--|--transfer time
670  * |--|--|--|--|--|--REDIRECT
671  */
672  std::size_t getinfo_transfer_time() const noexcept;
673 
674  /**
675  * @pre curl_t::has_redirect_url_support() &&
676  * url is set to use http(s) && curl_t::has_protocol("http")
677  * @return null-terminated string, freeing not required.
678  * <br>Would be freed up when corresponding curl::Easy_t is destroyed.
679  * <br>If not supported, would return nullptr.
680  *
681  * If you disable redirection or CURLOPT_MAXREDIRS limit
682  * prevented a redirect to happen (since 7.54.1),
683  * a would-be redirect-to url is returned.
684  *
685  * This function is only meaningful for http(s) protocol.
686  */
687  auto getinfo_redirect_url() const noexcept -> const char*;
688 
689  /**
690  * @pre url is set to use http(s) && curl_t::has_protocol("http")
691  * @return null-terminated string, freeing not required.
692  * <br>Would be freed up when corresponding curl::Easy_t is destroyed.
693  * <br>If not supported, would return nullptr.
694  *
695  * It might be the url you set or the redirected actual url.
696  */
697  auto getinfo_effective_url() const noexcept -> const char*;
698 
699  /**
700  * @pre url is set to use http(s) && curl_t::has_protocol("http") &&
701  * curl_t::has_getinfo_cookie_list_support()
702  *
703  * @return note that libcurl can be built with cookies disabled, thus this library
704  * can return exception curl::NotBuiltIn_error.
705  * If utils::slist is empty, it might be due to std::bad_alloc, or
706  * no cookie is present(cookie engine not enabled or no cookie has
707  * received).
708  *
709  * Since 7.43.0 cookies that were imported in the Set-Cookie format
710  * without a domain name are not exported by this option.
711  */
712  auto getinfo_cookie_list() const noexcept ->
713  Ret_except<utils::slist, curl::NotBuiltIn_error>;
714 
715  /**
716  * @pre curl_t::has_get_active_socket_support()
717  * @return CURL_SOCKET_BAD if no valid socket or not supported
718  *
719  * The return value can be used in Multi_t::multi_assign()
720  */
721  auto get_active_socket() const noexcept -> curl_socket_t;
722 
723  // High-level functions
724 
725  /**
726  * set_readall_callback() can be used for get or post.
727  */
728  template <class String>
729  auto set_readall_writeback(String &response) noexcept
730  {
731  set_writeback([](char *buffer, std::size_t _, std::size_t size, void *ptr) {
732  auto &response = *static_cast<String*>(ptr);
733  response.append(buffer, buffer + size);
734  return size;
735  }, &response);
736  }
737 
738  /**
739  * set_read_callback() can be used for get or post.
740  *
741  * This function will set writeback to only write arg.second bytes into
742  * arg.first.
743  */
744  template <class String, class size_type>
745  auto set_read_writeback(std::pair<String, size_type> &arg) noexcept
746  {
747  set_writeback([](char *buffer, std::size_t _, std::size_t size, void *ptr) {
748  auto &args = *static_cast<std::pair<String, size_type>*>(ptr);
749  auto &response = args.first;
750  auto &requested_len = args.second;
751 
752  auto str_size = response.size();
753  if (str_size < requested_len)
754  response.append(buffer, buffer + std::min(size, requested_len - str_size));
755 
756  return size;
757  }, &arg);
758  }
759 
760  /**
761  * After this call, Easy_ref_t::perform/Multi_t::perform or multi_socket_action must be
762  * called to establish the connection.
763  *
764  * To use the established connection, call set_nobody(false) or request_*()
765  * to disable nobody.
766  *
767  * Example usage:
768  *
769  * int main(int argc, char* argv[]) {
770  * curl::curl_t curl{nullptr};
771  *
772  * auto easy = curl.create_easy();
773  * assert(easy.p1 && easy.p2);
774  *
775  * auto easy_ref = curl::Easy_ref_t{easy};
776  * easy_ref.set_url("https://www.google.com");
777  *
778  * setup_establish_connection_only();
779  * easy_ref.perform(); // Establish the connection
780  *
781  * request_get();
782  * easy_ref.perform(); // Now result is writen to stdout.
783  * }
784  */
785  void setup_establish_connection_only() noexcept;
786 
787 protected:
788  static auto check_perform(long code, const char *fname) noexcept -> perform_ret_t;
789 };
790 } /* namespace curl */
791 
792 #endif
curl::Easy_ref_t::ProtocolInternal_error
Definition: curl_easy.hpp:94
curl::Easy_ref_t::PauseOptions::recv
@ recv
curl::Easy_ref_t::set_url
auto set_url(const char *url) noexcept -> Ret_except< void, std::bad_alloc >
Definition: curl_easy.cc:101
curl::Easy_ref_t::erase_all_session_cookies_in_mem
auto erase_all_session_cookies_in_mem() noexcept -> Ret_except< void, std::bad_alloc, curl::NotBuiltIn_error >
Definition: curl_easy.cc:169
curl::Easy_ref_t::set_cookielist
auto set_cookielist(const char *cookie) noexcept -> Ret_except< void, std::bad_alloc, curl::NotBuiltIn_error >
Definition: curl_easy.cc:149
curl::Easy_ref_t::setup_establish_connection_only
void setup_establish_connection_only() noexcept
Definition: curl_easy.cc:377
curl::Easy_ref_t::set_verbose
void set_verbose(FILE *stderr_stream_arg) noexcept
Definition: curl_easy.cc:64
curl::Easy_ref_t::set_useragent
auto set_useragent(const char *useragent) noexcept -> Ret_except< void, std::bad_alloc >
Definition: curl_easy.cc:194
curl::Exception
Definition: curl.hpp:16
curl::Easy_ref_t::reload_cookies_from_file
auto reload_cookies_from_file() noexcept -> Ret_except< void, std::bad_alloc, curl::NotBuiltIn_error >
Definition: curl_easy.cc:179
curl::Easy_ref_t::getinfo_effective_url
auto getinfo_effective_url() const noexcept -> const char *
Definition: curl_easy.cc:353
curl::Easy_ref_t::set_follow_location
void set_follow_location(long redir) noexcept
Definition: curl_easy.cc:185
curl::Easy_ref_t::set_cookie
auto set_cookie(const char *cookies) noexcept -> Ret_except< void, std::bad_alloc, curl::NotBuiltIn_error >
Definition: curl_easy.cc:120
curl::Easy_ref_t::getinfo_sizeof_uploaded
std::size_t getinfo_sizeof_uploaded() const noexcept
Definition: curl_easy.cc:310
curl::Url_ref_t
Definition: curl_url.hpp:24
curl::Easy_ref_t::set_ip_addr_only
auto set_ip_addr_only(const char *ip_addr) noexcept -> Ret_except< void, std::bad_alloc >
Definition: curl_easy.cc:210
curl::Easy_ref_t::getinfo_redirect_url
auto getinfo_redirect_url() const noexcept -> const char *
Definition: curl_easy.cc:347
curl::Easy_ref_t::NotBuiltIn_error
Definition: curl_easy.hpp:84
curl::Easy_ref_t::request_get
void request_get() noexcept
Definition: curl_easy.cc:250
curl::Easy_ref_t::get_error_buffer_size
static std::size_t get_error_buffer_size() noexcept
Definition: curl_easy.cc:71
curl::Easy_ref_t::request_post
void request_post(const void *data, std::size_t len) noexcept
Definition: curl_easy.cc:254
curl::Easy_ref_t::set_encoding
auto set_encoding(const char *encoding) noexcept -> Ret_except< void, std::bad_alloc >
Definition: curl_easy.cc:199
curl::Easy_ref_t::header_option::unspecified
@ unspecified
curl::Easy_ref_t
Definition: curl_easy.hpp:53
curl::Easy_ref_t::header_option
header_option
Definition: curl_easy.hpp:447
curl::Easy_ref_t::set_read_writeback
auto set_read_writeback(std::pair< String, size_type > &arg) noexcept
Definition: curl_easy.hpp:745
curl::Easy_ref_t::flush_cookies_to_jar
auto flush_cookies_to_jar() noexcept -> Ret_except< void, std::bad_alloc, curl::NotBuiltIn_error >
Definition: curl_easy.cc:174
curl::utils::slist
Definition: curl_slist.hpp:21
curl::Easy_ref_t::set_pause
auto set_pause(PauseOptions option) noexcept -> Ret_except< code, std::bad_alloc, Exception >
Definition: curl_easy.cc:278
curl::Easy_ref_t::erase_all_cookies_in_mem
auto erase_all_cookies_in_mem() noexcept -> Ret_except< void, std::bad_alloc, curl::NotBuiltIn_error >
Definition: curl_easy.cc:164
curl::Easy_ref_t::set_interface
auto set_interface(const char *value) noexcept -> Ret_except< void, std::bad_alloc >
Definition: curl_easy.cc:205
curl::Easy_ref_t::getinfo_transfer_time
std::size_t getinfo_transfer_time() const noexcept
Definition: curl_easy.cc:336
curl::Multi_t
Definition: curl_multi.hpp:29
curl::Easy_ref_t::getinfo_cookie_list
auto getinfo_cookie_list() const noexcept -> Ret_except< utils::slist, curl::NotBuiltIn_error >
Definition: curl_easy.cc:360
curl::Easy_ref_t::pin_publickey
auto pin_publickey(const char *pubkey) -> Ret_except< void, std::bad_alloc, curl::NotBuiltIn_error >
Definition: curl_easy.cc:107
curl::Easy_ref_t::set_private
void set_private(void *userp) noexcept
Definition: curl_easy.cc:80
curl::Easy_ref_t::set_cookiefile
auto set_cookiefile(const char *cookie_filename) noexcept -> Ret_except< void, curl::NotBuiltIn_error >
Definition: curl_easy.cc:131
curl::NotBuiltIn_error
Definition: curl.hpp:25
curl::Easy_ref_t::Exception
Definition: curl_easy.hpp:65
curl::Easy_ref_t::code
code
Definition: curl_easy.hpp:551
curl::Easy_ref_t::set_url
void set_url(const Url_ref_t &url) noexcept
Definition: curl_easy.cc:97
curl::Recursive_api_call_Exception
Definition: curl.hpp:40
curl::Easy_ref_t::set_timeout
void set_timeout(unsigned long timeout) noexcept
Definition: curl_easy.cc:226
curl::Easy_ref_t::header_option::unified
@ unified
curl::Easy_ref_t::set_writeback
void set_writeback(writeback_t writeback, void *userp) noexcept
Definition: curl_easy.cc:91
curl::Easy_ref_t::request_post
void request_post(readback_t readback, void *userp, std::size_t len=-1) noexcept
Definition: curl_easy.cc:259
curl::Easy_ref_t::getinfo_sizeof_response_header
std::size_t getinfo_sizeof_response_header() const noexcept
Definition: curl_easy.cc:320
curl::Easy_ref_t::start_new_cookie_session
void start_new_cookie_session() noexcept
Definition: curl_easy.cc:160
curl::Easy_ref_t::set_nobody
void set_nobody(bool enable) noexcept
Definition: curl_easy.cc:245
curl::Easy_ref_t::set_readall_writeback
auto set_readall_writeback(String &response) noexcept
Definition: curl_easy.hpp:729
curl::Easy_ref_t::set_cookiejar
auto set_cookiejar(const char *cookie_filename) noexcept -> Ret_except< void, std::bad_alloc, curl::NotBuiltIn_error >
Definition: curl_easy.cc:138
curl::Easy_ref_t::getinfo_sizeof_response_body
std::size_t getinfo_sizeof_response_body() const noexcept
Definition: curl_easy.cc:326
curl::Easy_ref_t::get_active_socket
auto get_active_socket() const noexcept -> curl_socket_t
Definition: curl_easy.cc:370
curl::Easy_ref_t::PauseOptions::all
@ all
curl::Easy_ref_t::set_error_buffer
void set_error_buffer(char *error_buffer) noexcept
Definition: curl_easy.cc:75
curl::Easy_ref_t::set_http_header
void set_http_header(const utils::slist &l, header_option option=header_option::unspecified) noexcept
Definition: curl_easy.cc:231
curl::Easy_ref_t::PauseOptions::cont
@ cont
curl::Easy_ref_t::PauseOptions::send
@ send
curl::Easy_ref_t::get_private
void * get_private() const noexcept
Definition: curl_easy.cc:84
curl::Easy_ref_t::PauseOptions
PauseOptions
Definition: curl_easy.hpp:572
curl::Easy_ref_t::getinfo_sizeof_request
std::size_t getinfo_sizeof_request() const noexcept
Definition: curl_easy.cc:304