DDraceNetwork Docs
http.h
Go to the documentation of this file.
1#ifndef ENGINE_SHARED_HTTP_H
2#define ENGINE_SHARED_HTTP_H
3
4#include <base/hash_ctxt.h>
5
7
8#include <algorithm>
9#include <atomic>
10#include <condition_variable>
11#include <deque>
12#include <mutex>
13#include <optional>
14#include <unordered_map>
15
16#include <engine/http.h>
17
18typedef struct _json_value json_value;
19class IStorage;
20
21enum class EHttpState
22{
23 ERROR = -1,
24 QUEUED,
25 RUNNING,
26 DONE,
27 ABORTED,
28};
29
30enum class HTTPLOG
31{
32 NONE,
33 FAILURE,
34 ALL,
35};
36
37enum class IPRESOLVE
38{
40 V4,
41 V6,
42};
43
45{
50};
51
53{
54 friend class CHttp;
55
56 enum class REQUEST
57 {
58 GET = 0,
59 HEAD,
60 POST,
61 POST_JSON,
62 };
63
64 static constexpr const char *GetRequestType(REQUEST Type)
65 {
66 switch(Type)
67 {
68 case REQUEST::GET:
69 return "GET";
70 case REQUEST::HEAD:
71 return "HEAD";
72 case REQUEST::POST:
74 return "POST";
75 }
76
77 // Unreachable, maybe assert instead?
78 return "UNKNOWN";
79 }
80
81 char m_aUrl[256] = {0};
82
83 void *m_pHeaders = nullptr;
84 unsigned char *m_pBody = nullptr;
85 size_t m_BodyLength = 0;
86
88 bool m_SkipByFileTime = true;
89
91 int64_t m_MaxResponseSize = -1;
92 int64_t m_IfModifiedSince = -1;
94
98
99 bool m_WriteToMemory = true;
100 bool m_WriteToFile = false;
101
102 uint64_t m_ResponseLength = 0;
103
104 // If `m_WriteToMemory` is true.
105 size_t m_BufferSize = 0;
106 unsigned char *m_pBuffer = nullptr;
107
108 // If `m_WriteToFile` is true.
109 IOHANDLE m_File = nullptr;
110 int m_StorageType = 0xdeadbeef;
114
115 std::atomic<double> m_Size{0.0};
116 std::atomic<double> m_Current{0.0};
117 std::atomic<int> m_Progress{0};
120
122
123 char m_aErr[256]; // 256 == CURL_ERROR_SIZE
124 std::atomic<EHttpState> m_State{EHttpState::QUEUED};
125 std::atomic<bool> m_Abort{false};
126 std::mutex m_WaitMutex;
127 std::condition_variable m_WaitCondition;
128
130 bool m_HeadersEnded = false;
131 std::optional<int64_t> m_ResultDate = {};
132 std::optional<int64_t> m_ResultLastModified = {};
133
134 bool ShouldSkipRequest();
135 // Abort the request with an error if `BeforeInit()` returns false.
136 bool BeforeInit();
137 bool ConfigureHandle(void *pHandle); // void * == CURL *
138 // `pHandle` can be nullptr if no handle was ever created for this request.
139 void OnCompletionInternal(void *pHandle, unsigned int Result); // void * == CURL *, unsigned int == CURLcode
140
141 // Abort the request if `OnHeader()` returns something other than
142 // `DataSize`. `pHeader` is NOT null-terminated.
143 size_t OnHeader(char *pHeader, size_t HeaderSize);
144 // Abort the request if `OnData()` returns something other than
145 // `DataSize`.
146 size_t OnData(char *pData, size_t DataSize);
147
148 static int ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr);
149 static size_t HeaderCallback(char *pData, size_t Size, size_t Number, void *pUser);
150 static size_t WriteCallback(char *pData, size_t Size, size_t Number, void *pUser);
151
152protected:
153 // These run on the curl thread now, DO NOT STALL THE THREAD
154 virtual void OnProgress() {}
156
157public:
158 CHttpRequest(const char *pUrl);
159 virtual ~CHttpRequest();
160
162 // Skip the download if the local file is newer or as new as the remote file.
168 // Download to memory only. Get the result via `Result*`.
170 {
171 m_WriteToMemory = true;
172 m_WriteToFile = false;
173 }
174 // Download to filesystem and memory.
175 void WriteToFileAndMemory(IStorage *pStorage, const char *pDest, int StorageType);
176 // Download to the filesystem only.
177 void WriteToFile(IStorage *pStorage, const char *pDest, int StorageType);
178 // Don't place the file in the specified location until
179 // `OnValidation(true)` has been called.
181 void ExpectSha256(const SHA256_DIGEST &Sha256) { m_ExpectedSha256 = Sha256; }
183 void Post(const unsigned char *pData, size_t DataLength)
184 {
186 m_BodyLength = DataLength;
187 m_pBody = (unsigned char *)malloc(std::max((size_t)1, DataLength));
188 mem_copy(m_pBody, pData, DataLength);
189 }
190 void PostJson(const char *pJson)
191 {
193 m_BodyLength = str_length(pJson);
194 m_pBody = (unsigned char *)malloc(m_BodyLength);
196 }
197 void Header(const char *pNameColonValue);
198 void HeaderString(const char *pName, const char *pValue)
199 {
200 char aHeader[256];
201 str_format(aHeader, sizeof(aHeader), "%s: %s", pName, pValue);
202 Header(aHeader);
203 }
204 void HeaderInt(const char *pName, int Value)
205 {
206 char aHeader[256];
207 str_format(aHeader, sizeof(aHeader), "%s: %d", pName, Value);
208 Header(aHeader);
209 }
210
211 const char *Dest()
212 {
213 if(m_WriteToFile)
214 {
215 return m_aDest;
216 }
217 else
218 {
219 return nullptr;
220 }
221 }
222
223 double Current() const { return m_Current.load(std::memory_order_relaxed); }
224 double Size() const { return m_Size.load(std::memory_order_relaxed); }
225 int Progress() const { return m_Progress.load(std::memory_order_relaxed); }
226 EHttpState State() const { return m_State; }
227 bool Done() const
228 {
231 }
232 void Abort() { m_Abort = true; }
233 // If `ValidateBeforeOverwrite` is set, this needs to be called after
234 // validating that the downloaded file has the correct format.
235 //
236 // If called with `true`, it'll place the downloaded file at the final
237 // destination, if called with `false`, it'll instead delete the
238 // temporary downloaded file.
239 void OnValidation(bool Success);
240
241 void Wait();
242
243 void Result(unsigned char **ppResult, size_t *pResultLength) const;
244 json_value *ResultJson() const;
245 const SHA256_DIGEST &ResultSha256() const;
246
247 int StatusCode() const;
248 std::optional<int64_t> ResultAgeSeconds() const;
249 std::optional<int64_t> ResultLastModified() const;
250};
251
252inline std::unique_ptr<CHttpRequest> HttpHead(const char *pUrl)
253{
254 auto pResult = std::make_unique<CHttpRequest>(pUrl);
255 pResult->Head();
256 return pResult;
257}
258
259inline std::unique_ptr<CHttpRequest> HttpGet(const char *pUrl)
260{
261 return std::make_unique<CHttpRequest>(pUrl);
262}
263
264inline std::unique_ptr<CHttpRequest> HttpGetFile(const char *pUrl, IStorage *pStorage, const char *pOutputFile, int StorageType)
265{
266 std::unique_ptr<CHttpRequest> pResult = HttpGet(pUrl);
267 pResult->WriteToFile(pStorage, pOutputFile, StorageType);
268 pResult->Timeout(CTimeout{4000, 0, 500, 5});
269 return pResult;
270}
271
272inline std::unique_ptr<CHttpRequest> HttpGetBoth(const char *pUrl, IStorage *pStorage, const char *pOutputFile, int StorageType)
273{
274 std::unique_ptr<CHttpRequest> pResult = HttpGet(pUrl);
275 pResult->WriteToFileAndMemory(pStorage, pOutputFile, StorageType);
276 pResult->Timeout(CTimeout{4000, 0, 500, 5});
277 return pResult;
278}
279
280inline std::unique_ptr<CHttpRequest> HttpPost(const char *pUrl, const unsigned char *pData, size_t DataLength)
281{
282 auto pResult = std::make_unique<CHttpRequest>(pUrl);
283 pResult->Post(pData, DataLength);
284 pResult->Timeout(CTimeout{4000, 15000, 500, 5});
285 return pResult;
286}
287
288inline std::unique_ptr<CHttpRequest> HttpPostJson(const char *pUrl, const char *pJson)
289{
290 auto pResult = std::make_unique<CHttpRequest>(pUrl);
291 pResult->PostJson(pJson);
292 pResult->Timeout(CTimeout{4000, 15000, 500, 5});
293 return pResult;
294}
295
296void EscapeUrl(char *pBuf, int Size, const char *pStr);
297
298template<int N>
299void EscapeUrl(char (&aBuf)[N], const char *pStr)
300{
301 EscapeUrl(aBuf, N, pStr);
302}
303
305
306// In an ideal world this would be a kernel interface
307class CHttp : public IHttp
308{
310 {
314 };
315
316 void *m_pThread = nullptr;
317
318 std::mutex m_Lock{};
319 std::condition_variable m_Cv{};
320 std::atomic<EState> m_State = UNINITIALIZED;
321 std::deque<std::shared_ptr<CHttpRequest>> m_PendingRequests{};
322 std::unordered_map<void *, std::shared_ptr<CHttpRequest>> m_RunningRequests{}; // void * == CURL *
323 std::chrono::milliseconds m_ShutdownDelay{};
324 std::optional<std::chrono::time_point<std::chrono::steady_clock>> m_ShutdownTime{};
325 std::atomic<bool> m_Shutdown = false;
326
327 // Only to be used with curl_multi_wakeup
328 void *m_pMultiH = nullptr; // void * == CURLM *
329
330 static void ThreadMain(void *pUser);
331 void RunLoop();
332
333public:
334 // Startup
335 bool Init(std::chrono::milliseconds ShutdownDelay);
336
337 // User
338 virtual void Run(std::shared_ptr<IHttpRequest> pRequest) override;
339 void Shutdown() override;
340 ~CHttp();
341};
342
343#endif // ENGINE_SHARED_HTTP_H
const SHA256_DIGEST SHA256_ZEROED
Definition: hash.cpp:6
Definition: http.h:53
void FailOnErrorStatus(bool FailOnErrorStatus)
Definition: http.h:167
void WriteToFileAndMemory(IStorage *pStorage, const char *pDest, int StorageType)
Definition: http.cpp:523
bool m_SkipByFileTime
Definition: http.h:88
static size_t HeaderCallback(char *pData, size_t Size, size_t Number, void *pUser)
Definition: http.cpp:351
const SHA256_DIGEST & ResultSha256() const
Definition: http.cpp:559
int64_t m_MaxResponseSize
Definition: http.h:91
static int ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr)
Definition: http.cpp:362
REQUEST
Definition: http.h:57
bool ConfigureHandle(void *pHandle)
Definition: http.cpp:149
HTTPLOG m_LogProgress
Definition: http.h:118
void * m_pHeaders
Definition: http.h:83
bool m_HeadersEnded
Definition: http.h:130
const char * Dest()
Definition: http.h:211
char m_aUrl[256]
Definition: http.h:81
SHA256_DIGEST m_ActualSha256
Definition: http.h:95
std::mutex m_WaitMutex
Definition: http.h:126
void Result(unsigned char **ppResult, size_t *pResultLength) const
Definition: http.cpp:543
virtual ~CHttpRequest()
Definition: http.cpp:72
char m_aDestAbsolute[IO_MAX_PATH_LENGTH]
Definition: http.h:112
std::atomic< int > m_Progress
Definition: http.h:117
void IpResolve(IPRESOLVE IpResolve)
Definition: http.h:166
void Abort()
Definition: http.h:232
std::optional< int64_t > m_ResultLastModified
Definition: http.h:132
REQUEST m_Type
Definition: http.h:93
void Header(const char *pNameColonValue)
Definition: http.cpp:529
static constexpr const char * GetRequestType(REQUEST Type)
Definition: http.h:64
void Wait()
Definition: http.cpp:534
json_value * ResultJson() const
Definition: http.cpp:551
void MaxResponseSize(int64_t MaxResponseSize)
Definition: http.h:164
size_t m_BodyLength
Definition: http.h:85
double Size() const
Definition: http.h:224
IPRESOLVE m_IpResolve
Definition: http.h:119
SHA256_DIGEST m_ExpectedSha256
Definition: http.h:97
void WriteToMemory()
Definition: http.h:169
std::optional< int64_t > ResultAgeSeconds() const
Definition: http.cpp:571
unsigned char * m_pBuffer
Definition: http.h:106
bool m_WriteToMemory
Definition: http.h:99
void OnCompletionInternal(void *pHandle, unsigned int Result)
Definition: http.cpp:372
int m_StorageType
Definition: http.h:110
void WriteToFile(IStorage *pStorage, const char *pDest, int StorageType)
Definition: http.cpp:506
void Timeout(CTimeout Timeout)
Definition: http.h:161
std::atomic< double > m_Size
Definition: http.h:115
int StatusCode() const
Definition: http.cpp:565
EHttpState State() const
Definition: http.h:226
bool ShouldSkipRequest()
Definition: http.cpp:106
virtual void OnCompletion(EHttpState State)
Definition: http.h:155
void Head()
Definition: http.h:182
void ExpectSha256(const SHA256_DIGEST &Sha256)
Definition: http.h:181
std::atomic< double > m_Current
Definition: http.h:116
std::optional< int64_t > ResultLastModified() const
Definition: http.cpp:581
int Progress() const
Definition: http.h:225
size_t OnData(char *pData, size_t DataSize)
Definition: http.cpp:311
static size_t WriteCallback(char *pData, size_t Size, size_t Number, void *pUser)
Definition: http.cpp:357
std::optional< int64_t > m_ResultDate
Definition: http.h:131
size_t m_BufferSize
Definition: http.h:105
void HeaderInt(const char *pName, int Value)
Definition: http.h:204
virtual void OnProgress()
Definition: http.h:154
void Post(const unsigned char *pData, size_t DataLength)
Definition: http.h:183
CTimeout m_Timeout
Definition: http.h:90
bool m_WriteToFile
Definition: http.h:100
uint64_t m_ResponseLength
Definition: http.h:102
char m_aDestAbsoluteTmp[IO_MAX_PATH_LENGTH]
Definition: http.h:111
void ValidateBeforeOverwrite(bool ValidateBeforeOverwrite)
Definition: http.h:180
int m_StatusCode
Definition: http.h:129
IOHANDLE m_File
Definition: http.h:109
unsigned char * m_pBody
Definition: http.h:84
void OnValidation(bool Success)
Definition: http.cpp:481
std::atomic< EHttpState > m_State
Definition: http.h:124
std::atomic< bool > m_Abort
Definition: http.h:125
std::condition_variable m_WaitCondition
Definition: http.h:127
char m_aDest[IO_MAX_PATH_LENGTH]
Definition: http.h:113
int64_t m_IfModifiedSince
Definition: http.h:92
SHA256_CTX m_ActualSha256Ctx
Definition: http.h:96
bool BeforeInit()
Definition: http.cpp:120
CHttpRequest(const char *pUrl)
Definition: http.cpp:66
void HeaderString(const char *pName, const char *pValue)
Definition: http.h:198
double Current() const
Definition: http.h:223
bool m_ValidateBeforeOverwrite
Definition: http.h:87
char m_aErr[256]
Definition: http.h:123
bool Done() const
Definition: http.h:227
void PostJson(const char *pJson)
Definition: http.h:190
void SkipByFileTime(bool SkipByFileTime)
Definition: http.h:163
void LogProgress(HTTPLOG LogProgress)
Definition: http.h:165
bool m_FailOnErrorStatus
Definition: http.h:121
size_t OnHeader(char *pHeader, size_t HeaderSize)
Definition: http.cpp:265
Definition: http.h:308
std::atomic< bool > m_Shutdown
Definition: http.h:325
virtual void Run(std::shared_ptr< IHttpRequest > pRequest) override
Definition: http.cpp:798
std::chrono::milliseconds m_ShutdownDelay
Definition: http.h:323
~CHttp()
Definition: http.cpp:823
std::atomic< EState > m_State
Definition: http.h:320
std::unordered_map< void *, std::shared_ptr< CHttpRequest > > m_RunningRequests
Definition: http.h:322
EState
Definition: http.h:310
@ ERROR
Definition: http.h:313
@ UNINITIALIZED
Definition: http.h:311
@ RUNNING
Definition: http.h:312
void Shutdown() override
Definition: http.cpp:813
std::optional< std::chrono::time_point< std::chrono::steady_clock > > m_ShutdownTime
Definition: http.h:324
std::condition_variable m_Cv
Definition: http.h:319
std::mutex m_Lock
Definition: http.h:318
std::deque< std::shared_ptr< CHttpRequest > > m_PendingRequests
Definition: http.h:321
static void ThreadMain(void *pUser)
Definition: http.cpp:608
void * m_pMultiH
Definition: http.h:328
void RunLoop()
Definition: http.cpp:614
bool Init(std::chrono::milliseconds ShutdownDelay)
Definition: http.cpp:587
void * m_pThread
Definition: http.h:316
Definition: http.h:8
Definition: http.h:12
Definition: storage.h:20
struct _json_value json_value
Definition: serverbrowser.h:17
void mem_copy(void *dest, const void *source, size_t size)
Definition: system.cpp:174
int str_length(const char *str)
Definition: system.cpp:2794
void * IOHANDLE
Definition: logger.h:12
std::unique_ptr< CHttpRequest > HttpGet(const char *pUrl)
Definition: http.h:259
std::unique_ptr< CHttpRequest > HttpHead(const char *pUrl)
Definition: http.h:252
std::unique_ptr< CHttpRequest > HttpPost(const char *pUrl, const unsigned char *pData, size_t DataLength)
Definition: http.h:280
IPRESOLVE
Definition: http.h:38
std::unique_ptr< CHttpRequest > HttpGetFile(const char *pUrl, IStorage *pStorage, const char *pOutputFile, int StorageType)
Definition: http.h:264
void EscapeUrl(char *pBuf, int Size, const char *pStr)
Definition: http.cpp:52
std::unique_ptr< CHttpRequest > HttpGetBoth(const char *pUrl, IStorage *pStorage, const char *pOutputFile, int StorageType)
Definition: http.h:272
std::unique_ptr< CHttpRequest > HttpPostJson(const char *pUrl, const char *pJson)
Definition: http.h:288
EHttpState
Definition: http.h:22
bool HttpHasIpresolveBug()
Definition: http.cpp:59
HTTPLOG
Definition: http.h:31
Definition: http.h:45
long ConnectTimeoutMs
Definition: http.h:46
long LowSpeedLimit
Definition: http.h:48
long LowSpeedTime
Definition: http.h:49
long TimeoutMs
Definition: http.h:47
Definition: hash.h:15
#define str_format
Definition: system.cpp:2829
@ IO_MAX_PATH_LENGTH
Definition: types.h:43