summaryrefslogtreecommitdiff
path: root/internal/curl
diff options
context:
space:
mode:
Diffstat (limited to 'internal/curl')
-rw-r--r--internal/curl/README1
-rw-r--r--internal/curl/ccurl/ccurl.ha47
-rw-r--r--internal/curl/curl.ha74
3 files changed, 122 insertions, 0 deletions
diff --git a/internal/curl/README b/internal/curl/README
new file mode 100644
index 0000000..8c56760
--- /dev/null
+++ b/internal/curl/README
@@ -0,0 +1 @@
+Basic hare bindings for libcurl's C API. Must be compiled with hare build $(pkg-config --libs-only-L --libs-only-l libcurl) ... to add the proper linker flags.
diff --git a/internal/curl/ccurl/ccurl.ha b/internal/curl/ccurl/ccurl.ha
new file mode 100644
index 0000000..3e44d97
--- /dev/null
+++ b/internal/curl/ccurl/ccurl.ha
@@ -0,0 +1,47 @@
+use types::c;
+
+export type CURL = opaque;
+export type CURLcode = int;
+export type CURLINFO = int;
+
+export def CURLOPT_URL = 10002;
+export def CURLOPT_WRITEFUNCTION = 20011;
+export def CURLOPT_WRITEDATA = 10001;
+
+export def CURLINFO_LONG = 0x200000;
+export def CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2;
+
+export @symbol("curl_easy_init") fn curl_easy_init() nullable *CURL;
+export @symbol("curl_easy_cleanup") fn curl_easy_cleanup(handle: nullable *CURL) void;
+
+export type write_callback = fn(ptr: *c::char, sz: c::ssize, nmemb: c::ssize, userdata: *opaque) c::ssize;
+export @symbol("curl_easy_setopt") fn curl_easy_setopt(
+ handle: nullable *CURL,
+ option: int,
+ parameter: const *c::char,
+) CURLcode;
+
+export @symbol("curl_easy_setopt") fn curl_easy_setopt_writefunction(
+ handle: nullable *CURL,
+ option: int,
+ parameter: *write_callback,
+) CURLcode;
+
+export @symbol("curl_easy_setopt") fn curl_easy_setopt_writedata(
+ handle: nullable *CURL,
+ option: int,
+ parameter: *opaque,
+) CURLcode;
+
+//export @symbol("curl_easy_setopt") fn curl_easy_setopt(
+// handle: nullable *CURL,
+// option: int,
+// parameter: (const *c::char | nullable opaque)
+//) CURLcode;
+
+export @symbol("curl_easy_perform") fn curl_easy_perform(easy_handle: nullable *CURL) CURLcode;
+export @symbol("curl_easy_getinfo") fn curl_easy_getinfo(
+ easy_handle: nullable *CURL,
+ info: CURLINFO,
+ code: nullable *c::long
+) CURLcode;
diff --git a/internal/curl/curl.ha b/internal/curl/curl.ha
new file mode 100644
index 0000000..148164a
--- /dev/null
+++ b/internal/curl/curl.ha
@@ -0,0 +1,74 @@
+use types::c;
+use fmt;
+use os;
+use memio;
+use strings;
+use io;
+use internal::curl::ccurl;
+
+export type curlerror = !(setopterr | performerr | getinfoerr);
+
+export type setopterr = !int;
+export type performerr = !int;
+export type getinfoerr = !int;
+
+// A HTTP response
+export type response = struct {
+ // Body
+ data: memio::stream,
+ // HTTP status
+ status: i64,
+ // Size of the body
+ sz: i64,
+};
+
+// Creates a response and returns it. Caller must call [[closeresponse]] to
+// close the underlying stream.
+export fn newresponse() response = {
+ return response {
+ data = memio::dynamic(),
+ status = 0,
+ sz = 0,
+ };
+};
+
+// Closes the stream associated to the response created by [[newresponse]].
+export fn closeresponse(resp: response) (void | io::error) = {
+ io::close(&resp.data)?;
+};
+
+fn cb(ptr: *c::char, sz: c::ssize, nmemb: c::ssize, userdata: *opaque) c::ssize = {
+ let s = c::tostr(ptr)!;
+ //fmt::printfln("FOOKL: {}", s)!;
+ let resp = userdata: *response;
+ let realsize = nmemb * sz;
+ let b = strings::toutf8(s);
+ memio::concat(&resp.data, strings::fromutf8_unsafe(b[..realsize]))!;
+ resp.sz += sz * nmemb;
+ return sz * nmemb;
+};
+
+// Makes a HTTP request to the given url and fills resp with the body, HTTP
+// status and body size.
+export fn get(url: const str, resp: *response) (void | curlerror) = {
+ let c = ccurl::curl_easy_init();
+ defer ccurl::curl_easy_cleanup(c);
+ let c_url = c::fromstr(url);
+ defer free(c_url);
+ let res = ccurl::curl_easy_setopt(c, ccurl::CURLOPT_URL, c_url);
+ if (res != 0) {
+ return res: setopterr;
+ };
+ res = ccurl::curl_easy_setopt_writefunction(c, ccurl::CURLOPT_WRITEFUNCTION, &cb);
+ res = ccurl::curl_easy_setopt_writedata(c, ccurl::CURLOPT_WRITEDATA, resp);
+ res = ccurl::curl_easy_perform(c);
+ if (res != 0) {
+ return res: performerr;
+ };
+ let rc: c::long = 0;
+ res = ccurl::curl_easy_getinfo(c, ccurl::CURLINFO_RESPONSE_CODE, &rc);
+ if (res != 0) {
+ return res: getinfoerr;
+ };
+ resp.status = rc;
+};