Kurlyk
Loading...
Searching...
No Matches
HttpClient.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef KURLYK_HEADER_KURLYK_HTTP_HTTP_CLIENT_HPP_INCLUDED
3#define KURLYK_HEADER_KURLYK_HTTP_HTTP_CLIENT_HPP_INCLUDED
4
7
8#if KURLYK_AUTH_SUPPORT
10#endif
11
12namespace kurlyk {
13
17 class HttpClient {
18 public:
19
25
33
34 HttpClient(const HttpClient&) = delete;
35 HttpClient& operator=(const HttpClient&) = delete;
38
47
53 auto& worker = core::NetworkWorker::get_instance();
54 auto& manager = HttpRequestManager::get_instance();
55 const uint64_t group_id = m_request.group_id;
56 if (worker.is_worker_thread()) {
57 // On the worker thread: execute cancellation inline to avoid self-deadlock.
58 manager.cancel_requests_by_group_id(group_id, nullptr);
59 worker.process();
60 return;
61 }
62 auto promise = std::make_shared<std::promise<void>>();
63 auto future = promise->get_future();
64 manager.cancel_requests_by_group_id(group_id, [promise](){
65 try {
66 promise->set_value();
67 } catch (const std::future_error& e) {
68 if (e.code() == std::make_error_condition(std::future_errc::promise_already_satisfied)) {
69 KURLYK_HANDLE_ERROR(e, "Promise already satisfied in HttpClient::request callback");
70 } else {
71 KURLYK_HANDLE_ERROR(e, "Future error in HttpClient::request callback");
72 }
73 } catch (const std::exception& e) {
74 KURLYK_HANDLE_ERROR(e, "Unhandled exception in HttpClient::request callback");
75 } catch (...) {
76 // Unknown fatal error in request callback
77 }
78 });
79 worker.notify();
80 try {
81 future.get();
82 } catch (const std::exception& e) {
83 KURLYK_HANDLE_ERROR(e, "cancel_requests() future.get() failed");
84 }
85 }
86
92 auto& worker = core::NetworkWorker::get_instance();
93 if (worker.is_worker_thread()) {
94 throw std::logic_error("HttpClient::wait_requests() must not be called from the network worker thread");
95 }
96 auto future = make_wait_requests_future(nullptr);
97 worker.notify();
98 try {
99 future.get();
100 } catch (const std::exception& e) {
101 KURLYK_HANDLE_ERROR(e, "wait_requests() future.get() failed");
102 }
103 }
104
109 bool wait_requests_for(std::chrono::milliseconds timeout) {
110 auto& worker = core::NetworkWorker::get_instance();
111 if (worker.is_worker_thread()) {
112 return false;
113 }
114 uint64_t waiter_id = 0;
115 auto future = make_wait_requests_future(&waiter_id);
116 worker.notify();
117 if (future.wait_for(timeout) == std::future_status::timeout) {
120 waiter_id);
121 return false;
122 }
123 try {
124 future.get();
125 } catch (const std::exception& e) {
126 KURLYK_HANDLE_ERROR(e, "wait_requests_for() future.get() failed");
127 return false;
128 }
129 return true;
130 }
131
140 std::lock_guard<std::mutex> lock(m_submit_mutex);
142 }
143
146 std::size_t max_in_flight() const {
147 std::lock_guard<std::mutex> lock(m_submit_mutex);
148 return m_max_in_flight;
149 }
150
157
161 auto& instance = HttpRequestManager::get_instance();
162
163 switch (type) {
166 instance.remove_limit(m_request.general_rate_limit);
167 }
170 break;
171
174 instance.remove_limit(m_request.specific_rate_limit);
175 }
178 break;
179 }
180 }
181
184 void set_host(const std::string& host) {
185 m_host = host;
186 }
187
190 void set_headers(const kurlyk::Headers& headers) {
191 m_request.headers = headers;
192 }
193
194#if KURLYK_AUTH_SUPPORT
202 void set_auth_provider(std::shared_ptr<http::auth::IAuthProvider> provider) {
203 m_auth_provider = provider;
204 }
205
207 void clear_auth_provider() {
208 m_auth_provider.reset();
209 }
210
212 bool has_auth_provider() const {
213 return m_auth_provider != nullptr;
214 }
215
217 std::shared_ptr<http::auth::IAuthProvider> auth_provider() const {
218 return m_auth_provider;
219 }
220#endif
221
227 long limit_id,
231 }
232
240 const HttpRateLimitHandlePtr& limit,
242 if (!limit) {
243 return false;
244 }
245
246 clear_rate_limit(type);
247
248 switch (type) {
251 break;
252
255 break;
256 }
257 return true;
258 }
259
266 long limit_id,
268 return assign_rate_limit_id(limit_id, type);
269 }
270
276 const HttpRateLimitHandlePtr& limit,
278 return assign_rate_limit_handle(limit, type);
279 }
280
288 long requests_per_period,
289 long period_ms,
291 bool sequential = false) {
292 auto& instance = HttpRequestManager::get_instance();
293
294 clear_rate_limit(type);
295
296 switch (type) {
299 instance.create_rate_limit(requests_per_period, period_ms, sequential);
301 break;
302
305 instance.create_rate_limit(requests_per_period, period_ms, sequential);
307 break;
308 }
309 }
310
317 long requests_per_minute,
319 bool sequential = false) {
320 long period_ms = 60000; // 1 minute in milliseconds
321 set_rate_limit(requests_per_minute, period_ms, type, sequential);
322 }
323
330 long requests_per_second,
332 bool sequential = false) {
333 long period_ms = 1000; // 1 second in milliseconds
334 set_rate_limit(requests_per_second, period_ms, type, sequential);
335 }
336
340 void set_rate_limit_key(const std::string& key) {
343 }
344
348 void set_general_rate_limit_key(const std::string& key) {
350 }
351
355 void set_specific_rate_limit_key(const std::string& key) {
357 }
358
363 const std::string& general_key,
364 const std::string& specific_key) {
365 m_request.general_rate_limit_key = general_key;
366 m_request.specific_rate_limit_key = specific_key;
367 }
368
375 bool identity = false,
376 bool deflate = false,
377 bool gzip = false,
378 bool brotli = false) {
379 m_request.set_accept_encoding(identity, deflate, gzip, brotli);
380 }
381
384 void set_accept_encoding(const std::string& value) {
386 }
387
390 void set_accept_language(const std::string& value) {
391 set_header("Accept-Language", value);
392 }
393
396 void set_content_type(const std::string& value) {
397 set_header("Content-Type", value);
398 }
399
402 void set_origin(const std::string& value) {
403 set_header("Origin", value);
404 }
405
408 void set_referer(const std::string& value) {
409 set_header("Referer", value);
410 }
411
414 void set_dnt(const bool value) {
415 m_request.headers.erase("dnt");
416 if (value) m_request.headers.emplace("dnt", "1");
417 }
418
421 void set_follow_location(bool value) {
423 }
424
427 void set_auto_referer(bool value) {
428 m_request.auto_referer = value;
429 }
430
433 void set_proxy_tunnel(bool value) {
434 m_request.proxy_tunnel = value;
435 }
436
440 void set_head_only(bool value) {
441 m_request.head_only = value;
442 }
443
446 void set_streaming(bool streaming) {
447 m_request.streaming = streaming;
448 }
449
455 const std::string& ip,
456 int port,
458 m_request.set_proxy(ip, port, type);
459 }
460
468 const std::string& ip,
469 const int port,
470 const std::string& username,
471 const std::string& password,
473 m_request.set_proxy(ip, port, username, password, type);
474 }
475
480 const std::string& username,
481 const std::string& password) {
482 m_request.set_proxy_auth(username, password);
483 }
484
487 void set_proxy_server(const std::string& server) {
489 }
490
493 void set_proxy_auth(const std::string& auth) {
495 }
496
501 }
502
506 void set_retry_attempts(long retry_attempts, long retry_delay_ms) {
507 m_request.set_retry_attempts(retry_attempts, retry_delay_ms);
508 }
509
512 void add_valid_status(long status) {
514 }
515
518 void set_valid_statuses(const std::set<long>& statuses) {
520 }
521
526
529 void set_user_agent(const std::string& user_agent) {
530 m_request.set_user_agent(user_agent);
531 }
532
535 void set_cookie(const std::string& cookie) {
536 m_request.set_cookie(cookie);
537 }
538
541 void set_cert_file(const std::string& cert_file) {
542 m_request.set_cert_file(cert_file);
543 }
544
547 void set_ca_file(const std::string& ca_file) {
548 m_request.set_ca_file(ca_file);
549 }
550
553 void set_timeout(long timeout) {
554 m_request.set_timeout(timeout);
555 }
556
559 void set_connect_timeout(long connect_timeout) {
560 m_request.set_connect_timeout(connect_timeout);
561 }
562
565 void set_verbose(bool verbose) {
566 m_request.verbose = verbose;
567 }
568
571 void set_debug_header(bool debug_header) {
572 m_request.debug_header = debug_header;
573 }
574
577 void set_max_redirects(long max_redirects) {
578 m_request.max_redirects = max_redirects;
579 }
580
588 std::unique_ptr<HttpRequest> request_ptr,
589 HttpResponseCallback callback) {
590 SubmitResult submit_result;
591 {
592 std::lock_guard<std::mutex> lock(m_submit_mutex);
593
594 if (m_max_in_flight != 0 &&
597 }
598
600 std::move(request_ptr), std::move(callback));
601 }
602
603 if (submit_result) {
605 }
606 return submit_result;
607 }
608
618 const std::string &method,
619 const std::string& path,
620 const QueryParams &query,
621 const Headers &headers,
622 const std::string &content,
623 HttpResponseCallback callback) {
624 return request(make_request(method, path, query, headers, content), std::move(callback));
625 }
626
638 const std::string &method,
639 const std::string& path,
640 const QueryParams &query,
641 const Headers &headers,
642 const std::string &content,
643 long specific_rate_limit_id,
644 HttpResponseCallback callback) {
645 return request(
646 method,
647 path,
648 query,
649 headers,
650 content,
651 HttpRequestManager::get_instance().get_rate_limit(specific_rate_limit_id),
652 std::move(callback));
653 }
654
665 const std::string &method,
666 const std::string& path,
667 const QueryParams &query,
668 const Headers &headers,
669 const std::string &content,
670 const HttpRateLimitHandlePtr& specific_rate_limit,
671 HttpResponseCallback callback) {
672 auto request_ptr = make_request(method, path, query, headers, content);
673 request_ptr->specific_rate_limit = specific_rate_limit;
674 return request(std::move(request_ptr), std::move(callback));
675 }
676
683 bool get(
684 const std::string& path,
685 const QueryParams& query,
686 const Headers& headers,
687 HttpResponseCallback callback) {
688 return request("GET", path, query, headers, std::string(), std::move(callback));
689 }
690
698 bool post(
699 const std::string& path,
700 const QueryParams& query,
701 const Headers& headers,
702 const std::string& content,
703 HttpResponseCallback callback) {
704 return request("POST", path, query, headers, content, std::move(callback));
705 }
706
715 bool get(
716 const std::string& path,
717 const QueryParams& query,
718 const Headers& headers,
719 long specific_rate_limit_id,
720 HttpResponseCallback callback) {
721 return request("GET", path, query, headers, std::string(), specific_rate_limit_id, std::move(callback));
722 }
723
731 bool get(
732 const std::string& path,
733 const QueryParams& query,
734 const Headers& headers,
735 const HttpRateLimitHandlePtr& specific_rate_limit,
736 HttpResponseCallback callback) {
737 return request("GET", path, query, headers, std::string(), specific_rate_limit, std::move(callback));
738 }
739
749 bool post(
750 const std::string& path,
751 const QueryParams& query,
752 const Headers& headers,
753 const std::string& content,
754 long specific_rate_limit_id,
755 HttpResponseCallback callback) {
756 return request("POST", path, query, headers, content, specific_rate_limit_id, std::move(callback));
757 }
758
767 bool post(
768 const std::string& path,
769 const QueryParams& query,
770 const Headers& headers,
771 const std::string& content,
772 const HttpRateLimitHandlePtr& specific_rate_limit,
773 HttpResponseCallback callback) {
774 return request("POST", path, query, headers, content, specific_rate_limit, std::move(callback));
775 }
776
784 std::future<HttpResponsePtr> request(
785 const std::string& method,
786 const std::string& path,
787 const QueryParams& query,
788 const Headers& headers,
789 const std::string& content) {
790 return submit_future_request(make_request(method, path, query, headers, content));
791 }
792
802 std::future<HttpResponsePtr> request(
803 const std::string& method,
804 const std::string& path,
805 const QueryParams& query,
806 const Headers& headers,
807 const std::string& content,
808 long specific_rate_limit_id) {
809 return request(
810 method,
811 path,
812 query,
813 headers,
814 content,
815 HttpRequestManager::get_instance().get_rate_limit(specific_rate_limit_id));
816 }
817
826 std::future<HttpResponsePtr> request(
827 const std::string& method,
828 const std::string& path,
829 const QueryParams& query,
830 const Headers& headers,
831 const std::string& content,
832 const HttpRateLimitHandlePtr& specific_rate_limit) {
833 auto request_ptr = make_request(method, path, query, headers, content);
834 request_ptr->specific_rate_limit = specific_rate_limit;
835 return submit_future_request(std::move(request_ptr));
836 }
837
843 std::future<HttpResponsePtr> get(
844 const std::string& path,
845 const QueryParams& query,
846 const Headers& headers) {
847 return request("GET", path, query, headers, std::string());
848 }
849
856 std::future<HttpResponsePtr> post(
857 const std::string& path,
858 const QueryParams& query,
859 const Headers& headers,
860 const std::string& content) {
861 return request("POST", path, query, headers, content);
862 }
863
871 std::future<HttpResponsePtr> get(
872 const std::string& path,
873 const QueryParams& query,
874 const Headers& headers,
875 long specific_rate_limit_id) {
876 return request("GET", path, query, headers, std::string(), specific_rate_limit_id);
877 }
878
887 std::future<HttpResponsePtr> post(
888 const std::string& path,
889 const QueryParams& query,
890 const Headers& headers,
891 const std::string& content,
892 long specific_rate_limit_id) {
893 return request("POST", path, query, headers, content, specific_rate_limit_id);
894 }
895
902 std::future<HttpResponsePtr> get(
903 const std::string& path,
904 const QueryParams& query,
905 const Headers& headers,
906 const HttpRateLimitHandlePtr& specific_rate_limit) {
907 return request("GET", path, query, headers, std::string(), specific_rate_limit);
908 }
909
917 std::future<HttpResponsePtr> post(
918 const std::string& path,
919 const QueryParams& query,
920 const Headers& headers,
921 const std::string& content,
922 const HttpRateLimitHandlePtr& specific_rate_limit) {
923 return request("POST", path, query, headers, content, specific_rate_limit);
924 }
925
926 private:
928 std::string m_host;
931 mutable std::mutex m_submit_mutex;
932 std::size_t m_max_in_flight = 0;
933# if KURLYK_AUTH_SUPPORT
934 std::shared_ptr<http::auth::IAuthProvider> m_auth_provider;
935# endif
936
942 std::unique_ptr<HttpRequest> request_ptr,
943 HttpResponseCallback callback) {
944 return submit_request(std::move(request_ptr), std::move(callback)).accepted;
945 }
946
947 void set_header(const std::string& name, const std::string& value) {
948 m_request.headers.erase(name);
949 m_request.headers.emplace(name, value);
950 }
951
952 std::unique_ptr<HttpRequest> make_request(
953 const std::string& method,
954 const std::string& path,
955 const QueryParams& query,
956 const Headers& headers,
957 const std::string& content) const {
958# if __cplusplus >= 201402L
959 auto request_ptr = std::make_unique<HttpRequest>(m_request);
960# else
961 auto request_ptr = std::unique_ptr<HttpRequest>(new HttpRequest(m_request));
962# endif
963
964 request_ptr->request_id = HttpRequestManager::get_instance().generate_request_id();
965 request_ptr->method = method;
966 request_ptr->set_url(m_host, path, query);
967 request_ptr->headers.insert(headers.begin(), headers.end());
968 request_ptr->content = content;
969# if KURLYK_AUTH_SUPPORT
970 if (m_auth_provider) {
971 m_auth_provider->authorize(*request_ptr);
972 }
973# endif
974 return request_ptr;
975 }
976
977 std::future<HttpResponsePtr> submit_future_request(std::unique_ptr<HttpRequest> request_ptr) {
978 auto promise = std::make_shared<std::promise<HttpResponsePtr>>();
979 auto future = promise->get_future();
980
981 HttpResponseCallback callback = [promise](HttpResponsePtr response) {
982 safe_set_response(promise, std::move(response));
983 };
984
985 safe_submit_request(promise, std::move(request_ptr), std::move(callback));
986 return future;
987 }
988
991 std::future<void> make_wait_requests_future(uint64_t* waiter_id) {
992 auto promise = std::make_shared<std::promise<void>>();
993 auto future = promise->get_future();
994
995 const uint64_t registered_waiter_id =
998 [promise]() {
999 try {
1000 promise->set_value();
1001 } catch (const std::future_error& e) {
1002 if (e.code() == std::make_error_condition(std::future_errc::promise_already_satisfied)) {
1003 KURLYK_HANDLE_ERROR(e, "Promise already satisfied in HttpClient::wait_requests callback");
1004 } else {
1005 KURLYK_HANDLE_ERROR(e, "Future error in HttpClient::wait_requests callback");
1006 }
1007 } catch (const std::exception& e) {
1008 KURLYK_HANDLE_ERROR(e, "Unhandled exception in HttpClient::wait_requests callback");
1009 } catch (...) {
1010 // Unknown fatal error in wait callback
1011 }
1012 });
1013 if (waiter_id) {
1014 *waiter_id = registered_waiter_id;
1015 }
1016
1017 return future;
1018 }
1019
1024 std::shared_ptr<std::promise<HttpResponsePtr>> promise,
1025 HttpResponsePtr response) {
1026 if (!response || !response->ready) return;
1027 try {
1028 promise->set_value(std::move(response));
1029 } catch (const std::future_error& e) {
1030 if (e.code() == std::make_error_condition(std::future_errc::promise_already_satisfied)) {
1031 KURLYK_HANDLE_ERROR(e, "Promise already satisfied in HttpClient::request callback");
1032 } else {
1033 KURLYK_HANDLE_ERROR(e, "Future error in HttpClient::request callback");
1034 }
1035 } catch (const std::exception& e) {
1036 KURLYK_HANDLE_ERROR(e, "Unhandled exception in HttpClient::request callback");
1037 } catch (...) {
1038 // Unknown fatal error in request callback
1039 }
1040 }
1041
1046# if __cplusplus >= 201402L
1047 auto response = std::make_unique<HttpResponse>();
1048# else
1049 auto response = std::unique_ptr<HttpResponse>(new HttpResponse());
1050# endif
1051 response->ready = true;
1052 response->status_code = 0;
1053 response->error_code = submit_result.error_code;
1054 response->error_message = submit_result.error_code.message();
1055 return response;
1056 }
1057
1063 std::shared_ptr<std::promise<HttpResponsePtr>> promise,
1064 std::unique_ptr<HttpRequest> request_ptr,
1065 HttpResponseCallback callback) {
1066 try {
1067 const SubmitResult submit_result = submit_request(std::move(request_ptr), std::move(callback));
1068 if (!submit_result) {
1069 safe_set_response(promise, make_submit_error_response(submit_result));
1070 }
1071 } catch (const std::exception& e) {
1072 KURLYK_HANDLE_ERROR(e, "Exception while submitting request");
1073 try {
1074 promise->set_exception(std::current_exception());
1075 } catch (...) {} // fallback
1076 } catch (...) {
1077 // Unknown fatal error while submitting request
1078 try {
1079 promise->set_exception(std::current_exception());
1080 } catch (...) {} // fallback
1081 }
1082 }
1083
1085 static void ensure_initialized() {
1086 static std::once_flag once;
1087 std::call_once(once, []() {
1090 });
1091 }
1092
1093 }; // HttpClient
1094
1095}; // namespace kurlyk
1096
1097#endif // KURLYK_HEADER_KURLYK_HTTP_HTTP_CLIENT_HPP_INCLUDED
Defines the IAuthProvider interface for HTTP authentication strategies.
#define KURLYK_HANDLE_ERROR(e, msg)
bool get(const std::string &path, const QueryParams &query, const Headers &headers, long specific_rate_limit_id, HttpResponseCallback callback)
Sends a GET request with a temporary specific rate limit found by ID.
bool request(std::unique_ptr< HttpRequest > request_ptr, HttpResponseCallback callback)
Adds the request to the request manager and notifies the worker to process it.
void set_proxy_auth(const std::string &auth)
Sets the proxy authentication credentials.
std::unique_ptr< HttpRequest > make_request(const std::string &method, const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content) const
bool m_owns_general_rate_limit
Flag indicating if the client owns the general rate limit.
~HttpClient()
Destroys the client, cancels requests associated with this client, and releases owned rate limits.
void wait_requests()
Waits until all requests associated with this client group finish.
void set_rate_limit(long requests_per_period, long period_ms, RateLimitType type=RateLimitType::RL_GENERAL, bool sequential=false)
Creates and assigns an owned rate limit for future requests.
HttpRequest m_request
Request defaults shared by requests created by this client.
bool wait_requests_for(std::chrono::milliseconds timeout)
Waits until all requests associated with this client group finish or timeout expires.
std::size_t max_in_flight() const
Returns this client's configured admission cap.
void set_valid_statuses(const std::set< long > &statuses)
Replaces all valid HTTP status codes for the request.
void set_head_only(bool value)
Configures whether to send only the HTTP headers (HEAD request).
void set_verbose(bool verbose)
Enables or disables verbose output.
void set_accept_language(const std::string &value)
Sets the Accept-Language header value.
std::future< HttpResponsePtr > request(const std::string &method, const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, long specific_rate_limit_id)
Sends an HTTP request with a temporary specific rate limit found by ID and returns a future with the ...
std::string m_host
The base host URL for the HTTP client.
void set_max_redirects(long max_redirects)
Sets the maximum number of redirects for the client.
std::future< HttpResponsePtr > post(const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, long specific_rate_limit_id)
Sends an asynchronous POST request with a temporary specific rate limit found by ID.
void set_content_type(const std::string &value)
Sets the Content-Type header value.
bool post(const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, HttpResponseCallback callback)
Sends a POST request.
bool request(const std::string &method, const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, HttpResponseCallback callback)
Sends an HTTP request with the specified method, path, and parameters.
HttpClient(const HttpClient &)=delete
void add_valid_status(long status)
Adds a valid HTTP status code to the request.
std::future< HttpResponsePtr > get(const std::string &path, const QueryParams &query, const Headers &headers, const HttpRateLimitHandlePtr &specific_rate_limit)
Sends an asynchronous GET request with a temporary specific rate limit.
std::future< HttpResponsePtr > request(const std::string &method, const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, const HttpRateLimitHandlePtr &specific_rate_limit)
Sends an HTTP request with a temporary specific rate limit and returns a future with the response.
HttpClient()
Default constructor for HttpClient.
void set_streaming(bool streaming)
Enables or disables intermediate callbacks for response body chunks.
void set_ca_file(const std::string &ca_file)
Sets the path to the CA certificate file.
void clear_valid_statuses()
Clears the set of valid HTTP status codes for the request.
SubmitResult submit_request(std::unique_ptr< HttpRequest > request_ptr, HttpResponseCallback callback)
Attempts to submit a prepared request to the global HTTP manager.
std::future< HttpResponsePtr > post(const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, const HttpRateLimitHandlePtr &specific_rate_limit)
Sends an asynchronous POST request with a temporary specific rate limit.
std::future< HttpResponsePtr > request(const std::string &method, const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content)
Sends an HTTP request with a specified method, path, and parameters, and returns a future with the re...
void set_proxy(const std::string &ip, int port, ProxyType type=ProxyType::PROXY_HTTP)
Sets the proxy server address.
bool set_rate_limit_handle(const HttpRateLimitHandlePtr &limit, RateLimitType type=RateLimitType::RL_GENERAL)
Sets an existing rate-limit handle for future requests.
void safe_submit_request(std::shared_ptr< std::promise< HttpResponsePtr > > promise, std::unique_ptr< HttpRequest > request_ptr, HttpResponseCallback callback)
Submits a request and propagates any failure to the provided promise.
bool get(const std::string &path, const QueryParams &query, const Headers &headers, const HttpRateLimitHandlePtr &specific_rate_limit, HttpResponseCallback callback)
Sends a GET request with a temporary specific rate limit.
void set_cert_file(const std::string &cert_file)
Sets the client certificate file path.
static void safe_set_response(std::shared_ptr< std::promise< HttpResponsePtr > > promise, HttpResponsePtr response)
Safely sets the response value on the given promise.
void set_auto_referer(bool value)
Configures whether to automatically set the Referer header on redirects.
void set_connect_timeout(long connect_timeout)
Sets the connection timeout duration.
void set_retry_attempts(long retry_attempts, long retry_delay_ms)
Sets retry attempts and delay between retries for HTTP requests.
void set_rate_limit_rps(long requests_per_second, RateLimitType type=RateLimitType::RL_GENERAL, bool sequential=false)
Sets the rate limit based on requests per second (RPS).
void set_timeout(long timeout)
Sets the timeout duration for HTTP requests.
void set_proxy_server(const std::string &server)
Sets the proxy server address.
std::future< HttpResponsePtr > get(const std::string &path, const QueryParams &query, const Headers &headers)
Sends a GET request asynchronously and returns a future with the response.
void set_rate_limit_rpm(long requests_per_minute, RateLimitType type=RateLimitType::RL_GENERAL, bool sequential=false)
Sets the rate limit based on requests per minute (RPM).
void clear_rate_limit(RateLimitType type=RateLimitType::RL_GENERAL)
Clears the configured rate limit of the specified type.
void set_referer(const std::string &value)
Sets the Referer header value.
void set_follow_location(bool value)
Configures whether to follow redirects automatically.
void set_proxy(const std::string &ip, const int port, const std::string &username, const std::string &password, ProxyType type=ProxyType::PROXY_HTTP)
Sets the proxy server address with authentication details.
void set_specific_rate_limit_key(const std::string &key)
Sets the partition key for the specific rate limit.
bool assign_rate_limit_handle(const HttpRateLimitHandlePtr &limit, RateLimitType type=RateLimitType::RL_GENERAL)
Assigns an existing rate-limit handle to future requests.
void set_cookie(const std::string &cookie)
Sets the cookie string for HTTP requests.
std::future< HttpResponsePtr > get(const std::string &path, const QueryParams &query, const Headers &headers, long specific_rate_limit_id)
Sends an asynchronous GET request with a temporary specific rate limit found by ID.
std::future< HttpResponsePtr > post(const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content)
Sends a POST request asynchronously and returns a future with the response.
void set_accept_encoding(const std::string &value)
Sets a custom Accept-Encoding header value.
bool assign_rate_limit_id(long limit_id, RateLimitType type=RateLimitType::RL_GENERAL)
Assigns an existing rate limit to future requests by ID.
std::size_t in_flight_requests() const
Returns the number of admitted requests whose final callback is still pending for this group.
HttpClient(HttpClient &&)=delete
void set_general_rate_limit_key(const std::string &key)
Sets the partition key for the general rate limit.
void set_user_agent(const std::string &user_agent)
Sets the User-Agent header.
void set_origin(const std::string &value)
Sets the Origin header value.
bool request(const std::string &method, const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, const HttpRateLimitHandlePtr &specific_rate_limit, HttpResponseCallback callback)
Sends an HTTP request with a temporary specific rate limit.
HttpClient(const std::string &host)
Constructs an HttpClient with the specified host.
void set_max_in_flight(std::size_t max_in_flight)
Sets maximum number of requests this client may submit while its group is busy.
void set_proxy_tunnel(bool value)
Configures whether to use a tunneling proxy for HTTP requests.
bool post(const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, long specific_rate_limit_id, HttpResponseCallback callback)
Sends a POST request with a temporary specific rate limit found by ID.
static HttpResponsePtr make_submit_error_response(const SubmitResult &submit_result)
Creates a ready HTTP response describing a synchronous submission rejection.
bool m_owns_specific_rate_limit
Flag indicating if the client owns the specific rate limit.
static void ensure_initialized()
Ensures that the network worker and request manager are initialized.
bool post(const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, const HttpRateLimitHandlePtr &specific_rate_limit, HttpResponseCallback callback)
Sends a POST request with a temporary specific rate limit.
HttpClient & operator=(HttpClient &&)=delete
void set_host(const std::string &host)
Sets the host URL for the HTTP client.
bool get(const std::string &path, const QueryParams &query, const Headers &headers, HttpResponseCallback callback)
Sends a GET request.
std::size_t m_max_in_flight
Maximum number of in-flight requests for this client group, or 0 for disabled.
void set_debug_header(bool debug_header)
Enables or disables debug headers.
void set_rate_limit_key(const std::string &key)
Sets the partition key for both rate limits (general and specific).
std::future< HttpResponsePtr > submit_future_request(std::unique_ptr< HttpRequest > request_ptr)
void set_proxy_auth(const std::string &username, const std::string &password)
Sets proxy authentication credentials.
void set_headers(const kurlyk::Headers &headers)
Sets the default headers for HTTP requests.
HttpClient & operator=(const HttpClient &)=delete
void set_rate_limit_keys(const std::string &general_key, const std::string &specific_key)
Sets independent partition keys for general and specific rate limits.
bool set_rate_limit_id(long limit_id, RateLimitType type=RateLimitType::RL_GENERAL)
Sets the rate limit ID for the HTTP request (alias for assign_rate_limit_id).
void set_dnt(const bool value)
Sets the Do Not Track (DNT) header value.
std::mutex m_submit_mutex
Protects client-side submission settings and admission checks.
bool request(const std::string &method, const std::string &path, const QueryParams &query, const Headers &headers, const std::string &content, long specific_rate_limit_id, HttpResponseCallback callback)
Sends an HTTP request with a temporary specific rate limit found by ID.
void set_header(const std::string &name, const std::string &value)
void set_accept_encoding(bool identity=false, bool deflate=false, bool gzip=false, bool brotli=false)
Sets the Accept-Encoding header.
std::future< void > make_wait_requests_future(uint64_t *waiter_id)
Creates a future that becomes ready when all requests in this client group finish.
void set_proxy_type(ProxyType type)
Sets the proxy type.
void cancel_requests()
Cancels requests associated with this client and waits for cancellation callbacks.
uint64_t generate_group_id()
Generates a new group ID.
std::size_t group_request_count(uint64_t group_id) const
Counts admitted requests that have not delivered their final callback for a group.
static HttpRequestManager & get_instance()
Get the singleton instance of HttpRequestManager.
uint64_t wait_requests_by_group_id(uint64_t group_id, std::function< void()> callback)
Registers a callback invoked after all requests from a group finish.
SubmitResult submit_request(std::unique_ptr< HttpRequest > request_ptr, HttpResponseCallback callback)
Attempts to enqueue a new HTTP request and reports the admission result.
bool cancel_wait_requests_by_group_id(uint64_t group_id, uint64_t waiter_id)
Removes a previously registered group waiter.
uint64_t generate_request_id()
Generates a new unique request ID.
Represents an HTTP request configuration.
bool proxy_tunnel
Enable proxy tunneling.
void set_proxy_type(ProxyType type)
Sets the proxy type.
bool head_only
If true, does not download the response body (HEAD-like behavior).
void set_cert_file(const std::string &cert_file)
Sets the client certificate file path.
void set_proxy_auth(const std::string &auth)
Sets the proxy authentication credentials.
bool follow_location
Automatically follow HTTP redirects.
bool debug_header
Include headers in debug output (CURLOPT_HEADER).
bool verbose
Enable verbose output (CURLOPT_VERBOSE).
void set_retry_attempts(long retry_attempts, long retry_delay_ms)
Sets the number of retry attempts and delay before retrying.
void set_proxy_server(const std::string &server)
Sets the proxy server address.
void set_ca_file(const std::string &ca_file)
Sets the path to the CA certificate file.
void set_timeout(long timeout)
Sets the request timeout.
void set_valid_statuses(const std::set< long > &statuses)
Sets the valid HTTP status codes, replacing any existing values.
bool streaming
Enable intermediate callbacks for response body chunks.
void set_cookie(const std::string &cookie)
Sets the cookie data.
Headers headers
HTTP request headers.
void set_connect_timeout(long connect_timeout)
Sets the connection timeout.
void set_proxy(const std::string &ip, int port)
Sets the proxy server address.
bool auto_referer
Automatically set Referer header.
void clear_valid_statuses()
Clears all valid status codes.
std::string general_rate_limit_key
Key used to separate general rate limit state; empty means default shared state.
std::string specific_rate_limit_key
Key used to separate specific rate limit state; empty means default shared state.
void set_accept_encoding(bool identity=false, bool deflate=false, bool gzip=false, bool brotli=false)
Sets the Accept-Encoding header with optional encoding types.
std::string accept_encoding
Accept-Encoding header.
long max_redirects
Maximum allowed redirects.
void set_user_agent(const std::string &user_agent)
Sets the User-Agent header.
HttpRateLimitHandlePtr general_rate_limit
General rate limit handle.
uint64_t group_id
ID shared by related requests, for example all requests created by one HttpClient.
HttpRateLimitHandlePtr specific_rate_limit
Specific rate limit handle.
void add_valid_status(long status)
Adds a single valid HTTP status code.
Represents an HTTP response.
void notify()
Notifies the worker to begin processing requests or tasks.
static NetworkWorker & get_instance()
Get the singleton instance of NetworkWorker.
void start(const bool use_async)
Starts the worker thread for asynchronous task processing.
#define KURLYK_AUTO_INIT_USE_ASYNC
Determines whether the NetworkWorker runs in a background thread during automatic initialization.
Definition kurlyk.hpp:22
@ QueueLimitExceeded
Operation was rejected because the bounded queue is already full.
std::error_code make_error_code(ClientError e)
Creates a std::error_code from a ClientError value.
Primary namespace for the Kurlyk library, encompassing initialization, request management,...
std::function< void(HttpResponsePtr response)> HttpResponseCallback
Callback invoked with an HTTP response.
RateLimitType
Defines rate limit scope categories.
Definition enums.hpp:24
@ RL_GENERAL
Applies globally to all requests.
Definition enums.hpp:25
@ RL_SPECIFIC
Applies to specific client/request.
Definition enums.hpp:26
ProxyType
Enumeration of supported proxy types compatible with libcurl.
Definition enums.hpp:12
@ PROXY_HTTP
HTTP proxy.
Definition enums.hpp:13
std::unique_ptr< HttpResponse > HttpResponsePtr
Owning pointer to an HTTP response.
HttpRateLimitHandlePtr get_rate_limit(long limit_id)
Returns a manager-owned rate-limit handle by ID.
Definition utils.hpp:44
utils::CaseInsensitiveMultimap Headers
Alias for HTTP headers, providing a case-insensitive unordered multimap.
std::shared_ptr< HttpRateLimitHandle > HttpRateLimitHandlePtr
Shared RAII handle for HTTP rate limits.
utils::CaseInsensitiveMultimap QueryParams
Alias for query parameters in HTTP requests, stored case-insensitively.
Represents the synchronous result of trying to enqueue or submit work.
bool accepted
Indicates whether the work item was accepted for processing.
std::error_code error_code
Describes the rejection reason when accepted is false.