mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-09 17:48:19 +00:00
Parse Date
and Last-Modified
HTTP headers
This commit is contained in:
parent
2d17097c91
commit
5603d284bf
|
@ -1 +1 @@
|
||||||
Subproject commit a4fbe0e52338a129bc3ac2e3a1de54de1d175279
|
Subproject commit 87fbb57839080f40d16cd77d8ad11ae91bb9c849
|
|
@ -148,6 +148,8 @@ bool CHttpRequest::ConfigureHandle(void *pHandle)
|
||||||
curl_easy_setopt(pH, CURLOPT_USERAGENT, GAME_NAME " " GAME_RELEASE_VERSION " (" CONF_PLATFORM_STRING "; " CONF_ARCH_STRING ")");
|
curl_easy_setopt(pH, CURLOPT_USERAGENT, GAME_NAME " " GAME_RELEASE_VERSION " (" CONF_PLATFORM_STRING "; " CONF_ARCH_STRING ")");
|
||||||
curl_easy_setopt(pH, CURLOPT_ACCEPT_ENCODING, ""); // Use any compression algorithm supported by libcurl.
|
curl_easy_setopt(pH, CURLOPT_ACCEPT_ENCODING, ""); // Use any compression algorithm supported by libcurl.
|
||||||
|
|
||||||
|
curl_easy_setopt(pH, CURLOPT_HEADERDATA, this);
|
||||||
|
curl_easy_setopt(pH, CURLOPT_HEADERFUNCTION, HeaderCallback);
|
||||||
curl_easy_setopt(pH, CURLOPT_WRITEDATA, this);
|
curl_easy_setopt(pH, CURLOPT_WRITEDATA, this);
|
||||||
curl_easy_setopt(pH, CURLOPT_WRITEFUNCTION, WriteCallback);
|
curl_easy_setopt(pH, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||||
curl_easy_setopt(pH, CURLOPT_NOPROGRESS, 0L);
|
curl_easy_setopt(pH, CURLOPT_NOPROGRESS, 0L);
|
||||||
|
@ -206,6 +208,52 @@ bool CHttpRequest::ConfigureHandle(void *pHandle)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CHttpRequest::OnHeader(char *pHeader, size_t HeaderSize)
|
||||||
|
{
|
||||||
|
// `pHeader` is NOT null-terminated.
|
||||||
|
// `pHeader` has a trailing newline.
|
||||||
|
|
||||||
|
if(HeaderSize <= 1)
|
||||||
|
{
|
||||||
|
m_HeadersEnded = true;
|
||||||
|
return HeaderSize;
|
||||||
|
}
|
||||||
|
if(m_HeadersEnded)
|
||||||
|
{
|
||||||
|
// redirect, clear old headers
|
||||||
|
m_HeadersEnded = false;
|
||||||
|
m_ResultDate = {};
|
||||||
|
m_ResultLastModified = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char DATE[] = "Date: ";
|
||||||
|
static const char LAST_MODIFIED[] = "Last-Modified: ";
|
||||||
|
|
||||||
|
// Trailing newline and null termination evens out.
|
||||||
|
if(HeaderSize - 1 >= sizeof(DATE) - 1 && str_startswith_nocase(pHeader, DATE))
|
||||||
|
{
|
||||||
|
char aValue[128];
|
||||||
|
str_truncate(aValue, sizeof(aValue), pHeader + (sizeof(DATE) - 1), HeaderSize - (sizeof(DATE) - 1) - 1);
|
||||||
|
int64_t Value = curl_getdate(aValue, nullptr);
|
||||||
|
if(Value != -1)
|
||||||
|
{
|
||||||
|
m_ResultDate = Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(HeaderSize - 1 >= sizeof(LAST_MODIFIED) - 1 && str_startswith_nocase(pHeader, LAST_MODIFIED))
|
||||||
|
{
|
||||||
|
char aValue[128];
|
||||||
|
str_truncate(aValue, sizeof(aValue), pHeader + (sizeof(LAST_MODIFIED) - 1), HeaderSize - (sizeof(LAST_MODIFIED) - 1) - 1);
|
||||||
|
int64_t Value = curl_getdate(aValue, nullptr);
|
||||||
|
if(Value != -1)
|
||||||
|
{
|
||||||
|
m_ResultLastModified = Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return HeaderSize;
|
||||||
|
}
|
||||||
|
|
||||||
size_t CHttpRequest::OnData(char *pData, size_t DataSize)
|
size_t CHttpRequest::OnData(char *pData, size_t DataSize)
|
||||||
{
|
{
|
||||||
// Need to check for the maximum response size here as curl can only
|
// Need to check for the maximum response size here as curl can only
|
||||||
|
@ -244,6 +292,12 @@ size_t CHttpRequest::OnData(char *pData, size_t DataSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t CHttpRequest::HeaderCallback(char *pData, size_t Size, size_t Number, void *pUser)
|
||||||
|
{
|
||||||
|
dbg_assert(Size == 1, "invalid size parameter passed to header callback");
|
||||||
|
return ((CHttpRequest *)pUser)->OnHeader(pData, Number);
|
||||||
|
}
|
||||||
|
|
||||||
size_t CHttpRequest::WriteCallback(char *pData, size_t Size, size_t Number, void *pUser)
|
size_t CHttpRequest::WriteCallback(char *pData, size_t Size, size_t Number, void *pUser)
|
||||||
{
|
{
|
||||||
return ((CHttpRequest *)pUser)->OnData(pData, Size * Number);
|
return ((CHttpRequest *)pUser)->OnData(pData, Size * Number);
|
||||||
|
@ -390,6 +444,22 @@ int CHttpRequest::StatusCode() const
|
||||||
return m_StatusCode;
|
return m_StatusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<int64_t> CHttpRequest::ResultAgeSeconds() const
|
||||||
|
{
|
||||||
|
dbg_assert(State() == EHttpState::DONE, "Request not done");
|
||||||
|
if(!m_ResultDate || !m_ResultLastModified)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return *m_ResultDate - *m_ResultLastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int64_t> CHttpRequest::ResultLastModified() const
|
||||||
|
{
|
||||||
|
dbg_assert(State() == EHttpState::DONE, "Request not done");
|
||||||
|
return m_ResultLastModified;
|
||||||
|
}
|
||||||
|
|
||||||
bool CHttp::Init(std::chrono::milliseconds ShutdownDelay)
|
bool CHttp::Init(std::chrono::milliseconds ShutdownDelay)
|
||||||
{
|
{
|
||||||
m_ShutdownDelay = ShutdownDelay;
|
m_ShutdownDelay = ShutdownDelay;
|
||||||
|
|
|
@ -118,6 +118,9 @@ class CHttpRequest : public IHttpRequest
|
||||||
std::atomic<bool> m_Abort{false};
|
std::atomic<bool> m_Abort{false};
|
||||||
|
|
||||||
int m_StatusCode = 0;
|
int m_StatusCode = 0;
|
||||||
|
bool m_HeadersEnded = false;
|
||||||
|
std::optional<int64_t> m_ResultDate = {};
|
||||||
|
std::optional<int64_t> m_ResultLastModified = {};
|
||||||
|
|
||||||
// Abort the request with an error if `BeforeInit()` returns false.
|
// Abort the request with an error if `BeforeInit()` returns false.
|
||||||
bool BeforeInit();
|
bool BeforeInit();
|
||||||
|
@ -125,11 +128,15 @@ class CHttpRequest : public IHttpRequest
|
||||||
// `pHandle` can be nullptr if no handle was ever created for this request.
|
// `pHandle` can be nullptr if no handle was ever created for this request.
|
||||||
void OnCompletionInternal(void *pHandle, unsigned int Result); // void * == CURL *, unsigned int == CURLcode
|
void OnCompletionInternal(void *pHandle, unsigned int Result); // void * == CURL *, unsigned int == CURLcode
|
||||||
|
|
||||||
|
// Abort the request if `OnHeader()` returns something other than
|
||||||
|
// `DataSize`. `pHeader` is NOT null-terminated.
|
||||||
|
size_t OnHeader(char *pHeader, size_t HeaderSize);
|
||||||
// Abort the request if `OnData()` returns something other than
|
// Abort the request if `OnData()` returns something other than
|
||||||
// `DataSize`.
|
// `DataSize`.
|
||||||
size_t OnData(char *pData, size_t DataSize);
|
size_t OnData(char *pData, size_t DataSize);
|
||||||
|
|
||||||
static int ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr);
|
static int ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr);
|
||||||
|
static size_t HeaderCallback(char *pData, size_t Size, size_t Number, void *pUser);
|
||||||
static size_t WriteCallback(char *pData, size_t Size, size_t Number, void *pUser);
|
static size_t WriteCallback(char *pData, size_t Size, size_t Number, void *pUser);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -207,6 +214,8 @@ public:
|
||||||
const SHA256_DIGEST &ResultSha256() const;
|
const SHA256_DIGEST &ResultSha256() const;
|
||||||
|
|
||||||
int StatusCode() const;
|
int StatusCode() const;
|
||||||
|
std::optional<int64_t> ResultAgeSeconds() const;
|
||||||
|
std::optional<int64_t> ResultLastModified() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<CHttpRequest> HttpHead(const char *pUrl)
|
inline std::unique_ptr<CHttpRequest> HttpHead(const char *pUrl)
|
||||||
|
|
Loading…
Reference in a new issue