# coro-http
Documentation for the library coro-http, version 3.2.3.
coro-http is a library implementing an HTTP 1.1 client and server. It uses a sync code-style making use of Lua coroutines, while keeping everything asynchronous behind the scenes. That is, it yields but it does NOT block any threads.
Can be used as a great replacement for the Luvit built-in http & https libraries, to get rid of the callback code-style, with a more user-friendly interface. This is achieved through coroutines yielding and resuming without blocking the main event loop of luv.
Keep in mind, Luvit (starting with version 2.18) already wraps the main file in a coroutine for you!
Many thanks for @trumedian for helping out with this!
# Installation
lit install creationix/coro-http
# Functions
# request(method, url[, headers[, body[, options]]])
Synchronously performs a non-blocking HTTP(s) request after establishing a connection with the said host.
-
This method will raise an error on network failure. Advised to be called with
pcall
/xpcall
. -
If the needed connection [with the host specified in
url
] has been previously established and is still alive, it will be reused instead of establishing a new one. Generally this happen by a previousrequest
call or by manually callingsaveConnection
. -
Be aware that coro-http will try to auto-set some headers if the user doesn’t supply them, specifically
Content-Length
andHost
.Host
will be set to the hostname if not provided.Content-Length
is set to the length ofbody
when the request is not chunked (Content-Encoding
is notchunked
) and it wasn’t already provided by the user.
This method MUST be run in a coroutine
# Parameters
Param | Type | Description | Optional |
---|---|---|---|
method | string | An all uppercase HTTP method name. | ❌ |
url | string | An HTTP(s) URL to send the request to. | ❌ |
headers | http-header | The HTTP headers of the request. | ✔ |
body | string | The request’s payload (if needed). | ✔ |
options | Request-Options/Timeout | - If a number is supplied, this will act as the timeout to wait before giving up on receiving a response. - If a table is supplied, this will act as a table to provide additional configurations. See Request-Options for more details. |
✔ |
# Returns
Name | Type | Description |
---|---|---|
res | Response | A Response structure representing the received response. |
body | string | The response payload (body) the server responded with as a string if any, otherwise an empty string. |
# Examples
- Requesting Google’s main page
local res, body = request("GET", "https://www.google.com")
if res.code ~= 200 then
print("Could not fetch www.google.com successfully: " .. res.reason); return
end
print("Received Google main page HTML: " .. body)
- Sending a Discord webhook using POST request
local json = require("json")
local webhook_url = "https://discord.com/api/webhooks/{ID}/{TOKEN}" -- Your webhook URL here
-- Discord expects a body that is a JSON string
-- we use the built-in json module to encode a Lua table into JSON
local body = json.encode{
content = "Hello There!\nThis is an example for a POST request using coro-http!"
}
local headers = {
{"Content-Type", "application/json"}, -- we are sending a JSON form string for the body
{"User-Agent", "MyWebhookClient"}. -- an optional example UA
}
-- Send the POST request
local res = request("POST", webhook_url, headers, body, 5000)
-- Was the request successful?
if res.code < 200 or res.code >= 300 then
return print("Failed to send webhook: " .. res.reason)
end
print("Webhook sent successfully!")
# createServer(host, port, onConnect)
Creates a new server instance and asynchronously binds it to host:port.
This method does not require running in a coroutine
# Parameters
Param | Type | Description |
---|---|---|
host | string | The host which the server corresponds to. |
port | number | The port to which the created server should listen on. |
onConnect | function | See onConnect for details. |
# Returns
Name | Type | Description |
---|---|---|
server | uv_tcp_t | The TCP socket of the created server. Server connection can be stopped and manipulated using this. |
# onConnect
A callback that will be asynchronously called each time a new connection is established to the server. That is, when a connection is received.
-
For a response the callback must return at least one value, and at most two values, those returns are:
head, body
. Wherehead
is a Response structure, andbody
is an optional string payload. -
If a second value was returned (for the payload), a
Content-Length
header must be set to the length of the returned payload. Chunked responses are not supported.
The callback has the following parameters:
Param | Type | Description |
---|---|---|
req | Request | The request’s headers and general information. |
body | string | The provided request’s payload as a string, empty string incase no payload is provided. |
socket | uv_tcp_t/uv_pipe_t | The socket that the connection was bound to. |
# Examples
- A local server that responds with 200
local res_payload = "Hello!"
local res_headers = {
{"Content-Length", tostring(#res_payload)}, -- Must always be set if a payload is returned
{"Content-Type", "text/plain"}, -- Type of the response's payload (res_payload)
{"Connection", "close"}, -- Whether to keep the connection alive, or close it
code = 200,
reason = "OK",
}
-- 127.0.0.1 is localhost
createServer("127.0.0.1", 8080, function(req, body)
print(req.method .. " request with the payload of '" .. body .. "'")
return res_headers, res_payload -- respond with this to every request
end)
# parseUrl(url)
Parses the given string representing a valid HTTP(s) URL into a Lua table.
This method does not require running in a coroutine
# Parameters
Param | Type | Description |
---|---|---|
url | string | The HTTP URL to be parsed. An error will be raised up if it is not a valid HTTP URL. |
# Returns
Name | Type | Description |
---|---|---|
result | table | A Parsed URL structure representing the URL as a Lua table. |
# Examples
- Parse a url and print its information
local url = "https://www.example:8080.com/path/to/index"
local pu = parseUrl(url)
print(([[
hostname: %s
path: %s
host: %s
port: %d
HTTPS?: %s
]]):format(
pu.hostname, pu.path, pu.host, pu.port,
pu.tls and true or false
))
# getConnection(host, port [, tls [, timeout]])
Establishes a new TCP connection with the given host on the given port.
-
If the connection was previously saved using
saveConnection
, calling this will return that connection and un-save it. -
If the saved connection was closed, or there were none previously saved, a new connection will be established instead.
-
User should never need this in normal scenarios.
This method MUST be run in a coroutine
# Parameters
Param | Type | Description | Optional |
---|---|---|---|
host | string | The host which the established connection refers to. | ❌ |
port | number | The port that this connection should refer to when connecting to the host. | ❌ |
tls | boolean/TLS Options | The use of SSL/TLS cryptographic protocol. - Boolean value whether to use SSL/TLS cert or not. - Table value to use SSL/TLS, with optional configurations. See TLS Options for acceptable fields. |
✔ Default: false . |
timeout | Timeout | How much time to wait for the response before canceling the request out. | ✔ |
# Returns
Name | Type | Description |
---|---|---|
connection | TCP Connection | The established connection. |
# saveConnection(connection)
Saves a pre-established TCP connection to be used later instead of establishing a new one (e.g. would be used by request).
-
If the passed connection is dead nothing will be saved.
-
User should never need this in normal scenarios.
This method does not require running in a coroutine
# Parameters
Param | Type | Description |
---|---|---|
connection | TCP Connection | A table representing a TCP connection returned by getConnection . |
# Structures
Here are the data structures (tables mostly) used by the library’s methods, either as returns or as arguments.
Whenever one of those structures is used throughout the documentation, it will be linked to here for further details.
Each structure has a description, and possibly a Structure
section that describes the table value. The syntax {foo, bar}
represents an array that has exactly two elements, tbl[1]
and tbl[2]
, what those values exactly are will be described below it in the Where
section. The syntax {foo...}
represents an array that could contain any size of element foo
. The syntax {foo = (type)}
represents a dictionary table that has a field foo
which is of type (type)
. Table values could contain multiple of those syntaxes.
# HTTP Header
A table structure representing an HTTP(s) header. The structure is an array of two strings, the first entry is the header-name, and the second entry is the header-value. See RFC2616 specification Section 14 for more details about the officially acceptable HTTP 1.1 headers.
# Structure
Full: {header-name, header-value}
.
- Where:
Entry | Type | Description |
---|---|---|
header-name | string | The name of the header. |
header-value | string | The value of the header. |
Examples:
{"Expires", "-1"}
.{"Accept", "text/plain"}
.
# Request/Response
Represents an HTTP(s) request or a response including the headers, and other general information about the connection. The exact data is highly dependent on the server/client and therefore the docs cannot tell exactly what fields to expect. If you need to know the exact provided fields, you should either debug your code or read the API manual of the said server.
# Structure
Full:
{
http_header...,
code = (number),
method = (string),
reason = (string),
version = (number),
keepAlive = (boolean),
}
- Where:
Entry | Type | Description |
---|---|---|
http_header | http-header | A sequence of http-header structures each individually. Meaning, each header is assigned to a numerical index in the structure. |
code | number | The HTTP status code. |
reason | string | The reason for getting the past status code (Reason-Phrase). |
version | number | The version of the used HTTP protocol as decimal number. |
keepAlive | boolean | Whether or not the connection should be kept alive. |
Examples:
{
{"Content-Type", "text/html"},
{"Content-Length", "1587"},
code = 200,
reason = "OK",
version = 1.1,
keepAlive = true
}
# TCP Connection
A table structure that represents a TCP connection (wrapped using coro-channel). The structure offers methods to directly read and write from the socket, and other details about the connection. Generally speaking you should only use these when it is the only way to accomplish what you need since they are for advanced uses.
# Available Fields
Field | Type | Description |
---|---|---|
socket | uv_tcp_t | The TCP socket (handle) used to bind the established connection. |
host | string | Same as the passed parameter host when establishing. |
port | number | Same as the passed parameter port when establishing. |
tls | table/boolean | Same as the passed parameter tls when establishing. |
read | function | A coro-channel reader that receives a new chunk of data each time it is resumed. |
write | function | A coro-channel writer that sends a chunk of data each time it is called through the socket. |
updateEncoder | function | Takes a single function argument, and uses the said argument as the new encoder. |
updateDecoder | function | Takes a single function argument, and uses the said argument as the new decoder. |
reset | function | Updates the decoder back to the original, httpCodec.decoder() . |
# TLS Options
Here are the available options and fields for configuring an SSL/TLS connection.
# Acceptable Fields
Field | Type | Description |
---|---|---|
protocol | string | The transport-layer-secure protocol to use. Supported values depends on lua-openssl version, openssl TLS 1.3 compatible supports: TLS (default) or DTLS . LibreSSL and others uses SSLv23 by default and supports other versions. |
ciphers | string | The encryption algorithm to encrypt data with, value MUST be a valid cipher suite string. Defaults are TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256 for TLS 1.3, ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256 for LTS 1.2, RC4:HIGH:!MD5:!aNULL:!EDH for LTS 1.0. |
key | string | The PEM key of the supplied certification (if cert field is passed). |
cert | string | The SSL/TLS x509 certification used for the handshake as string. Used alongside with field key or it gets ignored. |
ca | string/table | The x509 root certificates to check the connection against. Defaults to a root certification (root_ca.dat file) when available. |
insecure | boolean | Weather or not to accept invalid certificates on handshakes. Please only tinker with this when you do know what it means. default: false . |
All of the fields are optional and should only be touched when you know what you are dealing with.
# Parsed URL
A parsed URL is often returned by parseUrl as a table that represents an HTTP(s) URL.
# Available Fields
Fields | Type | Description |
---|---|---|
tls | boolean | Whether or not the parsed URL uses TLS/SSL (HTTPS). |
host | string | The authority of the parsed URL (hostname:port). |
hostname | string | The host name of the parsed URL (hostname only). |
port | number | The host port of the parsed URL if supplied(defaults to 80 for HTTP and 443 for HTTPS). |
path | string | Everything following the host of the parsed URL (including first / ) |
# Timeout
A numerical value in milliseconds that indicates how much time to wait for the response/request before canceling it out. If nothing is supplied libuv will timeout after an undefined amount of seconds.
Examples:
1000
, waits for a one second.500
, waits for half of a second.
# Request Options
A table that could configure some of Request behavior.
# Structure
Full:
{
timeout = (number),
followRedirects = (boolean)
}
- Where:
Entry | Type | Description |
---|---|---|
timeout | Timeout | See Timeout for description. |
followRedirects | boolean | whether or not to follow redirect requests. default: true . |