{"id":40270118,"url":"https://github.com/kibook/httpmanager","last_synced_at":"2026-01-20T02:54:15.418Z","repository":{"id":45113403,"uuid":"395395408","full_name":"kibook/httpmanager","owner":"kibook","description":"HTTP handler library for FiveM and RedM","archived":false,"fork":false,"pushed_at":"2022-05-04T15:40:26.000Z","size":130,"stargazers_count":26,"open_issues_count":0,"forks_count":16,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-08-01T18:14:05.071Z","etag":null,"topics":["citizenfx","fivem","redm"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kibook.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-08-12T17:25:30.000Z","updated_at":"2023-07-30T22:29:54.000Z","dependencies_parsed_at":"2022-09-02T23:10:52.078Z","dependency_job_id":null,"html_url":"https://github.com/kibook/httpmanager","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"purl":"pkg:github/kibook/httpmanager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibook%2Fhttpmanager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibook%2Fhttpmanager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibook%2Fhttpmanager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibook%2Fhttpmanager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kibook","download_url":"https://codeload.github.com/kibook/httpmanager/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kibook%2Fhttpmanager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28594958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T02:08:49.799Z","status":"ssl_error","status_checked_at":"2026-01-20T02:08:44.148Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["citizenfx","fivem","redm"],"created_at":"2026-01-20T02:54:14.643Z","updated_at":"2026-01-20T02:54:15.408Z","avatar_url":"https://github.com/kibook.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# httpmanager\n\nHTTP handler utility for FiveM and RedM. It can be used as a simple file server, or to provide easy HTTP functionality to any resource.\n\n# Installation\n\n1. Place in your resources directory.\n\n2. Add `start httpmanager` to server.cfg.\n\n# Usage\n\n## As a standalone file server\n\nAfter installing, you can place files in the `http` folder inside the `httpmanager` resource folder, and those files will be accessible at:\n\n```\nhttp://[server IP]:[server port]/httpmanager/...\n```\nor\n```\nhttps://[owner]-[server ID].users.cfx.re/httpmanager/...\n```\n\nFor 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`.\n\n## In other resources\n\nYou can quickly add HTTP functionality to any resource using the `createHttpHandler` export:\n\n```lua\nhandler = exports.httpmanager:createHttpHandler(options)\n```\n\nThis creates a new HTTP handler that can be used with `SetHttpHandler` in a server script in the resource:\n\n```lua\nSetHttpHandler(exports.httpmanager:createHttpHandler())\n```\n\n`options` is a table containing configuration options for the new handler. Any unspecified options will be given their default value.\n\n| Option              | Description                                                                                  | Default        |\n|---------------------|----------------------------------------------------------------------------------------------|----------------|\n| `documentRoot`      | The directory in the resource folder where files are served from.                            | `\"http\"`       |\n| `directoryIndex`    | If the path points to a directory, a file with this name inside that directory will be sent. | `\"index.html\"` |\n| `templateExtension` | File extension for files that will be automatically preprocessed as templates.               | `\"lsp\"`        |\n| `authorization`     | A table of usernames and passwords required to access any files or routes.                   | `nil`          |\n| `access`            | A table of paths with which users can access them.                                           | `{}`           |\n| `log`               | Whether to log requests to a file in the resource directory.                                 | `false`        |\n| `logFile`           | If `log` is `true`, store the log in this file in the resource directory.                    | `\"log.json\"`   |\n| `errorPages`        | A table of custom pages for different error codes (e.g., 404).                               | `{}`           |\n| `mimeTypes`         | A table of MIME type associations for extensions, which will override any detected type.     | `{}`           |\n| `routes`            | A table of route patterns and callbacks.                                                     | `{}`           |\n\n```lua\nSetHttpHandler(exports.httpmanager:createHttpHandler {\n\tdocumentRoot = \"root\",\n\tdirectoryIndex = \"index.html\",\n\ttemplateExtension = \"html\",\n\tauthorization = {\n\t\t[\"admin\"] = \"$2a$11$HoxJPx5sTe4RX5qPw1OkSO.ukDdwAvGJwXtmyOE5i.1gz7EvN71.q\",\n\t\t[\"user\"] = \"$2a$11$ILOCJlRiUPhRpmqYiZDDM.EdI16yOtMBTLJKTBLSUHTFzyXjXHJYa\"\n\t},\n\taccess = {\n\t\t{path = \"/admin/.*\", login = {[\"admin\"] = true}},\n\t\t{path = \"/public/.*\", login = false},\n\t\t{path = \"/public/secret/.*\"}\n\t},\n\tlog = true,\n\tlogFile = \"log.json\",\n\terrorPages = {\n\t\t[404] = \"custom404.html\"\n\t},\n\tmimeTypes = {\n\t\t[\"ogg\"] = \"audio/ogg\"\n\t},\n\troutes = {\n\t\t[\"/players/(%d+)\"] = function(req, res, helpers, player)\n\t\t\tif GetPlayerEndpoint(player) then\n\t\t\t\tres.send(GetPlayerName(player))\n\t\t\telse\n\t\t\t\tres.sendError(404)\n\t\t\tend\n\t\tend\n\t}\n})\n```\n\n## Authorization\n\nAccess 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.\n\nPasswords 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/`.\n\n```lua\nauthorization = {\n\t[\"admin\"] = \"$2a$11$HoxJPx5sTe4RX5qPw1OkSO.ukDdwAvGJwXtmyOE5i.1gz7EvN71.q\"\n}\n```\n\nRather than defining users separately for every resource, you can define central groups of users using realms. Realms are configured in [realms.lua](realms.lua):\n\n```lua\nRealms = {\n\t[\"default\"] = {\n\t\t[\"admin\"] = \"$2a$11$HoxJPx5sTe4RX5qPw1OkSO.ukDdwAvGJwXtmyOE5i.1gz7EvN71.q\"\n\t},\n\t[\"realm1\"] = {\n\t\tinherit = \"default\",\n\t\t[\"user1\"] = \"$2a$11$4RIDavyfsCw/vhImQdDYcOKgCnnJ0ZcJQCFeM8wfF1jkEGN/YnOOG\",\n\t\t[\"user2\"] = \"$2a$11$dMe9J7jkhg8N5E/VArrEn.1UKhB9QocNqDopPJkcRNXQ1p4KQDdQG\"\n\t},\n\t[\"realm2\"] = {\n\t\t...\n\t}\n}\n```\n\nTo use a realm, specify its name as a string for `authorization`:\n\n```lua\nSetHttpHandler(exports.httpmanager:createHttpHandler{\n\tauthorization = \"realm1\"\n})\n```\n\nResources which use the same realm will share the same logins, allowing users to go between them without re-entering their password.\n\nAccess 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.\n\n```lua\naccess = {\n\t{path = \"/admin/.*\", login = {[\"admin\"] = true}},\n\t{path = \"/public/.*\", login = false},\n\t{path = \"/public/secret/.*\"}\n}\n```\n\nIn 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.\n\nThe `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.\n\n## Routes\n\nRoutes 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.\n\nRoutes 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.\n\nAn 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:\n\n```lua\nroutes = {\n\t[\"/players/(%d+)\"] = function(request, response, helpers, player)\n\t\tif GetPlayerEndpoint(player) then\n\t\t\tresponse.send(GetPlayerName(player))\n\t\telse\n\t\t\tresponse.sendError(404)\n\t\tend\n\tend\n}\n```\n\nThe `request`, `response`, and `helpers` arguments provide the interface for getting data from clients and sending data back to clients.\n\n### `request`\n\nThe incoming request from the client.\n\n#### `request.path`\n\nThe raw path of the request.\n\n#### `request.url`\n\nThe parsed URL, containing the normalized path (`url.path`) and query parameters (`url.query`).\n\n#### `request.method`\n\nThe HTTP method of the request.\n\n#### `request.headers`\n\nThe HTTP headers of the request.\n\n#### `request.user`\n\nIf authentication is required, this will contain the authenticated name of the user.\n\n#### `request.readBody()`\n\nReads the body of the request, and returns a promise which is resolved with the raw body data:\n\n```lua\n-- POST request: /echo\n-- POST body: Hello\nrequest.readBody():next(function(body)\n\tresponse.send(body)\nend)\n```\n\n#### `request.readJson()`\n\nReads 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):\n\n```lua\n-- POST request: /multiply-by-two\n-- POST body: {\"input\": 3}\nrequest.readJson():next(function(data)\n\tresponse.sendJson{output = data.input * 2}\nend)\n```\n\n### `response`\n\nThe response that will be sent back to the client.\n\n#### `response.writeHead(code, [headers])`\n\nSets the HTTP status code and other headers of the response.\n\n#### `response.write(data)`\n\nWrites data to the body of the response without closing it.\n\n#### `response.send(data)`\n\nWrites data to the body of the response and closes it. No arguments will close the response without sending any additional data.\n\n#### `response.sendError(code, [details, [headers]])`\n\nSends an error page as the response.\n\n#### `response.sendFile(path)`\n\nSends a file as the response.\n\n#### `response.sendJson(data, [code, [headers]])`\n\nSends 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`.\n\n#### `response.sendTemplate(content, [env, [code, [headers]]])`\n\nProcesses and sends a template string as the response.\n\n#### `response.sendTemplateFile(path, [env, [code, [headers]]])`\n\nProcesses and sends a template file as the response.\n\n### `helpers`\n\nOther helper functions.\n\n#### `helpers.log(entry)`\n\nAdd an entry to the log. `entry` is a table that can contain any fields.\n\n## Templates\n\nTemplates are strings or files which may contain variables or pieces of Lua code, which are preprocessed server-side before being sent in a response.\n\nThere are two kinds of directives that can be used in a template:\n\n- `${...}` is replaced by the value of the expression inside.\n- `%{...}` is replaced by the return value of the block inside.\n\n### Expression directive\n\n```html\n\u003cp\u003eHello, ${name}!\u003c/p\u003e\n```\n\n```lua\nresponse.sendTemplateFile(\"test.html\", {name = \"Alice\"})\n```\n\n### Block directive\n\n```html\n\u003cp\u003e\u003cstrong\u003e%{\nlocal lang = request.url.query[\"lang\"]\n\nif lang == \"es\" then\n\treturn \"Numero de jugadores\"\nelseif lang == \"fr\" then\n\treturn \"Nombre de joueurs\"\nelse\n\treturn \"Number of players\"\nend\n}:\u003c/strong\u003e ${#GetPlayers()}\u003c/p\u003e\n```\n\nVariables 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.\n\nThe `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.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkibook%2Fhttpmanager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkibook%2Fhttpmanager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkibook%2Fhttpmanager/lists"}