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 int64_t m_MaxResponseSize = -1;
89 int64_t m_IfModifiedSince = -1;
91
95
96 bool m_WriteToFile = false;
97
98 uint64_t m_ResponseLength = 0;
99
100 // If `m_WriteToFile` is false.
101 size_t m_BufferSize = 0;
102 unsigned char *m_pBuffer = nullptr;
103
104 // If `m_WriteToFile` is true.
105 IOHANDLE m_File = nullptr;
108
109 std::atomic<double> m_Size{0.0};
110 std::atomic<double> m_Current{0.0};
111 std::atomic<int> m_Progress{0};
114
116
117 char m_aErr[256]; // 256 == CURL_ERROR_SIZE
118 std::atomic<EHttpState> m_State{EHttpState::QUEUED};
119 std::atomic<bool> m_Abort{false};
120 std::mutex m_WaitMutex;
121 std::condition_variable m_WaitCondition;
122
124 bool m_HeadersEnded = false;
125 std::optional<int64_t> m_ResultDate = {};
126 std::optional<int64_t> m_ResultLastModified = {};
127
128 // Abort the request with an error if `BeforeInit()` returns false.
129 bool BeforeInit();
130 bool ConfigureHandle(void *pHandle); // void * == CURL *
131 // `pHandle` can be nullptr if no handle was ever created for this request.
132 void OnCompletionInternal(void *pHandle, unsigned int Result); // void * == CURL *, unsigned int == CURLcode
133
134 // Abort the request if `OnHeader()` returns something other than
135 // `DataSize`. `pHeader` is NOT null-terminated.
136 size_t OnHeader(char *pHeader, size_t HeaderSize);
137 // Abort the request if `OnData()` returns something other than
138 // `DataSize`.
139 size_t OnData(char *pData, size_t DataSize);
140
141 static int ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr);
142 static size_t HeaderCallback(char *pData, size_t Size, size_t Number, void *pUser);
143 static size_t WriteCallback(char *pData, size_t Size, size_t Number, void *pUser);
144
145protected:
146 // These run on the curl thread now, DO NOT STALL THE THREAD
147 virtual void OnProgress() {}
149
150public:
151 CHttpRequest(const char *pUrl);
152 virtual ~CHttpRequest();
153
160 void WriteToFile(IStorage *pStorage, const char *pDest, int StorageType);
161 void ExpectSha256(const SHA256_DIGEST &Sha256) { m_ExpectedSha256 = Sha256; }
163 void Post(const unsigned char *pData, size_t DataLength)
164 {
166 m_BodyLength = DataLength;
167 m_pBody = (unsigned char *)malloc(std::max((size_t)1, DataLength));
168 mem_copy(m_pBody, pData, DataLength);
169 }
170 void PostJson(const char *pJson)
171 {
173 m_BodyLength = str_length(pJson);
174 m_pBody = (unsigned char *)malloc(m_BodyLength);
176 }
177 void Header(const char *pNameColonValue);
178 void HeaderString(const char *pName, const char *pValue)
179 {
180 char aHeader[256];
181 str_format(aHeader, sizeof(aHeader), "%s: %s", pName, pValue);
182 Header(aHeader);
183 }
184 void HeaderInt(const char *pName, int Value)
185 {
186 char aHeader[256];
187 str_format(aHeader, sizeof(aHeader), "%s: %d", pName, Value);
188 Header(aHeader);
189 }
190
191 const char *Dest()
192 {
193 if(m_WriteToFile)
194 {
195 return m_aDest;
196 }
197 else
198 {
199 return nullptr;
200 }
201 }
202
203 double Current() const { return m_Current.load(std::memory_order_relaxed); }
204 double Size() const { return m_Size.load(std::memory_order_relaxed); }
205 int Progress() const { return m_Progress.load(std::memory_order_relaxed); }
206 EHttpState State() const { return m_State; }
207 bool Done() const
208 {
211 }
212 void Abort() { m_Abort = true; }
213
214 void Wait();
215
216 void Result(unsigned char **ppResult, size_t *pResultLength) const;
217 json_value *ResultJson() const;
218 const SHA256_DIGEST &ResultSha256() const;
219
220 int StatusCode() const;
221 std::optional<int64_t> ResultAgeSeconds() const;
222 std::optional<int64_t> ResultLastModified() const;
223};
224
225inline std::unique_ptr<CHttpRequest> HttpHead(const char *pUrl)
226{
227 auto pResult = std::make_unique<CHttpRequest>(pUrl);
228 pResult->Head();
229 return pResult;
230}
231
232inline std::unique_ptr<CHttpRequest> HttpGet(const char *pUrl)
233{
234 return std::make_unique<CHttpRequest>(pUrl);
235}
236
237inline std::unique_ptr<CHttpRequest> HttpGetFile(const char *pUrl, IStorage *pStorage, const char *pOutputFile, int StorageType)
238{
239 std::unique_ptr<CHttpRequest> pResult = HttpGet(pUrl);
240 pResult->WriteToFile(pStorage, pOutputFile, StorageType);
241 pResult->Timeout(CTimeout{4000, 0, 500, 5});
242 return pResult;
243}
244
245inline std::unique_ptr<CHttpRequest> HttpPost(const char *pUrl, const unsigned char *pData, size_t DataLength)
246{
247 auto pResult = std::make_unique<CHttpRequest>(pUrl);
248 pResult->Post(pData, DataLength);
249 pResult->Timeout(CTimeout{4000, 15000, 500, 5});
250 return pResult;
251}
252
253inline std::unique_ptr<CHttpRequest> HttpPostJson(const char *pUrl, const char *pJson)
254{
255 auto pResult = std::make_unique<CHttpRequest>(pUrl);
256 pResult->PostJson(pJson);
257 pResult->Timeout(CTimeout{4000, 15000, 500, 5});
258 return pResult;
259}
260
261void EscapeUrl(char *pBuf, int Size, const char *pStr);
263
264// In an ideal world this would be a kernel interface
265class CHttp : public IHttp
266{
268 {
272 };
273
274 void *m_pThread = nullptr;
275
276 std::mutex m_Lock{};
277 std::condition_variable m_Cv{};
278 std::atomic<EState> m_State = UNINITIALIZED;
279 std::deque<std::shared_ptr<CHttpRequest>> m_PendingRequests{};
280 std::unordered_map<void *, std::shared_ptr<CHttpRequest>> m_RunningRequests{}; // void * == CURL *
281 std::chrono::milliseconds m_ShutdownDelay{};
282 std::optional<std::chrono::time_point<std::chrono::steady_clock>> m_ShutdownTime{};
283 std::atomic<bool> m_Shutdown = false;
284
285 // Only to be used with curl_multi_wakeup
286 void *m_pMultiH = nullptr; // void * == CURLM *
287
288 static void ThreadMain(void *pUser);
289 void RunLoop();
290
291public:
292 // Startup
293 bool Init(std::chrono::milliseconds ShutdownDelay);
294
295 // User
296 virtual void Run(std::shared_ptr<IHttpRequest> pRequest) override;
297 void Shutdown() override;
298 ~CHttp();
299};
300
301#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:159
static size_t HeaderCallback(char *pData, size_t Size, size_t Number, void *pUser)
Definition: http.cpp:300
const SHA256_DIGEST & ResultSha256() const
Definition: http.cpp:437
int64_t m_MaxResponseSize
Definition: http.h:88
static int ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr)
Definition: http.cpp:311
REQUEST
Definition: http.h:57
bool ConfigureHandle(void *pHandle)
Definition: http.cpp:100
HTTPLOG m_LogProgress
Definition: http.h:112
void * m_pHeaders
Definition: http.h:83
bool m_HeadersEnded
Definition: http.h:124
const char * Dest()
Definition: http.h:191
char m_aUrl[256]
Definition: http.h:81
SHA256_DIGEST m_ActualSha256
Definition: http.h:92
std::mutex m_WaitMutex
Definition: http.h:120
void Result(unsigned char **ppResult, size_t *pResultLength) const
Definition: http.cpp:421
virtual ~CHttpRequest()
Definition: http.cpp:72
char m_aDestAbsolute[IO_MAX_PATH_LENGTH]
Definition: http.h:106
std::atomic< int > m_Progress
Definition: http.h:111
void IpResolve(IPRESOLVE IpResolve)
Definition: http.h:158
void Abort()
Definition: http.h:212
std::optional< int64_t > m_ResultLastModified
Definition: http.h:126
REQUEST m_Type
Definition: http.h:90
void Header(const char *pNameColonValue)
Definition: http.cpp:407
static constexpr const char * GetRequestType(REQUEST Type)
Definition: http.h:64
void Wait()
Definition: http.cpp:412
json_value * ResultJson() const
Definition: http.cpp:429
void MaxResponseSize(int64_t MaxResponseSize)
Definition: http.h:155
size_t m_BodyLength
Definition: http.h:85
double Size() const
Definition: http.h:204
IPRESOLVE m_IpResolve
Definition: http.h:113
SHA256_DIGEST m_ExpectedSha256
Definition: http.h:94
std::optional< int64_t > ResultAgeSeconds() const
Definition: http.cpp:449
unsigned char * m_pBuffer
Definition: http.h:102
void OnCompletionInternal(void *pHandle, unsigned int Result)
Definition: http.cpp:321
void WriteToFile(IStorage *pStorage, const char *pDest, int StorageType)
Definition: http.cpp:393
void Timeout(CTimeout Timeout)
Definition: http.h:154
std::atomic< double > m_Size
Definition: http.h:109
int StatusCode() const
Definition: http.cpp:443
EHttpState State() const
Definition: http.h:206
virtual void OnCompletion(EHttpState State)
Definition: http.h:148
void Head()
Definition: http.h:162
void ExpectSha256(const SHA256_DIGEST &Sha256)
Definition: http.h:161
std::atomic< double > m_Current
Definition: http.h:110
std::optional< int64_t > ResultLastModified() const
Definition: http.cpp:459
int Progress() const
Definition: http.h:205
size_t OnData(char *pData, size_t DataSize)
Definition: http.cpp:262
static size_t WriteCallback(char *pData, size_t Size, size_t Number, void *pUser)
Definition: http.cpp:306
std::optional< int64_t > m_ResultDate
Definition: http.h:125
size_t m_BufferSize
Definition: http.h:101
void HeaderInt(const char *pName, int Value)
Definition: http.h:184
virtual void OnProgress()
Definition: http.h:147
void Post(const unsigned char *pData, size_t DataLength)
Definition: http.h:163
CTimeout m_Timeout
Definition: http.h:87
bool m_WriteToFile
Definition: http.h:96
uint64_t m_ResponseLength
Definition: http.h:98
int m_StatusCode
Definition: http.h:123
IOHANDLE m_File
Definition: http.h:105
unsigned char * m_pBody
Definition: http.h:84
std::atomic< EHttpState > m_State
Definition: http.h:118
std::atomic< bool > m_Abort
Definition: http.h:119
std::condition_variable m_WaitCondition
Definition: http.h:121
char m_aDest[IO_MAX_PATH_LENGTH]
Definition: http.h:107
int64_t m_IfModifiedSince
Definition: http.h:89
SHA256_CTX m_ActualSha256Ctx
Definition: http.h:93
void IfModifiedSince(int64_t IfModifiedSince)
Definition: http.h:156
bool BeforeInit()
Definition: http.cpp:80
CHttpRequest(const char *pUrl)
Definition: http.cpp:66
void HeaderString(const char *pName, const char *pValue)
Definition: http.h:178
double Current() const
Definition: http.h:203
char m_aErr[256]
Definition: http.h:117
bool Done() const
Definition: http.h:207
void PostJson(const char *pJson)
Definition: http.h:170
void LogProgress(HTTPLOG LogProgress)
Definition: http.h:157
bool m_FailOnErrorStatus
Definition: http.h:115
size_t OnHeader(char *pHeader, size_t HeaderSize)
Definition: http.cpp:216
Definition: http.h:266
std::atomic< bool > m_Shutdown
Definition: http.h:283
virtual void Run(std::shared_ptr< IHttpRequest > pRequest) override
Definition: http.cpp:664
std::chrono::milliseconds m_ShutdownDelay
Definition: http.h:281
~CHttp()
Definition: http.cpp:689
std::atomic< EState > m_State
Definition: http.h:278
std::unordered_map< void *, std::shared_ptr< CHttpRequest > > m_RunningRequests
Definition: http.h:280
EState
Definition: http.h:268
@ ERROR
Definition: http.h:271
@ UNINITIALIZED
Definition: http.h:269
@ RUNNING
Definition: http.h:270
void Shutdown() override
Definition: http.cpp:679
std::optional< std::chrono::time_point< std::chrono::steady_clock > > m_ShutdownTime
Definition: http.h:282
std::condition_variable m_Cv
Definition: http.h:277
std::mutex m_Lock
Definition: http.h:276
std::deque< std::shared_ptr< CHttpRequest > > m_PendingRequests
Definition: http.h:279
static void ThreadMain(void *pUser)
Definition: http.cpp:486
void * m_pMultiH
Definition: http.h:286
void RunLoop()
Definition: http.cpp:492
bool Init(std::chrono::milliseconds ShutdownDelay)
Definition: http.cpp:465
void * m_pThread
Definition: http.h:274
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:2754
void * IOHANDLE
Definition: logger.h:11
std::unique_ptr< CHttpRequest > HttpGet(const char *pUrl)
Definition: http.h:232
std::unique_ptr< CHttpRequest > HttpHead(const char *pUrl)
Definition: http.h:225
std::unique_ptr< CHttpRequest > HttpPost(const char *pUrl, const unsigned char *pData, size_t DataLength)
Definition: http.h:245
IPRESOLVE
Definition: http.h:38
std::unique_ptr< CHttpRequest > HttpGetFile(const char *pUrl, IStorage *pStorage, const char *pOutputFile, int StorageType)
Definition: http.h:237
void EscapeUrl(char *pBuf, int Size, const char *pStr)
Definition: http.cpp:52
std::unique_ptr< CHttpRequest > HttpPostJson(const char *pUrl, const char *pJson)
Definition: http.h:253
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:2789
@ IO_MAX_PATH_LENGTH
Definition: types.h:43