curl
 
Free and easy-to-use client-side URL transfer library supporting almost every protocol.

Website: https://curl.se/libcurl/
Platforms supported: Windows (32-bit and 64-bit), Linux, macOS, FreeBSD, Haiku
Headers to include: curl.bi
Header version: 7.85.0
Examples: in examples/network/curl/

Haiku R1 beta 6 amd64: `examples/manual/libraries/curl.bas` compiled and ran
with FreeBASIC 1.20.4-3 against HaikuPorts libcurl 8.22.0, fetching and
checking the exact response from a local loopback HTTP fixture.

The declarations describe libcurl 7.85.0. The Windows qualification uses the installed 32-bit and 64-bit libcurl 8.21.0 SDKs and compares stable C types and form-list layouts with the native C headers. This does not add newer APIs to curl.bi. The HTTP fixtures test loopback transfers; they do not establish HTTPS certificate or public-server interoperability.

The example accepts a URL as its first command-line argument. It prints the exact callback bytes, including embedded zeros, without adding a newline for each callback. It checks option and transfer errors, returns a failing process status for HTTP and transport errors, and balances global initialization and easy-handle cleanup. Its connection deadline is five seconds and its complete transfer deadline is fifteen seconds. CURLOPT_* options which take C long must receive a Clong argument in varargs on 64-bit Windows.

The CHttp examples build a static library from CHttp.bas, CHttpStream.bas and CHttpForm.bas before linking test.bas. Each connection owns its easy handle and header list. A stream with a supplied connection borrows it, so that connection must outlive the stream. These owning example objects are used synchronously on one thread and must not be copied.

CHttpStream.read(TRUE) returns exactly the response body, without the internal C terminator; a text read stops at the first zero. send() uploads the caller's bytes synchronously using CURLOPT_UPLOAD (PUT for HTTP), including an empty body. It keeps response storage separate from the borrowed upload buffer and supplies a seek callback so a redirected upload can be rewound. It removes stack-backed read and seek userdata before returning. read() can retrieve the upload response. Transfer failures clear partial response data. The wrapper treats HTTP status policy as a caller option; the standalone manual example enables CURLOPT_FAILONERROR.

CHttpForm retains the original curl_formadd multipart interface, which libcurl has deprecated in favor of the MIME API. It remains an example of that original binding, and should be linked against a libcurl build which still exposes it.

See the libcurl write callback, upload, seek callback, and global initialization references for the underlying API contracts.

Example

'' FreeBASIC manual examples
'' File: curl.bas
'' Purpose: Fetch a URL with libcurl's easy interface.
'' Responsibilities: Preserve callback bytes, report errors, and release curl state.
'' This file contains no redirects, retries or asynchronous transfers.
'' See Also: https://www.freebasic.net/wiki/wikka.php?wakka=ExtLibcurl

#include Once "curl.bi"
#include Once "crt/string.bi"

'' libcurl supplies a byte count, not a terminated string. A FreeBASIC STRING
'' preserves embedded zeros; the semicolon avoids adding callback-dependent
'' newlines. The temporary chunk belongs to this synchronous callback only.
Private Function write_callback cdecl ( ByVal buffer As Byte Ptr, _
                                        ByVal size As size_t, _
                                        ByVal nitems As size_t, _
                                        ByVal userdata As Any Ptr ) As size_t
    Dim maximum As size_t = Cast( size_t, -1 )
    If( size <> 0 AndAlso nitems > maximum \ size ) Then Return 0
    Dim bytes As size_t = size * nitems
    If( bytes > (maximum Shr 1) ) Then Return 0
    If( bytes <> 0 AndAlso buffer = NULL ) Then Return 0
    Dim chunk As String = Space( bytes )
    If( Len( chunk ) <> bytes ) Then Return 0
    If( bytes <> 0 ) Then memcpy( StrPtr( chunk ), buffer, bytes )
    Print chunk;
    Return bytes
End Function

Function main() As Integer
    Dim url As String = Command(1)
    If( Len( url ) = 0 ) Then url = "https://freebasic.net/"
    If( curl_global_init( CURL_GLOBAL_ALL ) <> CURLE_OK ) Then Return 1
    Dim handle As CURL Ptr = curl_easy_init( )
    If( handle = NULL ) Then
        curl_global_cleanup( )
        Return 1
    End If

    '' Long options use C long in varargs, including on 64-bit Windows.
    '' Bound the wait to five seconds for connection and fifteen in total.
    Dim As clong connect_timeout = 5000, total_timeout = 15000, fail_http = 1
    Dim result As CURLcode = CURLE_FAILED_INIT
    Do
        If( curl_easy_setopt( handle, CURLOPT_URL, StrPtr( url ) ) <> CURLE_OK ) Then Exit Do
        If( curl_easy_setopt( handle, CURLOPT_WRITEFUNCTION, @write_callback ) <> CURLE_OK ) Then Exit Do
        If( curl_easy_setopt( handle, CURLOPT_CONNECTTIMEOUT_MS, connect_timeout ) <> CURLE_OK ) Then Exit Do
        If( curl_easy_setopt( handle, CURLOPT_TIMEOUT_MS, total_timeout ) <> CURLE_OK ) Then Exit Do
        If( curl_easy_setopt( handle, CURLOPT_FAILONERROR, fail_http ) <> CURLE_OK ) Then Exit Do
        result = curl_easy_perform( handle )
    Loop While False

    If( result <> CURLE_OK ) Then Print "curl transfer failed: "; *curl_easy_strerror( result )
    curl_easy_cleanup( handle )
    curl_global_cleanup( )
    If( result <> CURLE_OK ) Then Return 1
    Return 0
End Function

End main()

'' end of curl.bas