https://github.com/arkenidar/c_lua_http_client
luajit ffi : c and lua http client with libCurl
https://github.com/arkenidar/c_lua_http_client
c client ffi http libcurl lua luajit
Last synced: about 2 months ago
JSON representation
luajit ffi : c and lua http client with libCurl
- Host: GitHub
- URL: https://github.com/arkenidar/c_lua_http_client
- Owner: arkenidar
- Created: 2025-12-20T12:13:32.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-21T10:45:44.000Z (6 months ago)
- Last Synced: 2025-12-23T02:44:52.249Z (6 months ago)
- Topics: c, client, ffi, http, libcurl, lua, luajit
- Language: Lua
- Homepage: https://curl.se/libcurl/
- Size: 6.23 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# LuaJIT HTTP Client with libcurl
A 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).
## Features
- Pure LuaJIT implementation using FFI (no C compilation needed)
- Support for all common HTTP methods (GET, POST, PUT, DELETE, PATCH, HEAD)
- Custom headers support
- Request/response body handling
- Timeout configuration
- SSL/TLS support
- Redirect following
- JSON support (with optional lua-cjson)
- Streaming response handling
- Thread-safe and high-performance
## Requirements
- LuaJIT 2.0+
- libcurl (shared library)
- Windows: `libcurl.dll` or `libcurl-4.dll`
- Linux: `libcurl.so`
- macOS: `libcurl.dylib`
- Optional: `lua-cjson` for JSON encoding/decoding
### Installing libcurl
**Windows (MSYS2/MinGW):**
```bash
pacman -S mingw-w64-x86_64-curl
```
**Linux (Debian/Ubuntu):**
```bash
sudo apt-get install libcurl4-openssl-dev
```
**Linux (Fedora/RHEL):**
```bash
sudo dnf install libcurl-devel
```
**macOS:**
```bash
brew install curl
```
## Installation
Simply copy the files to your project or add them to your LUA_PATH:
```bash
# Copy to your project
cp curl_ffi.lua http_client.lua /path/to/your/project/
# Or set LUA_PATH
export LUA_PATH="$LUA_PATH;/path/to/c_lua_http_client/?.lua"
```
## Quick Start
```lua
local http = require("http_client")
-- Simple GET request
local response, err = http.get("https://api.example.com/users")
if response then
print("Status: " .. response.status)
print("Body: " .. response.body)
print("Content-Type: " .. response.content_type)
else
print("Error: " .. err)
end
```
## API Reference
### Module Functions
#### `http.get(url, options)`
Perform a GET request.
```lua
local response, err = http.get("https://example.com", {
headers = {
["Authorization"] = "Bearer token123"
},
timeout = 10
})
```
#### `http.post(url, options)`
Perform a POST request.
```lua
local response, err = http.post("https://example.com/api", {
body = "key=value",
headers = {
["Content-Type"] = "application/x-www-form-urlencoded"
}
})
```
#### `http.put(url, options)`
Perform a PUT request.
#### `http.delete(url, options)`
Perform a DELETE request.
#### `http.patch(url, options)`
Perform a PATCH request.
#### `http.head(url, options)`
Perform a HEAD request.
#### `http.json(method, url, data, options)`
Perform a request with JSON encoding/decoding (requires lua-cjson).
```lua
local response, err = http.json("POST", "https://api.example.com/users", {
name = "John Doe",
email = "john@example.com"
})
if response and response.json then
print("User ID: " .. response.json.id)
end
```
### Client Instance
Create a custom client instance with default options:
```lua
local client = http.new({
timeout = 30,
connect_timeout = 10,
follow_redirects = true,
max_redirects = 10,
user_agent = "MyApp/1.0",
verify_ssl = true,
verbose = false
})
local response, err = client:get("https://example.com")
```
### Request Options
All request methods accept an options table:
```lua
{
-- Request body (string)
body = "request data",
-- Custom headers (table)
headers = {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer token"
},
-- Timeout in seconds
timeout = 30,
-- Connection timeout in seconds
connect_timeout = 10,
-- Follow redirects
follow_redirects = true,
-- Maximum number of redirects
max_redirects = 10,
-- Custom User-Agent
user_agent = "MyApp/1.0",
-- Verify SSL certificates
verify_ssl = true,
-- Verbose output (for debugging)
verbose = false
}
```
### Response Object
Successful requests return a response table:
```lua
{
status = 200, -- HTTP status code
headers = { -- Response headers (lowercase keys)
["content-type"] = "application/json",
["content-length"] = "1234"
},
body = "response body", -- Response body as string
content_type = "application/json", -- Content-Type header value
url = "https://final.url", -- Final URL (after redirects)
json = { ... } -- Parsed JSON (only with http.json())
}
```
Failed requests return `nil, error_message, partial_response`.
## Examples
### Basic GET Request
```lua
local http = require("http_client")
local response, err = http.get("https://httpbin.org/get")
if response then
print("Status:", response.status)
print("Body:", response.body)
end
```
### POST with Form Data
```lua
local response, err = http.post("https://httpbin.org/post", {
body = "name=John&email=john@example.com",
headers = {
["Content-Type"] = "application/x-www-form-urlencoded"
}
})
```
### POST with JSON
```lua
local response, err = http.json("POST", "https://httpbin.org/post", {
name = "Alice",
age = 30
})
if response and response.json then
-- Access parsed JSON response
print(response.json.data)
end
```
### Custom Headers
```lua
local response, err = http.get("https://api.example.com/data", {
headers = {
["Authorization"] = "Bearer your-token",
["Accept"] = "application/json",
["X-Custom-Header"] = "value"
}
})
```
### Timeout Handling
```lua
local response, err = http.get("https://slow-server.com", {
timeout = 5, -- 5 second timeout
connect_timeout = 2
})
if not response then
print("Request failed:", err)
end
```
### Custom Client Instance
```lua
local client = http.new({
timeout = 60,
user_agent = "MyBot/2.0",
verify_ssl = false -- Disable SSL verification (not recommended)
})
local response = client:get("https://self-signed-cert.com")
```
### Following Redirects
```lua
local response, err = http.get("https://httpbin.org/redirect/5", {
follow_redirects = true,
max_redirects = 10
})
if response then
print("Final URL:", response.url)
print("Status:", response.status)
end
```
## Error Handling
Always check for errors:
```lua
local response, err, partial = http.get("https://invalid-url")
if not response then
print("Error:", err)
if partial then
print("Partial response available")
print("Status:", partial.status)
end
else
print("Success:", response.status)
end
```
## Low-Level API
For advanced usage, you can use the low-level FFI bindings directly:
```lua
local curl_ffi = require("curl_ffi")
local handle = curl_ffi.init()
curl_ffi.setopt(handle, ffi.C.CURLOPT_URL, "https://example.com")
-- ... more options
local result = curl_ffi.perform(handle)
curl_ffi.cleanup(handle)
```
## File Structure
- [curl_ffi.lua](curl_ffi.lua) - Low-level FFI bindings to libcurl
- [http_client.lua](http_client.lua) - High-level HTTP client wrapper
- [example.lua](example.lua) - Usage examples and test cases
## Performance
This library uses LuaJIT's FFI which provides near-native performance for libcurl operations. The overhead is minimal compared to pure C implementations.
## Thread Safety
Each 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.
## Limitations
- Binary file uploads require manual setup (use low-level API)
- No built-in progress callbacks (can be added using low-level API)
- Multipart form data requires manual construction
## License
This project is provided as-is for educational and commercial use.
## Contributing
Contributions are welcome. Please ensure code follows the existing style and includes examples.
## Troubleshooting
### "Could not load libcurl" error
Make sure libcurl is installed and in your system's library path:
**Windows:** Add the directory containing `libcurl.dll` to your PATH
**Linux/macOS:** Use `ldconfig` or set `LD_LIBRARY_PATH`
### SSL Certificate Errors
If you encounter SSL certificate verification errors:
```lua
-- Disable verification (not recommended for production)
local response = http.get(url, { verify_ssl = false })
```
### Timeout Issues
Adjust timeout values based on your network conditions:
```lua
local response = http.get(url, {
timeout = 60, -- Total request timeout
connect_timeout = 10 -- Connection timeout
})
```
## Version
libcurl version can be checked with:
```lua
local http = require("http_client")
print(http.version())
```