https://github.com/kibook/httpmanager
HTTP handler library for FiveM and RedM
https://github.com/kibook/httpmanager
citizenfx fivem redm
Last synced: 5 months ago
JSON representation
HTTP handler library for FiveM and RedM
- Host: GitHub
- URL: https://github.com/kibook/httpmanager
- Owner: kibook
- Created: 2021-08-12T17:25:30.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2022-05-04T15:40:26.000Z (about 4 years ago)
- Last Synced: 2023-08-01T18:14:05.071Z (almost 3 years ago)
- Topics: citizenfx, fivem, redm
- Language: Lua
- Homepage:
- Size: 127 KB
- Stars: 26
- Watchers: 2
- Forks: 16
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# httpmanager
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.
# Installation
1. Place in your resources directory.
2. Add `start httpmanager` to server.cfg.
# Usage
## As a standalone file server
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`.
## In other resources
You can quickly add HTTP functionality to any resource using the `createHttpHandler` export:
```lua
handler = exports.httpmanager:createHttpHandler(options)
```
This creates a new HTTP handler that can be used with `SetHttpHandler` in a server script in the resource:
```lua
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. | `{}` |
```lua
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
}
})
```
## Authorization
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/`.
```lua
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.lua):
```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`:
```lua
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.
```lua
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](https://www.lua.org/pil/20.2.html). Access rules are tested in reverse order, so later rules will override earlier rules.
## Routes
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](https://www.lua.org/pil/20.2.html), and any [captures](https://www.lua.org/pil/20.3.html) 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:
```lua
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.
### `request`
The incoming request from the client.
#### `request.path`
The raw path of the request.
#### `request.url`
The parsed URL, containing the normalized path (`url.path`) and query parameters (`url.query`).
#### `request.method`
The HTTP method of the request.
#### `request.headers`
The HTTP headers of the request.
#### `request.user`
If authentication is required, this will contain the authenticated name of the user.
#### `request.readBody()`
Reads the body of the request, and returns a promise which is resolved with the raw body data:
```lua
-- POST request: /echo
-- POST body: Hello
request.readBody():next(function(body)
response.send(body)
end)
```
#### `request.readJson()`
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):
```lua
-- POST request: /multiply-by-two
-- POST body: {"input": 3}
request.readJson():next(function(data)
response.sendJson{output = data.input * 2}
end)
```
### `response`
The response that will be sent back to the client.
#### `response.writeHead(code, [headers])`
Sets the HTTP status code and other headers of the response.
#### `response.write(data)`
Writes data to the body of the response without closing it.
#### `response.send(data)`
Writes data to the body of the response and closes it. No arguments will close the response without sending any additional data.
#### `response.sendError(code, [details, [headers]])`
Sends an error page as the response.
#### `response.sendFile(path)`
Sends a file as the response.
#### `response.sendJson(data, [code, [headers]])`
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`.
#### `response.sendTemplate(content, [env, [code, [headers]]])`
Processes and sends a template string as the response.
#### `response.sendTemplateFile(path, [env, [code, [headers]]])`
Processes and sends a template file as the response.
### `helpers`
Other helper functions.
#### `helpers.log(entry)`
Add an entry to the log. `entry` is a table that can contain any fields.
## Templates
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.
### Expression directive
```html
Hello, ${name}!
```
```lua
response.sendTemplateFile("test.html", {name = "Alice"})
```
### Block directive
```html
%{
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
}: ${#GetPlayers()}
```
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.