{"id":34838370,"url":"https://github.com/arkenidar/c_lua_http_client","last_synced_at":"2026-05-06T00:02:16.901Z","repository":{"id":329715204,"uuid":"1120064109","full_name":"arkenidar/c_lua_http_client","owner":"arkenidar","description":"luajit ffi : c and lua http client with libCurl","archived":false,"fork":false,"pushed_at":"2025-12-21T10:45:44.000Z","size":6533,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-23T02:44:52.249Z","etag":null,"topics":["c","client","ffi","http","libcurl","lua","luajit"],"latest_commit_sha":null,"homepage":"https://curl.se/libcurl/","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/arkenidar.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-20T12:13:32.000Z","updated_at":"2025-12-21T10:45:48.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/arkenidar/c_lua_http_client","commit_stats":null,"previous_names":["arkenidar/c_lua_http_client"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/arkenidar/c_lua_http_client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arkenidar%2Fc_lua_http_client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arkenidar%2Fc_lua_http_client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arkenidar%2Fc_lua_http_client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arkenidar%2Fc_lua_http_client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arkenidar","download_url":"https://codeload.github.com/arkenidar/c_lua_http_client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arkenidar%2Fc_lua_http_client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32672682,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["c","client","ffi","http","libcurl","lua","luajit"],"created_at":"2025-12-25T16:49:03.840Z","updated_at":"2026-05-06T00:02:16.894Z","avatar_url":"https://github.com/arkenidar.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LuaJIT HTTP Client with libcurl\n\nA lightweight, efficient HTTP client for LuaJIT using FFI bindings to libcurl. This library provides a simple and elegant API for making HTTP requests without external dependencies (except libcurl itself).\n\n## Features\n\n- Pure LuaJIT implementation using FFI (no C compilation needed)\n- Support for all common HTTP methods (GET, POST, PUT, DELETE, PATCH, HEAD)\n- Custom headers support\n- Request/response body handling\n- Timeout configuration\n- SSL/TLS support\n- Redirect following\n- JSON support (with optional lua-cjson)\n- Streaming response handling\n- Thread-safe and high-performance\n\n## Requirements\n\n- LuaJIT 2.0+\n- libcurl (shared library)\n  - Windows: `libcurl.dll` or `libcurl-4.dll`\n  - Linux: `libcurl.so`\n  - macOS: `libcurl.dylib`\n- Optional: `lua-cjson` for JSON encoding/decoding\n\n### Installing libcurl\n\n**Windows (MSYS2/MinGW):**\n```bash\npacman -S mingw-w64-x86_64-curl\n```\n\n**Linux (Debian/Ubuntu):**\n```bash\nsudo apt-get install libcurl4-openssl-dev\n```\n\n**Linux (Fedora/RHEL):**\n```bash\nsudo dnf install libcurl-devel\n```\n\n**macOS:**\n```bash\nbrew install curl\n```\n\n## Installation\n\nSimply copy the files to your project or add them to your LUA_PATH:\n\n```bash\n# Copy to your project\ncp curl_ffi.lua http_client.lua /path/to/your/project/\n\n# Or set LUA_PATH\nexport LUA_PATH=\"$LUA_PATH;/path/to/c_lua_http_client/?.lua\"\n```\n\n## Quick Start\n\n```lua\nlocal http = require(\"http_client\")\n\n-- Simple GET request\nlocal response, err = http.get(\"https://api.example.com/users\")\n\nif response then\n    print(\"Status: \" .. response.status)\n    print(\"Body: \" .. response.body)\n    print(\"Content-Type: \" .. response.content_type)\nelse\n    print(\"Error: \" .. err)\nend\n```\n\n## API Reference\n\n### Module Functions\n\n#### `http.get(url, options)`\nPerform a GET request.\n\n```lua\nlocal response, err = http.get(\"https://example.com\", {\n    headers = {\n        [\"Authorization\"] = \"Bearer token123\"\n    },\n    timeout = 10\n})\n```\n\n#### `http.post(url, options)`\nPerform a POST request.\n\n```lua\nlocal response, err = http.post(\"https://example.com/api\", {\n    body = \"key=value\",\n    headers = {\n        [\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n    }\n})\n```\n\n#### `http.put(url, options)`\nPerform a PUT request.\n\n#### `http.delete(url, options)`\nPerform a DELETE request.\n\n#### `http.patch(url, options)`\nPerform a PATCH request.\n\n#### `http.head(url, options)`\nPerform a HEAD request.\n\n#### `http.json(method, url, data, options)`\nPerform a request with JSON encoding/decoding (requires lua-cjson).\n\n```lua\nlocal response, err = http.json(\"POST\", \"https://api.example.com/users\", {\n    name = \"John Doe\",\n    email = \"john@example.com\"\n})\n\nif response and response.json then\n    print(\"User ID: \" .. response.json.id)\nend\n```\n\n### Client Instance\n\nCreate a custom client instance with default options:\n\n```lua\nlocal client = http.new({\n    timeout = 30,\n    connect_timeout = 10,\n    follow_redirects = true,\n    max_redirects = 10,\n    user_agent = \"MyApp/1.0\",\n    verify_ssl = true,\n    verbose = false\n})\n\nlocal response, err = client:get(\"https://example.com\")\n```\n\n### Request Options\n\nAll request methods accept an options table:\n\n```lua\n{\n    -- Request body (string)\n    body = \"request data\",\n\n    -- Custom headers (table)\n    headers = {\n        [\"Content-Type\"] = \"application/json\",\n        [\"Authorization\"] = \"Bearer token\"\n    },\n\n    -- Timeout in seconds\n    timeout = 30,\n\n    -- Connection timeout in seconds\n    connect_timeout = 10,\n\n    -- Follow redirects\n    follow_redirects = true,\n\n    -- Maximum number of redirects\n    max_redirects = 10,\n\n    -- Custom User-Agent\n    user_agent = \"MyApp/1.0\",\n\n    -- Verify SSL certificates\n    verify_ssl = true,\n\n    -- Verbose output (for debugging)\n    verbose = false\n}\n```\n\n### Response Object\n\nSuccessful requests return a response table:\n\n```lua\n{\n    status = 200,                    -- HTTP status code\n    headers = {                       -- Response headers (lowercase keys)\n        [\"content-type\"] = \"application/json\",\n        [\"content-length\"] = \"1234\"\n    },\n    body = \"response body\",          -- Response body as string\n    content_type = \"application/json\", -- Content-Type header value\n    url = \"https://final.url\",       -- Final URL (after redirects)\n    json = { ... }                   -- Parsed JSON (only with http.json())\n}\n```\n\nFailed requests return `nil, error_message, partial_response`.\n\n## Examples\n\n### Basic GET Request\n\n```lua\nlocal http = require(\"http_client\")\n\nlocal response, err = http.get(\"https://httpbin.org/get\")\nif response then\n    print(\"Status:\", response.status)\n    print(\"Body:\", response.body)\nend\n```\n\n### POST with Form Data\n\n```lua\nlocal response, err = http.post(\"https://httpbin.org/post\", {\n    body = \"name=John\u0026email=john@example.com\",\n    headers = {\n        [\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n    }\n})\n```\n\n### POST with JSON\n\n```lua\nlocal response, err = http.json(\"POST\", \"https://httpbin.org/post\", {\n    name = \"Alice\",\n    age = 30\n})\n\nif response and response.json then\n    -- Access parsed JSON response\n    print(response.json.data)\nend\n```\n\n### Custom Headers\n\n```lua\nlocal response, err = http.get(\"https://api.example.com/data\", {\n    headers = {\n        [\"Authorization\"] = \"Bearer your-token\",\n        [\"Accept\"] = \"application/json\",\n        [\"X-Custom-Header\"] = \"value\"\n    }\n})\n```\n\n### Timeout Handling\n\n```lua\nlocal response, err = http.get(\"https://slow-server.com\", {\n    timeout = 5,  -- 5 second timeout\n    connect_timeout = 2\n})\n\nif not response then\n    print(\"Request failed:\", err)\nend\n```\n\n### Custom Client Instance\n\n```lua\nlocal client = http.new({\n    timeout = 60,\n    user_agent = \"MyBot/2.0\",\n    verify_ssl = false  -- Disable SSL verification (not recommended)\n})\n\nlocal response = client:get(\"https://self-signed-cert.com\")\n```\n\n### Following Redirects\n\n```lua\nlocal response, err = http.get(\"https://httpbin.org/redirect/5\", {\n    follow_redirects = true,\n    max_redirects = 10\n})\n\nif response then\n    print(\"Final URL:\", response.url)\n    print(\"Status:\", response.status)\nend\n```\n\n## Error Handling\n\nAlways check for errors:\n\n```lua\nlocal response, err, partial = http.get(\"https://invalid-url\")\n\nif not response then\n    print(\"Error:\", err)\n    if partial then\n        print(\"Partial response available\")\n        print(\"Status:\", partial.status)\n    end\nelse\n    print(\"Success:\", response.status)\nend\n```\n\n## Low-Level API\n\nFor advanced usage, you can use the low-level FFI bindings directly:\n\n```lua\nlocal curl_ffi = require(\"curl_ffi\")\n\nlocal handle = curl_ffi.init()\ncurl_ffi.setopt(handle, ffi.C.CURLOPT_URL, \"https://example.com\")\n-- ... more options\nlocal result = curl_ffi.perform(handle)\ncurl_ffi.cleanup(handle)\n```\n\n## File Structure\n\n- [curl_ffi.lua](curl_ffi.lua) - Low-level FFI bindings to libcurl\n- [http_client.lua](http_client.lua) - High-level HTTP client wrapper\n- [example.lua](example.lua) - Usage examples and test cases\n\n## Performance\n\nThis library uses LuaJIT's FFI which provides near-native performance for libcurl operations. The overhead is minimal compared to pure C implementations.\n\n## Thread Safety\n\nEach request creates its own CURL handle, making it safe to use from multiple coroutines. However, the global libcurl initialization is done once at module load time.\n\n## Limitations\n\n- Binary file uploads require manual setup (use low-level API)\n- No built-in progress callbacks (can be added using low-level API)\n- Multipart form data requires manual construction\n\n## License\n\nThis project is provided as-is for educational and commercial use.\n\n## Contributing\n\nContributions are welcome. Please ensure code follows the existing style and includes examples.\n\n## Troubleshooting\n\n### \"Could not load libcurl\" error\n\nMake sure libcurl is installed and in your system's library path:\n\n**Windows:** Add the directory containing `libcurl.dll` to your PATH\n**Linux/macOS:** Use `ldconfig` or set `LD_LIBRARY_PATH`\n\n### SSL Certificate Errors\n\nIf you encounter SSL certificate verification errors:\n\n```lua\n-- Disable verification (not recommended for production)\nlocal response = http.get(url, { verify_ssl = false })\n```\n\n### Timeout Issues\n\nAdjust timeout values based on your network conditions:\n\n```lua\nlocal response = http.get(url, {\n    timeout = 60,           -- Total request timeout\n    connect_timeout = 10    -- Connection timeout\n})\n```\n\n## Version\n\nlibcurl version can be checked with:\n\n```lua\nlocal http = require(\"http_client\")\nprint(http.version())\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farkenidar%2Fc_lua_http_client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farkenidar%2Fc_lua_http_client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farkenidar%2Fc_lua_http_client/lists"}