\startluacode
local ffi = assert(require("ffi"))

-- Definition copied straight from curl.h
ffi.cdef[[
typedef struct Curl_easy CURL;
typedef int CURLcode;
typedef int CURLoption;
typedef int CURLINFO;
typedef size_t(*callback)(void *buffer, size_t size, size_t nmemb, void *userp);

CURLcode curl_global_init(long flags);
CURL *curl_easy_init(void);
CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
CURLcode curl_easy_perform(CURL *curl);
CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
void curl_easy_cleanup(CURL *curl);
void curl_global_cleanup(void);
]]

-- Magic numbers
-- for more complex applications one should copy the full enums
-- CURLcode, CURLoption, and CURLINFO into ffi.cdef
local CURLE_OK = 0
local CURL_GLOBAL_DEFAULT = 3
local CURLOPT_URL = 10002
local CURLOPT_NOBODY = 44
local CURLOPT_HEADER = 42
local CURLOPT_WRITEFUNCTION = 20011
local CURLINFO_RESPONSE_CODE = 0x200000 + 2

local lcurl = assert(ffi.load("curl"))

-- Callback function for data received by the request
local function discard(buffer, size, nmemb, userp)
    return size * nmemb
end

-- Initialize the curl session
lcurl.curl_global_init(CURL_GLOBAL_DEFAULT)
-- Make the cleanup function available globally so we can call it when
-- ConTeXt is done
curl_global_cleanup = lcurl.curl_global_cleanup

function curl_check_status(url)
    -- Start a libcurl easy session
    local curl = assert(lcurl.curl_easy_init())

    -- URL to work on
    assert(CURLE_OK == lcurl.curl_easy_setopt(curl, CURLOPT_URL, url))
    -- Do not get the body contents
    assert(CURLE_OK == lcurl.curl_easy_setopt(curl, CURLOPT_NOBODY, ffi.cast("long",1)))
    -- Include the header in the body output
    assert(CURLE_OK == lcurl.curl_easy_setopt(curl, CURLOPT_HEADER, ffi.cast("long",1)))
    -- Callback for writing data
    assert(CURLE_OK == lcurl.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ffi.cast("callback",discard)))

    -- perform a blocking file transfer
    assert(CURLE_OK == lcurl.curl_easy_perform(curl))

    -- extract last received response code from a curl handle
    local c_http_code = ffi.new("long[1]")
    assert(CURLE_OK == lcurl.curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, c_http_code))

    -- End a libcurl easy handle
    lcurl.curl_easy_cleanup(curl)

    -- Convert C long* to Lua number
    return tonumber(c_http_code[0])
end
\stopluacode

\appendtoks
    \ctxlua{curl_global_cleanup()}
\to \everystoptext

\starttext

HTTP: \ctxlua{context(curl_check_status("http://example.com/"))}

HTTPS: \ctxlua{context(curl_check_status("https://example.com/"))}

404: \ctxlua{context(curl_check_status("https://example.com/xyz"))}

\stoptext
