http
HTTP client and server. No require() needed. All responses return {status, body, headers}.
Options table supports {headers = {["X-Key"] = "value"}}.
http.get(url, opts?)→{status, body, headers}— GET requesthttp.post(url, body, opts?)→{status, body, headers}— POST request (auto-JSON if table body)http.put(url, body, opts?)→{status, body, headers}— PUT requesthttp.patch(url, body, opts?)→{status, body, headers}— PATCH requesthttp.delete(url, opts?)→{status, body, headers}— DELETE requesthttp.serve(port, routes)→ blocks — Start HTTP server with async handlers- Routes:
{GET = {["/path"] = function(req) return {status=200, body="ok"} end}} - Handlers receive
{method, path, body, headers, query}, return{status, body, json?, headers?} - Handlers can call async builtins (
http.get,sleep, etc.) - Header values can be a string or an array of strings. Array values emit the same header name
multiple times — required for
Set-Cookiewith multiple cookies, and useful forLink,Vary,Cache-Control, etc.:return { status = 200, headers = { ["Set-Cookie"] = { "session=abc; Path=/; HttpOnly", "csrf=xyz; Path=/", }, }, body = "ok", } - SSE: return
{sse = function(send) send({event="update", data="hello", id="1"}) end}send()accepts:event,data,id,retryfields- Sets
Content-Type: text/event-streamautomatically - Stream closes when function returns
- WebSocket upgrade (v0.15.1+): return
{ws = function(conn) ... end}from any handler whose request carriesUpgrade: websocket.http.servevalidates the handshake, sends101 Switching Protocols, and hands the upgraded connection to the callback:
Connection methods:GET = { ["/echo"] = function(req) return { ws = function(conn) while true do local msg = conn:read() -- string, nil on close if not msg then break end conn:write(msg) -- text frame -- conn:write(bytes, { binary = true }) for binary frames end end, headers = { ["X-Shell-Allowed"] = "true" }, -- optional } end, }conn:read()(blocks until next text/binary frame, returns nil on close),conn:write(data, opts?)(opts.binary=truefor binary frames),conn:close(code?, reason?),conn:is_closed(). Field:conn.peer_addr. Ping/pong is handled automatically by the underlying tungstenite stack. For browser-shell bridging seeassay.shell.
- Routes:
http.download(url, path, opts?)→integer— Stream a URL to disk (v0.15.5+). Writes via temp file + atomic rename — partial downloads are removed on error.url(string): URL to GETpath(string): destination file path; parent dirs are created if neededopts(table, optional):headers = {[name] = value},timeout(seconds, > 0)- Returns bytes written as an integer
- Raises on 4xx/5xx, IO failure, or network failure; no partial file is left at
pathon error
http.download( "https://example.com/release.tar.gz", "/tmp/release.tar.gz", { timeout = 300, headers = { ["User-Agent"] = "myapp/1.0" } } )