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
13namespace coeurl {
14struct 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.
21struct 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 response_headers() const
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.
72 std::string_view url() const { return url_; }
73 //! The response in this request.
74 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.
78 CURLcode error_code() const { return curl_error; }
79 /// @brief Headers for the response
80 /// @sa request_headers(const Headers &)
81 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