Kurlyk
Loading...
Searching...
No Matches
ProxyChecker.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef KURLYK_HEADER_KURLYK_HTTP_PROXY_CHECKER_HPP_INCLUDED
3#define KURLYK_HEADER_KURLYK_HTTP_PROXY_CHECKER_HPP_INCLUDED
4
7
8#include <future>
9#include <limits>
10#include <memory>
11#include <string>
12#include <utility>
13
14#include <kurlyk/core.hpp>
15#include "data.hpp"
17#include "utils.hpp"
18
19namespace kurlyk {
20namespace detail {
21
22 inline bool proxy_check_has_scheme(const std::string& url, const char* scheme) {
23 const std::string prefix(scheme);
24 if (url.size() < prefix.size()) return false;
25 for (std::string::size_type i = 0; i < prefix.size(); ++i) {
26 char actual = url[i];
27 if (actual >= 'A' && actual <= 'Z') {
28 actual = static_cast<char>(actual - 'A' + 'a');
29 }
30 if (actual != prefix[i]) return false;
31 }
32 return true;
33 }
34
35 inline bool proxy_check_is_http_url(const std::string& url) {
36 return proxy_check_has_scheme(url, "http://") ||
37 proxy_check_has_scheme(url, "https://");
38 }
39
40 inline long proxy_check_milliseconds(double seconds) {
41 if (seconds <= 0.0) return 0;
42 const double milliseconds = seconds * 1000.0;
43 const double maximum = static_cast<double>((std::numeric_limits<long>::max)());
44 if (milliseconds >= maximum) {
45 return (std::numeric_limits<long>::max)();
46 }
47 return static_cast<long>(milliseconds + 0.5);
48 }
49
51 const std::error_code& error_code,
52 const std::string& error_message = std::string()) {
53 ProxyCheckResult result;
54 result.error_code = error_code;
55 result.error_message = error_message.empty() ? error_code.message() : error_message;
56 return result;
57 }
58
60 const HttpResponsePtr& response,
61 bool is_https) {
62 if (!response) {
65 "Proxy check returned no HTTP response");
66 }
67
68 ProxyCheckResult result;
69 result.error_code = response->error_code;
70 result.error_message = response->error_message.empty() && response->error_code
71 ? response->error_code.message()
72 : response->error_message;
73 result.http_status = response->status_code;
74
75 const bool received_http_response =
76 response->ready &&
77 response->status_code > 0 &&
78 (!response->error_code || utils::is_http_error(response->error_code));
79 result.reachable = received_http_response;
80 result.http_ok = received_http_response &&
81 response->status_code >= 200 && response->status_code < 400;
82 result.https_ok = is_https && result.http_ok;
83
84 result.connect_latency_ms = proxy_check_milliseconds(response->connect_time);
85 if (response->appconnect_time > 0.0 &&
86 response->connect_time >= 0.0 &&
87 response->appconnect_time >= response->connect_time) {
89 response->appconnect_time - response->connect_time);
90 }
91 result.ttfb_ms = proxy_check_milliseconds(response->starttransfer_time);
92 result.total_latency_ms = proxy_check_milliseconds(response->total_time);
93 return result;
94 }
95
97 const std::shared_ptr<std::promise<ProxyCheckResult>>& promise,
98 ProxyCheckResult result) {
99 try {
100 promise->set_value(std::move(result));
101 } catch (const std::future_error& error) {
102 KURLYK_HANDLE_ERROR(error, "Future error in ProxyChecker callback");
103 } catch (const std::exception& error) {
104 KURLYK_HANDLE_ERROR(error, "Unhandled exception in ProxyChecker callback");
105 } catch (...) {
106 // Unknown fatal error in proxy checker callback.
107 }
108 }
109
110} // namespace detail
111
115 public:
121 std::future<ProxyCheckResult> check(
122 const ProxyConfig& proxy,
123 const ProxyCheckOptions& options = ProxyCheckOptions()) const {
124 const std::shared_ptr<std::promise<ProxyCheckResult>> promise(
125 new std::promise<ProxyCheckResult>());
126 std::future<ProxyCheckResult> future = promise->get_future();
127
128 if (!proxy.is_valid()) {
130 promise,
133 "Proxy server must contain a valid host and port"));
134 return future;
135 }
136
137 if (!detail::proxy_check_is_http_url(options.test_url) ||
138 options.connect_timeout < 0 ||
139 options.request_timeout < 0) {
141 promise,
144 "Proxy check requires an HTTP(S) test URL and non-negative timeouts"));
145 return future;
146 }
147
148# if __cplusplus >= 201402L
149 std::unique_ptr<HttpRequest> request = std::make_unique<HttpRequest>();
150# else
151 std::unique_ptr<HttpRequest> request(new HttpRequest());
152# endif
153 request->url = options.test_url;
154 request->method = "HEAD";
155 request->head_only = true;
156 request->ca_file = options.ca_file;
157 request->follow_location = options.follow_redirects;
158 request->proxy_server = proxy.proxy_server;
159 request->proxy_auth = proxy.proxy_auth;
160 request->proxy_type = proxy.proxy_type;
161 request->proxy_tunnel = options.proxy_tunnel;
162 request->connect_timeout = options.connect_timeout;
163 request->timeout = options.request_timeout;
164 request->retry_attempts = 0;
165
166 const bool is_https = detail::proxy_check_has_scheme(options.test_url, "https://");
167 HttpResponseCallback callback = [promise, is_https](HttpResponsePtr response) {
168 if (response && !response->ready) return;
170 promise,
171 detail::make_proxy_check_result(response, is_https));
172 };
173
174 const SubmitResult submit_result = submit_http_request(
175 std::move(request), std::move(callback));
176 if (!submit_result) {
178 promise,
180 }
181 return future;
182 }
183 };
184
189 inline std::future<ProxyCheckResult> check_proxy(
190 const ProxyConfig& proxy,
191 const ProxyCheckOptions& options = ProxyCheckOptions()) {
192 return ProxyChecker().check(proxy, options);
193 }
194
195} // namespace kurlyk
196
197#endif // KURLYK_HEADER_KURLYK_HTTP_PROXY_CHECKER_HPP_INCLUDED
Manages and processes HTTP requests using a singleton pattern.
#define KURLYK_HANDLE_ERROR(e, msg)
Represents an HTTP request configuration.
Checks whether a proxy can complete an HTTP or HTTPS no-body request.
std::future< ProxyCheckResult > check(const ProxyConfig &proxy, const ProxyCheckOptions &options=ProxyCheckOptions()) const
Starts an asynchronous proxy check.
Aggregates core infrastructure components such as task manager interface and the network worker.
Aggregates core HTTP data structures such as request, response, and cookie.
Contains utility functions for handling HTTP requests, rate limiting, and request cancellation.
long proxy_check_milliseconds(double seconds)
bool proxy_check_has_scheme(const std::string &url, const char *scheme)
bool proxy_check_is_http_url(const std::string &url)
ProxyCheckResult make_proxy_check_result(const HttpResponsePtr &response, bool is_https)
void set_proxy_check_promise(const std::shared_ptr< std::promise< ProxyCheckResult > > &promise, ProxyCheckResult result)
ProxyCheckResult make_proxy_check_error(const std::error_code &error_code, const std::string &error_message=std::string())
@ AbortedDuringDestruction
Request handler was destroyed before completion, causing the request to abort.
@ InvalidConfiguration
Provided configuration is incomplete or invalid.
bool is_http_error(const std::error_code &ec)
Checks whether the given error code belongs to the HTTP error category.
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.
std::unique_ptr< HttpResponse > HttpResponsePtr
Owning pointer to an HTTP response.
std::future< ProxyCheckResult > check_proxy(const ProxyConfig &proxy, const ProxyCheckOptions &options=ProxyCheckOptions())
Starts an asynchronous no-body request through a proxy.
SubmitResult submit_http_request(std::unique_ptr< HttpRequest > request_ptr, HttpResponseCallback callback)
Attempts to submit an HTTP request and reports the admission result.
Definition utils.hpp:195
Configures the no-body request used to check a proxy.
Stores proxy reachability, protocol status, errors, and curl timing metrics.
std::string error_message
Error details supplied by the HTTP backend.
bool reachable
True when an HTTP response was received through the proxy.
long tls_latency_ms
TLS setup time after TCP connect, in milliseconds; includes proxy CONNECT negotiation.
std::error_code error_code
Transport, HTTP, or client-side error.
long total_latency_ms
Total request time, in milliseconds.
long connect_latency_ms
Elapsed time until the TCP connection was established, in milliseconds.
bool http_ok
True when the test endpoint returned a 2xx or 3xx response.
long ttfb_ms
Elapsed time until the first response byte, in milliseconds.
bool https_ok
True when an HTTPS test returned a 2xx or 3xx response.
long http_status
HTTP status returned by the test endpoint or proxy.
Stores proxy server, authentication, and transport settings.
ProxyType proxy_type
Proxy transport type.
std::string proxy_auth
Proxy authentication in username:password format.
std::string proxy_server
Proxy address in host:port format.
bool is_valid() const
Checks whether the proxy server address is valid.
Represents the synchronous result of trying to enqueue or submit work.
std::error_code error_code
Describes the rejection reason when accepted is false.