This is a very fragile and hacky script but I like it.
I could see myself using something like this as a crude scraper tool.
Here I have cleaned up the code a little bit:
Code: Select all
local https = {}
https.timeout = 0
https.js = [[
var script = %script%;
var url = %url%;
var method = %method%;
var data = %data%;
var username = %username%;
var password = %password%;
var timeout = %timeout%;
var headers = %headers%;
var status = 0;
try
{
var xHttp = new ActiveXObject("MSXML2.ServerXMLHTTP");
if (timeout)
xHttp.setTimeouts(timeout, timeout, timeout, timeout);
xHttp.open(method, url, false, username, password);
for (var key in headers)
xHttp.setRequestHeader(key, headers[key]);
xHttp.send(data);
var fsT = new ActiveXObject("ADODB.Stream");
fsT.type = 2;
fsT.charset = headers['charset'];
fsT.open();
fsT.writeText(xHttp.responseText);
fsT.saveToFile(script + "0", 2);
var response = xHttp.getAllResponseHeaders();
var FSO = new ActiveXObject("Scripting.FileSystemObject");
var file = FSO.CreateTextFile(script + "2", true);
file.Write(response + "\n");
file.Close();
status = xHttp.status;
}
catch (err)
{
status = 400;
}
var FSO = new ActiveXObject("Scripting.FileSystemObject");
var file = FSO.CreateTextFile(script + "1", true);
file.Write(status + "\n");
file.Close();
]]
function https.request(url, data)
local p = {}
if type(url) == "table" then
for k, v in pairs(url) do
p[k] = v
end
else
p.url = url
p.data = data
end
p.url = p.url or ""
p.data = p.data or ""
p.method = p.method or "GET"
p.timeout = https.timeout
local h = p.headers or {}
h['charset'] = h['charset'] or "us-ascii"
h['conent-type'] = h['content-type'] or "application/x-www-form-urlencoded"
h['content-length'] = string.len(p.data)
p.headers = h
local script = os.tmpname()
p.script = script
local js = https.js
for k, v in pairs(p) do
if type(v) == "table" then
local t = {}
for j, w in pairs(v) do
if type(w) == "string" then
w = string.format("%q", w)
else
w = tostring(w)
end
local row = string.format("%q:%s", j, w)
table.insert(t, row)
end
v = "{"..table.concat(t, ",\n").."}"
elseif type(v) == "string" then
v = string.format("%q", v)
else
v = tostring(v)
end
js = js:gsub("%%"..k.."%%", v)
end
js = js:gsub("%%(.-)%%", "null")
local file = io.open(script..".js", "w")
if not file then
return
end
file:write(js)
file:close()
--os.execute(script..".js")
local console = io.popen(script..".js", "r")
console:read("*all")
console:close()
local response = {}
for i = 0, 2 do
local out = io.open(script..i, "r")
if out then
response[i + 1] = out:read("*a")
out:close()
end
os.remove(script..i)
end
os.remove(script..".js")
response[2] = tonumber(response[2])
return unpack(response)
end
return https
+ Removed the Love2D dependency so it can work using pure Lua.
+ Added temporary filenames so this could be used in parallel.
+ Certificate validation is ON by default - seems like xHttp.setOption(2, 13056) is probably insecure
+ Username and Pass can be supplied optionally using the table syntax: https.request{url='https://example.com',user='me',pass='secret'}
+ Better way to pass data from Lua to JavaScript (the reverse is not as elegant)
+ Works similarly to LuaSocket's http.request (returning the headers and body)
- The JavaScript part will only work with Windows.
- The console windows will pop up when using https.request.
- All requests are blocking
Usage (for experimentation and fun):
Code: Select all
https = require("https")
function love.load()
body, status, headers = https.request("https://love2d.org/")
love.system.setClipboardText(body)
end
function love.draw()
love.graphics.print(tostring(status), 0, 0)
love.graphics.print(tostring(body), 0, 20)
end