mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-16 08:11:35 +02:00
4b7a4daf2c
tmpnam() on the Windows CRT returns a bare, CWD-relative name (e.g. \sb4c.2), and io.open on it fails with Permission denied when the game's working directory is not writable -- a Program Files (or otherwise protected) install. postLog then dies before curl runs: the mod reports a send failure and no bytes leave the machine (confirmed on a Windows install: "could not create request body: \sb4c.2: Permission denied"). Stage the request body under the OS temp contract instead: TEMP/TMP on Windows (always set, always per-user writable), TMPDIR with a /tmp fallback on POSIX. The transport stays on plain io/os -- no love.filesystem dependency. Tests updated to mock os.getenv and assert the staged path sits under the temp dir; 10/10 checks pass.
82 lines
2.7 KiB
Lua
82 lines
2.7 KiB
Lua
-- HostShell.httpPost must work with Lua/LuaJIT's one-way io.popen.
|
|
--
|
|
-- io.popen accepts "r" or "w", not "rw". POST needs both a request body
|
|
-- and a response status, so the body is staged in a temporary file and curl
|
|
-- is opened read-only for its response.
|
|
-- luajit tests/engine/host_shell_postlog.lua
|
|
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
|
|
local T = require("tests.harness")
|
|
local check, eq = T.check, T.eq
|
|
local HostShell = require("src.core.HostShell")
|
|
|
|
local MARK = "\n__gen1recomp_http__"
|
|
local STAGE_DIR = "/tmp/gen1recomp-postlog-stage"
|
|
local URL = "https://logs.example.com/logs"
|
|
local BODY = "debug log body\n"
|
|
|
|
local realOpen = io.open
|
|
local realPopen = io.popen
|
|
local realGetenv = os.getenv
|
|
local realRemove = os.remove
|
|
local realHaveCurl = HostShell.haveCurl
|
|
|
|
local openedPath, openedMode, writtenBody
|
|
local popenCommand, popenMode, removedPath
|
|
|
|
HostShell.haveCurl = function() return true end
|
|
os.getenv = function(name)
|
|
if name == "TEMP" or name == "TMP" or name == "TMPDIR" then
|
|
return STAGE_DIR
|
|
end
|
|
return realGetenv(name)
|
|
end
|
|
os.remove = function(path)
|
|
removedPath = path
|
|
return true
|
|
end
|
|
|
|
io.open = function(path, mode)
|
|
openedPath, openedMode = path, mode
|
|
return {
|
|
write = function(_, value)
|
|
writtenBody = value
|
|
return true
|
|
end,
|
|
close = function() return true end,
|
|
}
|
|
end
|
|
|
|
io.popen = function(command, mode)
|
|
popenCommand, popenMode = command, mode
|
|
return {
|
|
read = function() return MARK .. "200" end,
|
|
close = function() return true end,
|
|
}
|
|
end
|
|
|
|
local ok, err = HostShell.httpPost(URL, BODY, "text/plain", "gen1recomp-mod/test", 10)
|
|
|
|
io.open = realOpen
|
|
io.popen = realPopen
|
|
os.getenv = realGetenv
|
|
os.remove = realRemove
|
|
HostShell.haveCurl = realHaveCurl
|
|
|
|
eq(ok, true, "a desktop POST succeeds through the read-only response pipe: " .. tostring(err))
|
|
check(type(openedPath) == "string" and openedPath:find(STAGE_DIR .. "/gen1recomp-post-", 1, true) == 1, "the request body is staged under the OS temp dir")
|
|
check(openedPath and openedPath:sub(-4) == ".tmp", "the staged body carries a .tmp name")
|
|
eq(openedMode, "wb", "the temporary request body is opened for binary writing")
|
|
eq(writtenBody, BODY, "the complete log body is staged")
|
|
eq(popenMode, "r", "curl is opened in the supported read-only mode")
|
|
check(popenCommand:find("--data-binary", 1, true) ~= nil,
|
|
"curl reads the staged body with --data-binary")
|
|
check(openedPath and popenCommand:find(openedPath, 1, true) ~= nil,
|
|
"curl receives the temporary body path")
|
|
check(popenCommand:find(BODY, 1, true) == nil,
|
|
"the log body is not placed directly in the command line")
|
|
eq(removedPath, openedPath, "the staged request body is removed")
|
|
|
|
T.finish("host shell postlog")
|