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