HTTP handler utility for FiveM and RedM. It can be used as a simple file server, or to provide easy HTTP functionality to any resource.
-
Place in your resources directory.
-
Add
start httpmanager
to server.cfg.
After installing, you can place files in the http
folder inside the httpmanager
resource folder, and those files will be accessible at:
http://[server IP]:[server port]/httpmanager/...
or
https://[owner]-[server ID].users.cfx.re/httpmanager/...
For example, if you place a file named test.html
in the http
folder, it would be accessible at http://[server IP]:[server port]/httpmanager/test.html
.
You can quickly add HTTP functionality to any resource using the createHttpHandler
export:
handler = exports.httpmanager:createHttpHandler(options)
This creates a new HTTP handler that can be used with SetHttpHandler
in a server script in the resource:
SetHttpHandler(exports.httpmanager:createHttpHandler())
options
is a table containing configuration options for the new handler. Any unspecified options will be given their default value.
Option | Description | Default |
---|---|---|
documentRoot |
The directory in the resource folder where files are served from. | "http" |
directoryIndex |
If the path points to a directory, a file with this name inside that directory will be sent. | "index.html" |
templateExtension |
File extension for files that will be automatically preprocessed as templates. | "lsp" |
authorization |
A table of usernames and passwords required to access any files or routes. | nil |
access |
A table of paths with which users can access them. | {} |
log |
Whether to log requests to a file in the resource directory. | false |
logFile |
If log is true , store the log in this file in the resource directory. |
"log.json" |
errorPages |
A table of custom pages for different error codes (e.g., 404). | {} |
mimeTypes |
A table of MIME type associations for extensions, which will override any detected type. | {} |
routes |
A table of route patterns and callbacks. | {} |
SetHttpHandler(exports.httpmanager:createHttpHandler {
documentRoot = "root",
directoryIndex = "index.html",
templateExtension = "html",
authorization = {
["admin"] = "$2a$11$HoxJPx5sTe4RX5qPw1OkSO.ukDdwAvGJwXtmyOE5i.1gz7EvN71.q",
["user"] = "$2a$11$ILOCJlRiUPhRpmqYiZDDM.EdI16yOtMBTLJKTBLSUHTFzyXjXHJYa"
},
access = {
{path = "/admin/.*", login = {["admin"] = true}},
{path = "/public/.*", login = false},
{path = "/public/secret/.*"}
},
log = true,
logFile = "log.json",
errorPages = {
[404] = "custom404.html"
},
mimeTypes = {
["ogg"] = "audio/ogg"
},
routes = {
["/players/(%d+)"] = function(req, res, helpers, player)
if GetPlayerEndpoint(player) then
res.send(GetPlayerName(player))
else
res.sendError(404)
end
end
}
})
Access to a handler can be controlled by the authorization
option. If authorization
is unset, then no restrictions are applied. If authorization
is a table of usernames and passwords, then access will only be granted once a client has been authenticated using one of these username/password combinations.
Passwords in the authorization
table must be hashed. httpmanager includes a built-in utility for generating password hashes, which can be accessed at http://[server IP]:[server port]/httpmanager/password/
.
authorization = {
["admin"] = "$2a$11$HoxJPx5sTe4RX5qPw1OkSO.ukDdwAvGJwXtmyOE5i.1gz7EvN71.q"
}
Rather than defining users separately for every resource, you can define central groups of users using realms. Realms are configured in realms.lua:
Realms = {
["default"] = {
["admin"] = "$2a$11$HoxJPx5sTe4RX5qPw1OkSO.ukDdwAvGJwXtmyOE5i.1gz7EvN71.q"
},
["realm1"] = {
inherit = "default",
["user1"] = "$2a$11$4RIDavyfsCw/vhImQdDYcOKgCnnJ0ZcJQCFeM8wfF1jkEGN/YnOOG",
["user2"] = "$2a$11$dMe9J7jkhg8N5E/VArrEn.1UKhB9QocNqDopPJkcRNXQ1p4KQDdQG"
},
["realm2"] = {
...
}
}
To use a realm, specify its name as a string for authorization
:
SetHttpHandler(exports.httpmanager:createHttpHandler{
authorization = "realm1"
})
Resources which use the same realm will share the same logins, allowing users to go between them without re-entering their password.
Access can be further refined using the access
option. access
is a table of rules that each specify a path pattern and which users (as defined in the authorization
table) can access it.
access = {
{path = "/admin/.*", login = {["admin"] = true}},
{path = "/public/.*", login = false},
{path = "/public/secret/.*"}
}
In this example, anything under /admin/
can only be accessed by the user admin
, and no other users in the authorization
table. Things under /public/
require no login, and can be accessed by anyone. However, the last rule adds an exception, where anything under /public/secret/
goes back to the default of allowing only authorized users access.
The path
in an access rule is a Lua pattern. Access rules are tested in reverse order, so later rules will override earlier rules.
Routes are handlers for specific URL patterns. When a URL matching one of these patterns is requested, the request is directed to a callback function to determine the response. URLs that match no routes are handled as simple file requests.
Routes use Lua patterns, and any captures are passed as parameters to the route handler function.
An example route is /players/(%d+)
. This would match a URL like /players/3
. If you wanted the name of the player on the server with the specified ID number to be the response, you could use a handler like this:
routes = {
["/players/(%d+)"] = function(request, response, helpers, player)
if GetPlayerEndpoint(player) then
response.send(GetPlayerName(player))
else
response.sendError(404)
end
end
}
The request
, response
, and helpers
arguments provide the interface for getting data from clients and sending data back to clients.
The incoming request from the client.
The raw path of the request.
The parsed URL, containing the normalized path (url.path
) and query parameters (url.query
).
The HTTP method of the request.
The HTTP headers of the request.
If authentication is required, this will contain the authenticated name of the user.
Reads the body of the request, and returns a promise which is resolved with the raw body data:
-- POST request: /echo
-- POST body: Hello
request.readBody():next(function(body)
response.send(body)
end)
Reads the body of the request as JSON, deserializes it, and returns a promise which is resolved with the result (or rejected with any errors encountered):
-- POST request: /multiply-by-two
-- POST body: {"input": 3}
request.readJson():next(function(data)
response.sendJson{output = data.input * 2}
end)
The response that will be sent back to the client.
Sets the HTTP status code and other headers of the response.
Writes data to the body of the response without closing it.
Writes data to the body of the response and closes it. No arguments will close the response without sending any additional data.
Sends an error page as the response.
Sends a file as the response.
Sends JSON data as the response. If data
is a string, it is sent as-is. If data
is not a string, it is encoded to a string with json.encode
.
Processes and sends a template string as the response.
Processes and sends a template file as the response.
Other helper functions.
Add an entry to the log. entry
is a table that can contain any fields.
Templates are strings or files which may contain variables or pieces of Lua code, which are preprocessed server-side before being sent in a response.
There are two kinds of directives that can be used in a template:
${...}
is replaced by the value of the expression inside.%{...}
is replaced by the return value of the block inside.
<p>Hello, ${name}!</p>
response.sendTemplateFile("test.html", {name = "Alice"})
<p><strong>%{
local lang = request.url.query["lang"]
if lang == "es" then
return "Numero de jugadores"
elseif lang == "fr" then
return "Nombre de joueurs"
else
return "Number of players"
end
}:</strong> ${#GetPlayers()}</p>
Variables can be defined in the env
parameter to the template helper functions. A request
variable always exists and contains the request information, just like a route callback.
The templateExtension
option to createHttpHandler
allows specifying an extension for HTML files which are automatically processed as templates. The default extension is .lsp
, so a file named mypage.lsp
will be automatically processed as a template when it is requested.