Rigs of Rods 2026.01
Soft-body Physics Simulation
Loading...
Searching...
No Matches
CurlHelpers.cpp
Go to the documentation of this file.
1/*
2 This source file is part of Rigs of Rods
3 Copyright 2005-2012 Pierre-Michel Ricordel
4 Copyright 2007-2012 Thomas Fischer
5 Copyright 2013-2023 Petr Ohlidal
6
7 For more information, see http://www.rigsofrods.org/
8
9 Rigs of Rods is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 3, as
11 published by the Free Software Foundation.
12
13 Rigs of Rods is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "Application.h"
23#include "CurlHelpers.h"
24#include "GameContext.h"
25#include "RoRVersion.h"
26#include "ScriptEvents.h"
27#include "ServerScriptEngine.h"
29
30#include <fmt/format.h>
31
32using namespace RoR;
33
34#ifdef USE_CURL
35# include <curl/curl.h>
36# include <curl/easy.h>
37
38static size_t CurlStringWriteFunc(void *ptr, size_t size, size_t nmemb, std::string* data)
39{
40 data->append((char*)ptr, size * nmemb);
41 return size * nmemb;
42}
43
44static size_t CurlProgressFunc(void* ptr, double filesize_B, double downloaded_B)
45{
46 // Ensure that the file to be downloaded is not empty because that would cause a division by zero error later on
47 if (filesize_B <= 0.0)
48 {
49 return 0;
50 }
51
52 CurlTaskContext* context = (CurlTaskContext*)ptr;
53
54 double perc = (downloaded_B / filesize_B) * 100;
55
56 if (perc > context->ctc_old_perc && context->ctc_msg_progress != MSG_INVALID)
57 {
60 args->arg2ex = perc;
61 args->arg5ex = fmt::format("{} {}\n{}: {:.2f}{}\n{}: {:.2f}{}", "Downloading",
62 context->ctc_displayname, "File size", filesize_B/(1024 * 1024), "MB", "Downloaded", downloaded_B/(1024 * 1024), "MB");
63
65 }
66
67 context->ctc_old_perc = perc;
68
69 // If you don't return 0, the transfer will be aborted - see the documentation
70 return 0;
71}
72
73bool RoR::GetUrlAsString(const std::string& url, CURLcode& curl_result, long& response_code, std::string& response_payload)
74{
75 std::string response_header;
76 std::string user_agent = fmt::format("{}/{}", "Rigs of Rods Client", ROR_VERSION_STRING);
77
78 CURL *curl = curl_easy_init();
79 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
80 curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
81#ifdef _WIN32
82 curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
83#endif // _WIN32
84 curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "gzip");
85 curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent.c_str());
86 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlStringWriteFunc);
87 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_payload);
88 curl_easy_setopt(curl, CURLOPT_HEADERDATA, &response_header);
89
90 curl_result = curl_easy_perform(curl);
91 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
92
93 curl_easy_cleanup(curl);
94 curl = nullptr;
95
96 if (curl_result != CURLE_OK || response_code != 200)
97 {
98 Ogre::LogManager::getSingleton().stream()
99 << "[RoR|CURL] Failed to retrieve url '"<<url<<"' as string;"
100 << " Error: '" << curl_easy_strerror(curl_result) << "'; HTTP status code: " << response_code;
101 response_payload = curl_easy_strerror(curl_result);
102 return false;
103 }
104
105 return true;
106}
107
109{
110 std::string data;
111 CURLcode curl_result = CURLE_OK;
112 long http_response = 0;
113 bool result = GetUrlAsString(task.ctc_url, /*out:*/curl_result, /*out:*/http_response, /*out:*/data);
114
115 if (!result && task.ctc_msg_failure != MSG_INVALID)
116 {
117 // `data` contains the `curl_easy_strerror()` message (already logged)
118 ScriptEventArgs* args = new ScriptEventArgs();
120 args->arg2ex = http_response;
121 args->arg3ex = curl_result;
122 args->arg5ex = data;
123
125 }
126 else if (result && task.ctc_msg_failure != MSG_INVALID)
127 {
128 // `data` contains the `CURL_WRITEDATA` payload.
129 ScriptEventArgs* args = new ScriptEventArgs();
131 args->arg2ex = http_response;
132 args->arg3ex = curl_result;
133 args->arg5ex = data;
134
136 }
137
138 return result;
139}
140
141#endif //USE_CURL
Central state/object manager and communications hub.
static size_t CurlStringWriteFunc(void *ptr, size_t size, size_t nmemb, std::string *data)
static size_t CurlProgressFunc(void *ptr, double filesize_B, double downloaded_B)
Game state manager and message-queue provider.
const char *const ROR_VERSION_STRING
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
@ MSG_INVALID
Definition Application.h:85
GameContext * GetGameContext()
bool GetUrlAsStringMQ(CurlTaskContext task)
@ ASTHREADSTATUS_CURLSTRING_PROGRESS
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 percentage, arg#3 unused,...
@ ASTHREADSTATUS_CURLSTRING_FAILURE
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 HTTP code, arg#3 CURLcode,...
@ ASTHREADSTATUS_CURLSTRING_SUCCESS
Args of RoR::SE_ANGELSCRIPT_THREAD_STATUS: arg#1 type, arg#2 HTTP code, arg#3 CURLcode,...
bool GetUrlAsString(const std::string &url, CURLcode &curl_result, long &response_code, std::string &response_payload)
std::string ctc_displayname
Definition CurlHelpers.h:36
std::string ctc_url
Definition CurlHelpers.h:37
MsgType ctc_msg_failure
Sent on failure; Payload: RoR::ScriptEventArgs (see 'gameplay/ScriptEvents.h') with args for RoR::SE_...
Definition CurlHelpers.h:41
Unified game event system - all requests and state changes are reported using a message.
Definition GameContext.h:52
Args for eventCallbackEx() queued via MSG_SIM_SCRIPT_EVENT_TRIGGERED See descriptions at enum RoR::sc...