• Re: making http request with gforth

    From okflo@okflo@teletyp.ist to comp.lang.forth on Sat Oct 18 20:34:59 2025
    From Newsgroup: comp.lang.forth

    okflo@teletyp.ist writes:

    hi forthers,

    I am trying to do a (very simple and naive) http-request
    with gforth (current from git):
    [...]

    Hi,

    following up to my own post, I did nearly a year ago:

    Some days ago I came back to forth and finally grasped the ffi of
    gforth. Great stuff - especially the simple way to make c-callbacks!

    Gforth's documentation doesn't include any example, so - perhaps my implementation, see below, helps someone else. See also at https://teletyp.ist/blog/entries/Doing-http-requests-with-gforth-and-libcurl.html
    for web-reference.

    Let me also address some questions to the experienced forthers:

    - I use global variables (in the dictionary) for curl-data and
    response-code. What would be the right way to do this locally in
    http-request? The usual locals are on a stack IMHO - so I would need
    to allocate cells?
    - What is the best way, to convert an sstring to a cstring? I was
    wondering, that there is a cstring>sstring in gforth, but not the
    other way sstring>cstring?
    - Please raise any other detail, I did wrong! ;)

    best regards & many thanks for any hints in advance - okflo

    #+begin_src forth
    \ 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 ;
    #+end_src
    --- Synchronet 3.21a-Linux NewsLink 1.2