http
The built-in http module sends HTTP and HTTPS requests from a script. Requests are asynchronous: the response arrives in a callback, the game does not wait for the network.
The module is loaded with require and, like ffi, must be listed in the script dependencies on the website. Otherwise require returns the error module 'http' needs to be stated in the 'requirements' section of the script. A module from the dependencies is also available right away as the global variable http.
-- http is listed in the script dependencies on the website
local http = require("http")
print(type(http.get)) --> function
- Only
http://andhttps://addresses are supported. - There is no synchronous variant: the result arrives only in the callback.
- The callback runs on the game thread, at most one HTTP callback per frame. Several requests can be sent at once; their responses arrive one by one in the following frames.
- An error inside the callback is printed to the console, the script keeps running.
- When the script is turned off, its unfinished requests are cancelled and the callback does not arrive. The game does not freeze.
- The Windows system proxy is used automatically.
- Response headers are not passed to the script: only the status code and the body are available.
http.get(url: string, options: table | nil, callback: function)#
Sends a GET request.
| Parameter | Type | Description |
|---|---|---|
url |
string |
request address |
options |
table or nil |
request options (see "Request options"). Any value other than a table is ignored |
callback |
function |
function(response), receives the response table (see "Response") |
- The callback is always the third argument. Without options pass
nil:http.get(url, nil, cb). Callinghttp.get(url, cb)gives the errorbad argument #3 ... (function expected, got nil). urlis not a string — errorbad argument #1 ... (string expected, got ...).
Returns: nothing.
local http = require("http")
http.get("https://httpbin.org/get", nil, function(r)
if r.error then
print("network error: ", r.error)
return
end
print("status ", r.status, ", length ", #r.body)
end)
Other methods#
http.head, http.post, http.put, http.delete, http.patch take the same arguments as http.get and send a request with the corresponding method.
| Function | Method | Where params go |
|---|---|---|
http.get(url, options, callback) |
GET |
into the query string |
http.head(url, options, callback) |
HEAD |
into the query string; the response body is always empty |
http.delete(url, options, callback) |
DELETE |
into the query string |
http.post(url, options, callback) |
POST |
into the request body |
http.put(url, options, callback) |
PUT |
into the request body |
http.patch(url, options, callback) |
PATCH |
into the request body |
post, put and patch without json and params send an empty body with Content-Type: application/x-www-form-urlencoded.
Returns: nothing.
local http = require("http")
http.put("https://httpbin.org/put", { json = '{"p":1}' }, function(r) print("PUT ", r.status) end)
http.patch("https://httpbin.org/patch", { params = { q = "w" } }, function(r) print("PATCH ", r.status) end)
http.delete("https://httpbin.org/delete", { params = { id = "1" } }, function(r) print("DELETE ", r.status) end)
http.head("https://httpbin.org/get", nil, function(r) print("HEAD ", r.status, " ", #r.body) end) --> HEAD 200 0
Request options#
The options table. All keys are optional, unknown keys are skipped. A key must be a string and a value must have the listed type, otherwise the error is bad argument ... (<type> expected, got ...).
| Key | Type | Description |
|---|---|---|
timeout |
number |
limit for the whole request, seconds (including all redirects). Default 30. 0 or a negative value — no limit. The fractional part is dropped |
headers |
table |
request headers { ["Name"] = "value" }. Keys and values must be strings |
params |
table or string |
parameters. A table is joined into k=v&k2=v2 (order as in pairs), a string is used as is. For post/put/patch this is the request body (Content-Type: application/x-www-form-urlencoded unless you set your own in headers), for get/head/delete it is the query string: ? is appended to the address, or & if it already has ? |
json |
string |
request body as a ready JSON string, plus the header Content-Type: application/json. If the string is not empty, params is not used. Works with any method |
cookie |
cookies |
an object from http.cookies(): its cookies are sent and cookies from the response are stored in it. Any other value — error cookies expected |
authorization |
table |
Basic authorization: { username = "...", password = "..." }. Both fields are required and must be strings |
paramsare not encoded: encode spaces,&,=, non-Latin characters and other special characters in values yourself as%XX. A space or a control character in the address gives the errorinvalid_url. Non-Latin characters in the address are also better encoded by yourself.
local http = require("http")
http.get("https://httpbin.org/get", {
timeout = 10,
headers = { ["X-Key"] = "secret" },
params = { page = "2", sort = "name" }, -- sent as ?page=2&sort=name (order is not guaranteed)
}, function(r)
print(r.status)
end)
http.get("https://httpbin.org/basic-auth/user1/pass1", {
authorization = { username = "user1", password = "pass1" },
}, function(r)
print(r.status) --> 200; with a wrong password — 401
end)
Response#
The callback receives one table:
| Field | Type | Description |
|---|---|---|
status |
number |
HTTP status code. 0 — network error, no response |
body |
string |
response body; an empty string on a network error and for head |
error |
string or nil |
reason of the network error. Without an error the field is absent (nil) |
- 4xx and 5xx codes are a normal response:
statusandbodyare filled, there is noerror. - Redirects are followed automatically, up to 50 hops.
statusandbodyare those of the last response. On301,302,303aPOSTrequest is repeated asGETwithout a body. - The body arrives in full, including binary data: it is a Lua string with any bytes, zero bytes included.
local http = require("http")
http.get("https://httpbin.org/status/404", nil, function(r)
if r.error then
print("network: ", r.error)
elseif r.status ~= 200 then
print("server answered ", r.status) --> server answered 404
else
print(r.body)
end
end)
Network errors#
On a network error status = 0, body = "", and error is a string of the form <kind> or <kind> (<code>), where the code is a Windows system error code. Check the kind by the start of the string, for example r.error:find("^dns").
| Kind | When |
|---|---|
timeout |
the request timeout expired |
dns |
the server name was not found |
connect |
could not connect, or the connection was dropped |
tls |
secure connection or certificate error |
invalid_url |
invalid address (including a space in the address) |
unsupported_scheme |
the scheme is not http/https (for example, ftp://) |
invalid_response |
the server did not answer with HTTP |
proxy |
system proxy auto-configuration error |
too_many_redirects |
more than 50 redirects |
cancelled |
the request was cancelled |
out_of_memory |
not enough memory for the response body |
response_too_large |
the response body is larger than the largest Lua string |
winhttp |
other system network errors |
local http = require("http")
http.get("https://httpbin.org/delay/5", { timeout = 2 }, function(r)
if r.error == "timeout" then
print("the server did not answer within 2 seconds")
elseif r.error then
print("network: ", r.error)
else
print(r.status)
end
end)
http.cookies()#
Creates an empty cookies object. Pass it in the cookie option so that requests send and keep cookies, like a browser.
- The object accumulates cookies from responses (including intermediate responses during redirects). A cookie with the same name, domain and path replaces the previous one, there are no duplicates. Cookies deleted by the server are removed.
- Cookies are stored in the object before the callback is called, and only if the request finished without a network error.
- The script cannot read the contents of the object: it only carries cookies between requests.
tostring(obj)returns"cookies". - Without the
cookieoption a request sends no cookies.
Returns: cookies — a new object.
local http = require("http")
local jar = http.cookies()
-- The server sets the cookie srv=abc and redirects to /cookies
http.get("https://httpbin.org/cookies/set?srv=abc", { cookie = jar }, function(r)
-- The next request with the same object sends srv=abc
http.get("https://httpbin.org/cookies", { cookie = jar }, function(r2)
print(r2.body) --> { "cookies": { "srv": "abc" } }
end)
end)
cookies:set(fields: table)#
Adds a cookie to the object manually. Another call with the same name, host and path replaces the value.
| Field | Type | Description |
|---|---|---|
host |
string |
domain, for example "httpbin.org". Default "" |
name |
string |
name. Default "" |
value |
string |
value. Default "" |
path |
string |
path the cookie applies to. Default "/" |
subdomains |
boolean |
also applies to subdomains of host. Default false |
secure |
boolean |
sent only over https://. Default false |
expire |
number |
expiry time, unix time in seconds. Default 0 — lives as long as the object |
All fields are optional, unknown fields are skipped. A field of the wrong type gives the error bad argument ... (<type> expected, got ...). If the argument is not a table — table expected.
Returns: nothing.
local http = require("http")
local jar = http.cookies()
jar:set({ host = "httpbin.org", name = "session", value = "1" })
jar:set({ host = "httpbin.org", name = "session", value = "2" }) -- replaces the previous one
http.get("https://httpbin.org/cookies", { cookie = jar }, function(r)
print(r.body) --> { "cookies": { "session": "2" } }
end)
Example: POST with JSON#
local http = require("http")
local body = json.encode({ name = "player", score = 10 })
http.post("https://httpbin.org/post", { json = body, timeout = 10 }, function(r)
if r.error then
print("network: ", r.error)
return
end
if r.status ~= 200 then
print("server answered ", r.status)
return
end
local answer = json.decode(r.body)
print(answer.json.name) --> player
end)