457 lines
14 KiB
Lua
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
|