21#include <condition_variable>
30static constexpr std::initializer_list<std::string_view> _certificate_files = {
31 "/etc/ssl/certs/ca-certificates.crt"sv,
32 "/etc/pki/tls/certs/ca-bundle.crt"sv,
33 "/etc/ssl/ca-bundle.pem"sv,
34 "/etc/pki/tls/cacert.pem"sv,
35 "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"sv,
36 "/etc/ssl/cert.pem"sv,
39static constexpr std::initializer_list<std::string_view> _certificate_directories = {
41 "/etc/pki/tls/certs"sv,
42 "/system/etc/security/cacerts"sv,
77 const std::string
uri;
88static std::string _http_ca_file =
"";
89static std::string _http_ca_path =
"";
96 if (_http_ca_file.empty() && _http_ca_path.empty()) {
103 _http_requests.push(std::make_unique<NetworkHTTPRequest>(uri, callback, std::move(data)));
121 callback->HandleQueue();
133 CURLcode res = curl_easy_setopt(curl, option, value);
134 if (res != CURLE_OK) {
135 Debug(net, 0,
"Could not execute curl_easy_setopt for {} [{}]", option, res);
142 CURL *curl = curl_easy_init();
143 assert(curl !=
nullptr);
154 std::unique_ptr<NetworkHTTPRequest> request = std::move(
_http_requests.front());
161 curl_easy_reset(curl);
162 curl_slist *headers =
nullptr;
164 if (_debug_net_level >= 5) {
176 CurlSetOption(curl, CURLOPT_CAINFO, _http_ca_file.empty() ?
nullptr : _http_ca_file.c_str());
177 CurlSetOption(curl, CURLOPT_CAPATH, _http_ca_path.empty() ?
nullptr : _http_ca_path.c_str());
192 if (!request->data.empty()) {
194 if (request->data.starts_with(
"{")) {
195 headers = curl_slist_append(headers,
"Content-Type: application/json");
197 headers = curl_slist_append(headers,
"Content-Type: application/x-www-form-urlencoded");
201 CurlSetOption(curl, CURLOPT_POSTFIELDS, request->data.c_str());
207 CurlSetOption(curl, CURLOPT_WRITEFUNCTION, +[](
char *ptr,
size_t size,
size_t nmemb,
void *userdata) ->
size_t {
208 Debug(net, 6,
"HTTP callback: {} bytes", size * nmemb);
212 std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size * nmemb);
213 std::copy_n(ptr, size * nmemb, buffer.get());
225 CurlSetOption(curl, CURLOPT_XFERINFOFUNCTION, +[](
void *userdata, curl_off_t , curl_off_t , curl_off_t , curl_off_t ) ->
int {
229 CurlSetOption(curl, CURLOPT_XFERINFODATA, &request->callback);
232 CURLcode res = curl_easy_perform(curl);
234 curl_slist_free_all(headers);
236 if (res == CURLE_OK) {
237 Debug(net, 1,
"HTTP request succeeded");
238 request->callback.OnReceiveData(
nullptr, 0);
240 long status_code = 0;
241 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status_code);
245 request->callback.OnFailure();
249 request->callback.WaitTillEmptyOrCondition([]() ->
bool {
254 curl_easy_cleanup(curl);
259 curl_global_init(CURL_GLOBAL_DEFAULT);
265 for (
auto &ca_file : _certificate_files) {
267 _http_ca_file = ca_file;
271 if (_http_ca_file.empty()) {
272 for (
auto &ca_path : _certificate_directories) {
274 _http_ca_path = ca_path;
279 Debug(net, 3,
"Using certificate file: {}", _http_ca_file.empty() ?
"none" : _http_ca_file);
280 Debug(net, 3,
"Using certificate path: {}", _http_ca_path.empty() ?
"none" : _http_ca_path);
283 if (_http_ca_file.empty() && _http_ca_path.empty()) {
284 Debug(net, 0,
"No certificate files or directories found, HTTPS will not work!");
309 curl_global_cleanup();
Converts a HTTPCallback to a Thread-Safe variant.
void OnReceiveData(std::unique_ptr< char[]> data, size_t length)
Similar to HTTPCallback::OnReceiveData, but thread-safe.
std::atomic< bool > cancelled
Whether this callback has been cancelled, or not.
const std::string data
Data to send, if any.
~NetworkHTTPRequest()
Remove ourselves from the callback list.
NetworkHTTPRequest(std::string_view uri, HTTPCallback *callback, std::string &&data)
Create a new HTTP request.
HTTPThreadSafeCallback callback
Callback to send data back on.
const std::string uri
URI to connect to.
static void Connect(std::string_view uri, HTTPCallback *callback, std::string &&data="")
Connect to the given URI.
static void HTTPReceive()
Do the receiving for all HTTP connections.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
bool FileExists(std::string_view filename)
Test whether the given filename exists.
Functions for standard in/out file operations.
Basic functions to send and receive HTTP packets.
constexpr int HTTP_429_TOO_MANY_REQUESTS
HTTP error code for when the client is doing too many requests.
static std::mutex _http_mutex
Mutex to prevent concurrent access _http_requests.
static std::queue< std::unique_ptr< NetworkHTTPRequest > > _http_requests
HTTP requests that are currently running.
void NetworkHTTPInitialize()
Initialize the HTTP socket handler.
static std::vector< HTTPThreadSafeCallback * > _new_http_callbacks
Callbacks for the request that should be started.
static std::thread _http_thread
The thread running the HTTP requests.
static std::condition_variable _http_cv
Conditional variable to wake up the HTTP request thread.
static std::atomic< bool > _http_thread_exit
Whether to ask the HTTP request thread to stop.
static std::mutex _http_callback_mutex
Mutex to prevent concurrent access to _http_callbacks.
void CurlSetOption(CURL *curl, auto option, auto value)
Set some specific option and emit debug information upon failure.
static std::mutex _new_http_callback_mutex
Mutex to prevent concurrent access to _new_http_callbacks.
void HttpThread()
Thread entry point for the HTTP request thread.
void NetworkHTTPUninitialize()
Uninitialize the HTTP socket handler.
static std::vector< HTTPThreadSafeCallback * > _http_callbacks
Callback for the current requests.
Shared functions for implementations of HTTP requests.
static std::vector< HTTPThreadSafeCallback * > _new_http_callbacks
Callbacks for the request that should be started.
static std::mutex _http_callback_mutex
Mutex to prevent concurrent access to _http_callbacks.
static std::mutex _new_http_callback_mutex
Mutex to prevent concurrent access to _new_http_callbacks.
static std::vector< HTTPThreadSafeCallback * > _http_callbacks
Callback for the current requests.
std::string_view GetNetworkRevisionString()
Get the network version string used by this build.
Variables and function used internally.
Declaration of OTTD revision dependent variables.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
Callback for when the HTTP handler has something to tell us.
virtual void OnFailure()=0
An error has occurred and the connection has been closed.
bool StartNewThread(std::thread *thr, std::string_view name, TFn &&_Fx, TArgs &&... _Ax)
Start a new thread.
std::mutex lock
synchronization for playback status fields