Skip to content

Commit e600a28

Browse files
committed
http/cookie: Add store:load_from_file() method
1 parent 9381ad9 commit e600a28

File tree

2 files changed

+124
-1
lines changed

2 files changed

+124
-1
lines changed

http/cookie.lua

+89-1
Original file line numberDiff line numberDiff line change
@@ -666,8 +666,96 @@ function store_methods:clean()
666666
return true
667667
end
668668

669-
-- Saves to a file in netscape format
669+
-- Files in 'netscape format'
670670
-- curl's lib/cookie.c is best reference for the format
671+
local function parse_netscape_format(line, now)
672+
if line == "" then
673+
return
674+
end
675+
local i = 1
676+
local http_only = false
677+
if line:sub(1, 1) == "#" then
678+
if line:sub(1, 10) == "#HttpOnly_" then
679+
http_only = true
680+
i = 11
681+
else
682+
return
683+
end
684+
end
685+
686+
local domain, host_only, path, secure_only, expiry, name, value =
687+
line:match("^%.?([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t(%d+)\t([^\t]+)\t(.+)", i)
688+
if not domain then
689+
return
690+
end
691+
domain = canonicalise_host(domain)
692+
if domain == nil then
693+
return
694+
end
695+
696+
if host_only == "TRUE" then
697+
host_only = true
698+
elseif host_only == "FALSE" then
699+
host_only = false
700+
else
701+
return
702+
end
703+
704+
if secure_only == "TRUE" then
705+
secure_only = true
706+
elseif secure_only == "FALSE" then
707+
secure_only = false
708+
else
709+
return
710+
end
711+
712+
expiry = tonumber(expiry, 10)
713+
714+
return setmetatable({
715+
name = name;
716+
value = value;
717+
expiry_time = expiry;
718+
domain = domain;
719+
path = path;
720+
creation_time = now;
721+
last_access_time = now;
722+
persistent = expiry == 0;
723+
host_only = host_only;
724+
secure_only = secure_only;
725+
http_only = http_only;
726+
same_site = nil;
727+
}, cookie_mt)
728+
end
729+
730+
function store_methods:load_from_file(file)
731+
local now = self.time()
732+
733+
-- Clean now so that we don't hit storage limits
734+
self:clean()
735+
736+
local cookies = {}
737+
local n = 0
738+
while true do
739+
local line, err, errno = file:read()
740+
if not line then
741+
if err ~= nil then
742+
return nil, err, errno
743+
end
744+
break
745+
end
746+
local cookie = parse_netscape_format(line, now)
747+
if cookie then
748+
n = n + 1
749+
cookies[n] = cookie
750+
end
751+
end
752+
for i=1, n do
753+
local cookie = cookies[i]
754+
add_to_store(self, cookie, cookie.http_only, now)
755+
end
756+
return true
757+
end
758+
671759
function store_methods:save_to_file(file)
672760
do -- write a preamble
673761
local ok, err, errno = file:write [[

spec/cookie_spec.lua

+35
Original file line numberDiff line numberDiff line change
@@ -395,4 +395,39 @@ describe("cookie module", function()
395395
"sub.example.com FALSE / FALSE 2147483647 subdomain matched";
396396
}, lines)
397397
end)
398+
it("can load a netscape format cookiejar", function()
399+
local s = http_cookie.new_store()
400+
local file = io.tmpfile()
401+
assert(file:write([[
402+
# Netscape HTTP Cookie File
403+
# https://curl.haxx.se/docs/http-cookies.html
404+
# This file was generated by libcurl! Edit at your own risk.
405+
406+
#HttpOnly_other.com TRUE / FALSE 2147483647 foo somethingelse
407+
sub.example.com FALSE / FALSE 2147483647 subdomain matched
408+
example.com TRUE / TRUE 2147483647 qux QUX
409+
#HttpOnly_example.com TRUE / FALSE 2147483647 bar BAR
410+
example.com TRUE / FALSE 2147483647 foo FOO
411+
example.com TRUE /someplace FALSE 2147483647 baz BAZ
412+
]]))
413+
assert(file:seek("set"))
414+
assert(s:load_from_file(file))
415+
assert.same("bar=BAR; foo=FOO; qux=QUX", s:lookup("example.com", "/", true, true))
416+
end)
417+
it("can load a netscape format cookiejar with invalid lines", function()
418+
local s = http_cookie.new_store()
419+
local file = io.tmpfile()
420+
assert(file:write([[
421+
example.com TRUE / TRUE 2147483647 qux QUX
422+
not a valid line
423+
example.com INVALID_BOOLEAN / FALSE 2147483647 should fail
424+
example.com TRUE / INVALID_BOOLEAN 2147483647 should fail
425+
example.com TRUE / FALSE not_a_number should fail
426+
#HttpOnly_example.com TRUE / FALSE 2147483647 bar BAR
427+
example.com TRUE / FALSE 2147483647 foo FOO
428+
]]))
429+
assert(file:seek("set"))
430+
assert(s:load_from_file(file))
431+
assert.same("bar=BAR; foo=FOO; qux=QUX", s:lookup("example.com", "/", true, true))
432+
end)
398433
end)

0 commit comments

Comments
 (0)