UP | HOME

Doing http requests with gforth and libcurl

Forth is great

Forth is great. Unfortunately most of my colleagues are completely unaware of it or at best think of it as something alien for embedded systems.

I love it, beside of its simplicity and its cleanness, it gives me the feeling of having full power over my system, like in the 8bit ara. Hint: read Jones forth - it is an eye opener! You'll understand forth as a system, not only as a programming languange.

Gforths ffi

There are many different forth-implementation, native (running on a bare metal machine / board) or hosted forth. I like gforth. Some forth enthusiasts call it bloated. Really impressive is its ffi (foreign function interface), which even makes c-callbacks very easy. Coming from common lisp, and it's various ffi's, I was very impressed.

Currently I am coming back to forth, because of programing my wonderful picocalc in zeptoforth.

Simple libcurl bindings for gforth

Following as an example, my very simple implementation of bindings of libcurl to make http requests. I am far from being an forth expert. Actually it was quite a challenge for me to do a simple http-request out of gforth, because I nearly found no example code. How do c-callbacks work, etc?

That's also the reason for me publishing this code, hopefully someone is happy to find this information. Take it with a grain of salt, as mentioned, I am no forth expert.

Make sure, that f.e. libcurl-gnutls is on your system. Code was testet at AMD64 Archlinux and AARCH64 Debian.

\ http-request bindings to libcurl for gforth (>= 0.7.9)

c-library curl
  s" curl-gnutls" add-lib
  \c #include <curl/curl.h>
  \c #include <curl/easy.h>

  c-value curl-global-all CURL_GLOBAL_ALL -- n
  c-value curle-ok CURLE_OK -- n
  c-value curlopt-url CURLOPT_URL -- n
  c-value curlopt-customrequest CURLOPT_CUSTOMREQUEST -- n
  c-value curlopt-writefunction CURLOPT_WRITEFUNCTION -- n
  c-value curlopt-writedata CURLOPT_WRITEDATA -- n
  c-value curlopt-useragent CURLOPT_USERAGENT -- n
  c-value curlinfo-response-code CURLINFO_RESPONSE_CODE -- n
  
  c-function curl-global-init curl_global_init n -- void
  c-function curl-easy-init curl_easy_init void -- a
  c-function curl-easy-setopt curl_easy_setopt a n a -- void
  c-function curl-easy-perform curl_easy_perform a -- a
  c-function curl-easy-getinfo curl_easy_getinfo a n a -- void
  c-function curl-easy-cleanup curl_easy_cleanup a -- void

  c-callback make-receive-request a n n a -- n
end-c-library

: receive-request ( data chunksize nmemb usrptr )
  -rot * swap over >r $+! r> ;

' receive-request make-receive-request constant recv

: >cstring ( addr u -- c-string-addr )
  [ s\" \0" ] 2literal s+ drop ;

s" GET" >cstring constant method-get
s" POST" >cstring constant method-post
s" PUT" >cstring constant method-put
s" DELETE" >cstring constant method-delete
s" PATCH" >cstring constant method-patch

variable curl-data
variable response-code

: http-request ( method url-addr url-len -- status content-addr content-len )
  curl-data $init
  curl-global-all curl-global-init
  curl-easy-init { curl }
  curl 0= if ." CURL initialization failed..." quit then

  >cstring curl curlopt-url rot curl-easy-setopt
  curl curlopt-customrequest rot curl-easy-setopt
  curl curlopt-writefunction recv curl-easy-setopt
  curl curlopt-writedata curl-data curl-easy-setopt

  curl curl-easy-perform
  curle-ok <> if ." CURL perform failed..." quit then

  curl curlinfo-response-code response-code curl-easy-getinfo
  
  curl curl-easy-cleanup
  response-code @
  curl-data $@
  save-mem
  curl-data $free ; \ you'll have to make sure, to free memory on your own!

: my-example ( -- )
  method-get s" https://example.com" http-request
  2dup type
  drop free ;

Date: 2025-10-18 Sat 00:00

Author: Otto Diesenbacher-Reinmüller

Validate