1 #pragma once
2 
3 /// @file
4 /// @brief Include for the @ref coeurl::Request
5 
6 #include <functional>
7 #include <string>
8 
9 #include <curl/curl.h>
10 
11 #include "headers.hpp"
12 
13 namespace coeurl {
14 struct Client;
15 
16 /// @brief A HTTP request.
17 ///
18 /// Can be sent using a @ref Client
19 /// You can listen to various events here and access the response, after it
20 /// finished.
21 struct Request {
22     //! The different HTTP methods.
23     enum class Method {
24         Delete,  //!< HTTP DELETE
25         Get,     //!< HTTP GET
26         Head,    //!< HTTP HEAD
27         Options, //!< HTTP OPTIONS
28         Patch,   //!< HTTP PATCH
29         Post,    //!< HTTP POST
30         Put,     //!< HTTP PUT
31     };
32 
33     /// @brief construct a new request to @a url.
34     /// @param url The URL to request.
35     /// @param client The client to use.
36     /// @param method The http method for this request. Usually GET.
37     Request(Client *client, Method method, std::string url);
38     //! Cleans up a request.
39     ~Request();
40     //! Uncopyable
41     Request(Request const &) = delete;
42     //! Uncopyable
43     void operator=(Request const &) = delete;
44     //! Unmoveable
45     Request(Request &&) = delete;
46     //! Unmoveable
47     void operator=(Request &&) = delete;
48 
49     //! The maximum number of redirects. Defaults to 0.
50     Request &max_redirects(long amount);
51     //! Whether to verify the certificate of the peer. Defaults to whatever is
52     //! set on the client (usually true).
53     Request &verify_peer(bool verify);
54     //! The actual request body. \a contenttype defaults to
55     //! "application/octet-stream".
56     Request &request(std::string r, std::string contenttype = "application/octet-stream");
57     /// @brief Headers for this request.
58     /// @sa request_headers
59     Request &request_headers(const Headers &h);
60     //! Timeout connection after the specified amount of seconds, if the server
61     //! stops sending acks.
62     Request &connection_timeout(long t);
63 
64     //! Optional completion handler.
65     Request &on_complete(const std::function<void(const Request &)> handler);
66     //! Optional upload progress handler.
67     Request &on_upload_progress(std::function<void(size_t progress, size_t total)> handler);
68     //! Optional download progress handler.
69     Request &on_download_progess(std::function<void(size_t progress, size_t total)> handler);
70 
71     //! The url for this request.
urlcoeurl::Request72     std::string_view url() const { return url_; }
73     //! The response in this request.
responsecoeurl::Request74     std::string_view response() const { return response_; }
75     //! The HTTP response code. 200 for success.
76     int response_code() const;
77     //! The curl error code. CURLE_OK (0) on success.
error_codecoeurl::Request78     CURLcode error_code() const { return curl_error; }
79     /// @brief Headers for the response
80     /// @sa request_headers
response_headerscoeurl::Request81     Headers response_headers() const { return response_headers_; }
82 
83   private:
84     /* CURLOPT_WRITEFUNCTION */
85     static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data);
86     /* CURLOPT_READFUNCTION */
87     static size_t read_cb(char *buffer, size_t size, size_t nitems, void *data);
88     /* CURLOPT_HEADERFUNCTION */
89     static size_t header_cb(char *buffer, size_t size, size_t nitems, void *data);
90     /* CURLOPT_PROGRESSFUNCTION */
91     static int prog_cb(void *p, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ult, curl_off_t uln);
92 
93     CURL *easy;
94     std::string request_;
95     std::string request_contenttype_;
96     std::string response_;
97     std::string url_;
98     Headers response_headers_;
99     curl_slist *request_headers_ = nullptr;
100 
101     Client *global;
102     size_t readoffset = 0;
103     char error[CURL_ERROR_SIZE];
104 
105     enum class Status {
106         Running,
107         Canceled,
108         Done,
109     } status = Status::Running;
110     CURLcode curl_error = CURLcode::CURLE_OK;
111     Method method = Method::Get;
112 
113     long connection_timeout_ = 0;
114 
115     std::function<void(const Request &)> on_complete_;
116     std::function<void(size_t progress, size_t total)> on_upload_progress_, on_download_progess_;
117 
118     friend Client;
119 };
120 } // namespace coeurl
121