dobrograd-13-06-2022/garrysmod/addons/util-dlib/lua/dlib/util/httpclient.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

457 lines
14 KiB
Lua

do
local _class_0
local _base_0 = {
Expired = function(self, stamp)
if stamp == nil then
stamp = os.time()
end
if self.m_Session then
return false
end
return self.m_Expires < stamp
end,
Is = function(self, path)
if self.Secure and not path:startsWith('https://') then
return false
end
local protocol, domain = path:match('(https?)://([a-zA-Z0-9.-]+)')
if not protocol or not domain then
return false
end
if self.explicitDomain and self.m_Domain ~= domain then
return false
end
if not self.explicitDomain and not domain:endsWith(self.m_Domain) then
return false
end
local uripath = path:sub(#protocol + 4 + #domain):trim()
if uripath == '' then
uripath = '/'
end
return uripath:startsWith(self.m_Path)
end,
Hash = function(self)
return tostring(self.name) .. "_" .. tostring(self.m_Domain) .. "[" .. tostring(self.explicitDomain) .. "]_" .. tostring(util.CRC(self.m_Path)) .. "_" .. tostring(self.m_Secure)
end,
Value = function(self)
return tostring(self.name) .. "=" .. tostring(self.value)
end,
Serialize = function(self)
local build = {
self.name .. '=' .. self.value,
'Created=' .. os.date('%a, %d %b %Y %H:%M:%S GMT', self.m_CreationTime),
'Domain=' .. self.m_Domain,
'Path=' .. self.m_Path
}
if self.m_HttpOnly then
table.insert(build, 'HttpOnly')
end
if not self.m_Session then
table.insert(build, 'Expires=' .. os.date('%a, %d %b %Y %H:%M:%S GMT', self.m_Expires))
end
if self.explicitDomain then
table.insert(build, 'UnsafeDomain')
end
return table.concat(build, '; ')
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, name, value, domain, path, explicitDomain)
if path == nil then
path = '/'
end
if explicitDomain == nil then
explicitDomain = true
end
assert(isstring(name), 'Name must be a string')
assert(isstring(value), 'Value must be a string')
assert(not name:find(' ', 1, true) and not name:find('=', 1, true) and not name:find(';', 1, true) and not name:find('\n', 1, true), 'Cookie name can not contain special symbols')
assert(not value:find(' ', 1, true) and not value:find('=', 1, true) and not value:find(';', 1, true) and not value:find('\n', 1, true), 'Cookie value can not contain special symbols')
assert(isstring(domain), 'Domain must be a string')
assert(isstring(path), 'Path must be a string')
assert(isstring(domain), 'Domain must be a string')
self.name = name
self.value = value
self.m_HttpOnly = false
self.m_Domain = domain
self.m_Path = path
self.m_Secure = false
self.m_CreationTime = os.time()
self.m_Expires = math.huge
self.m_Session = true
self.explicitDomain = explicitDomain
end,
__base = _base_0,
__name = "Cookie"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0
self.Parse = function(self, strInput, domain, unsafe)
if unsafe == nil then
unsafe = false
end
assert(isstring(strInput), 'Input must be a string')
local split = strInput:split(';')
local _name = table.remove(split, 1)
local startPos, endPos = _name:find('=', 1, true)
if not startPos then
error('Malformed input. First key=value pair in cookie must always be cookie\'s name and value!')
end
local cname = _name:sub(1, startPos - 1)
local cvalue = _name:sub(startPos + 1)
local data = {
unsafedomain = true
}
for _index_0 = 1, #split do
local param = split[_index_0]
local trim = param:trim()
local _exp_0 = trim:lower()
if 'secure' == _exp_0 then
data.secure = true
elseif 'httponly' == _exp_0 then
data.httponly = true
elseif 'unsafedomain' == _exp_0 then
if unsafe then
data.unsafedomain = true
end
else
startPos, endPos = trim:find('=', 1, true)
if startPos then
local name = trim:sub(1, startPos - 1)
local value = trim:sub(startPos + 1)
if name:lower() == 'max-age' then
do
local num = tonumber(value)
if num then
data.override_expires = true
if num == 0 then
data.expires = nil
data.session = true
else
data.expires = os.time() + num
data.session = false
end
end
end
elseif name:lower() == 'expires' and not data.override_expires then
data.expires = http.ParseDate(value)
data.session = false
if data.expires < 10 then
data.expires = nil
data.session = true
end
elseif unsafe and name:lower() == 'created' then
data.created = http.ParseDate(value)
elseif name:lower() == 'domain' then
data.domain = value
data.unsafedomain = false
elseif name:lower() == 'path' then
data.path = value
end
end
end
end
local cookie = self(cname, cvalue, data.domain or domain, data.path)
if data.secure then
cookie:SetIsSecure(true)
end
if data.httponly then
cookie:SetHttpOnly(true)
end
if data.created then
cookie:SetCreationStamp(data.created)
end
if data.domain then
cookie:SetDomain(data.domain)
end
cookie:SetExplicitDomain(data.unsafedomain)
if data.expires then
cookie:SetExpiresStamp(data.expires)
cookie:SetIsSession(data.session)
end
return cookie
end
AccessorFunc(self.__base, 'm_HttpOnly', 'HttpOnly', FORCE_BOOL)
AccessorFunc(self.__base, 'explicitDomain', 'ExplicitDomain', FORCE_BOOL)
AccessorFunc(self.__base, 'm_Session', 'IsSession', FORCE_BOOL)
AccessorFunc(self.__base, 'm_CreationTime', 'CreationStamp', FORCE_NUMBER)
AccessorFunc(self.__base, 'm_Expires', 'ExpiresStamp', FORCE_NUMBER)
AccessorFunc(self.__base, 'm_Secure', 'IsSecure', FORCE_BOOL)
AccessorFunc(self.__base, 'm_Path', 'Path', FORCE_STRING)
AccessorFunc(self.__base, 'm_Domain', 'Domain', FORCE_STRING)
AccessorFunc(self.__base, 'value', 'Value', FORCE_STRING)
http.Cookie = _class_0
end
do
local _class_0
local _base_0 = {
Add = function(self, input, domain)
local cookie = isstring(input) and http.Cookie:Parse(input, domain) or input
local hash = cookie:Hash()
if self.jar[hash] then
cookie:SetCreationStamp(self.jar[hash]:GetCreationStamp())
end
self.jar[hash] = cookie
return self
end,
Remove = function(self, input, domain)
local cookie = isstring(input) and http.Cookie:Parse(input, domain) or input
local hash = cookie:Hash()
if self.jar[hash] then
self.jar[hash] = nil
return true
end
return false
end,
GetFor = function(self, url)
for hash, cookie in pairs(self.jar) do
if cookie:Expired() then
self.jar[hash] = nil
end
end
local _accum_0 = { }
local _len_0 = 1
for hash, cookie in pairs(self.jar) do
if cookie:Is(url) then
_accum_0[_len_0] = cookie
_len_0 = _len_0 + 1
end
end
return _accum_0
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self)
self.jar = { }
end,
__base = _base_0,
__name = "CookieJar"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
http.CookieJar = _class_0
end
local Promise
Promise = DLib.Promise
do
local _class_0
local _base_0 = {
CookieList = function(self, url)
local cookies = self.cookiejar:GetFor(url)
if not cookies or #cookies == 0 then
return false
end
return table.concat((function()
local _accum_0 = { }
local _len_0 = 1
for _index_0 = 1, #cookies do
local cookie = cookies[_index_0]
_accum_0[_len_0] = cookie:Value()
_len_0 = _len_0 + 1
end
return _accum_0
end)(), '; ')
end,
Patch = function(self, url, headers)
local cookieList = self:CookieList(url)
local hit = not cookieList
local hit2 = not self.last_referer
if hit and hit2 then
return headers
end
for headerName in pairs(headers) do
if not hit and headerName:lower() == 'cookie' then
hit = true
end
if not hit2 and headerName:lower() == 'referer' then
hit2 = true
end
end
if not hit then
headers.Cookie = cookieList
end
if not hit2 then
headers.Referer = self.last_referer
end
return headers
end,
_Domain = function(self, url)
return url:match('https?://([a-zA-Z0-9.-]+)'):lower()
end,
_Receive = function(self, domain, headers)
for key, value in pairs(headers) do
if key:lower() == 'set-cookie' then
self.cookiejar:Add(value, domain)
end
end
end,
Get = function(self, url, headers)
if headers == nil then
headers = { }
end
return Promise(function(resolve, reject)
return http.PromiseGet(url, self:Patch(url, headers)):Catch(reject):Then(function(body, size, headers, code, ...)
if body == nil then
body = ''
end
if size == nil then
size = 0
end
if headers == nil then
headers = { }
end
if code == nil then
code = 500
end
self:_Receive(self:_Domain(url), headers)
if code >= 200 and code < 300 then
self.last_referer = url
end
return resolve(body, size, headers, code, ...)
end)
end)
end,
Post = function(self, url, params, headers)
if headers == nil then
headers = { }
end
return Promise(function(resolve, reject)
return http.PromisePost(url, params, self:Patch(url, headers)):Catch(reject):Then(function(body, size, headers, code, ...)
if body == nil then
body = ''
end
if size == nil then
size = 0
end
if headers == nil then
headers = { }
end
if code == nil then
code = 500
end
self:_Receive(self:_Domain(url), headers)
if code >= 200 and code < 300 then
self.last_referer = url
end
return resolve(body, size, headers, code, ...)
end)
end)
end,
PostBody = function(self, url, body, headers)
if headers == nil then
headers = { }
end
return Promise(function(resolve, reject)
return http.PromisePostBody(url, body, self:Patch(url, headers)):Catch(reject):Then(function(body, size, headers, code, ...)
if body == nil then
body = ''
end
if size == nil then
size = 0
end
if headers == nil then
headers = { }
end
if code == nil then
code = 500
end
self:_Receive(self:_Domain(url), headers)
if code >= 200 and code < 300 then
self.last_referer = url
end
return resolve(body, size, headers, code, ...)
end)
end)
end,
Put = function(self, url, body, headers)
if headers == nil then
headers = { }
end
return Promise(function(resolve, reject)
return http.PromisePut(url, body, self:Patch(url, headers)):Catch(reject):Then(function(body, size, headers, code, ...)
if body == nil then
body = ''
end
if size == nil then
size = 0
end
if headers == nil then
headers = { }
end
if code == nil then
code = 500
end
self:_Receive(self:_Domain(url), headers)
if code >= 200 and code < 300 then
self.last_referer = url
end
return resolve(body, size, headers, code, ...)
end)
end)
end,
Head = function(self, url, headers)
if headers == nil then
headers = { }
end
return Promise(function(resolve, reject)
return http.PromiseHead(url, self:Patch(url, headers)):Catch(reject):Then(function(headers, code, ...)
if headers == nil then
headers = { }
end
if code == nil then
code = 500
end
self:_Receive(self:_Domain(url), headers)
if code >= 200 and code < 300 then
self.last_referer = url
end
return resolve(headers, code, ...)
end)
end)
end
}
_base_0.__index = _base_0
_class_0 = setmetatable({
__init = function(self, cookiejar)
if isstring(cookiejar) then
error('serializing of cookiejar is not supported yet')
elseif type(cookiejar) == 'table' then
self.cookiejar = cookiejar
else
self.cookiejar = http.CookieJar()
end
self.set_referer = true
self.last_referer = false
end,
__base = _base_0,
__name = "Client"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({}, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0
AccessorFunc(self.__base, 'set_referer', 'SetReferer', FORCE_BOOL)
AccessorFunc(self.__base, 'last_referer', 'LastReferer')
http.Client = _class_0
return _class_0
end