Fun API Documentation 0.42.1
The programming language that makes you have fun!
Loading...
Searching...
No Matches
curl.c
Go to the documentation of this file.
1/*
2 * This file is part of the Fun programming language.
3 * https://fun-lang.xyz/
4 *
5 * Copyright 2025 Johannes Findeisen <you@hanez.org>
6 * Licensed under the terms of the Apache-2.0 license.
7 * https://opensource.org/license/apache-2-0
8 */
9
10/**
11 * @file curl.c
12 * @brief libcurl helpers and buffers used by HTTP-related VM opcodes.
13 *
14 * This module centralizes small, concrete libcurl utilities used by VM
15 * opcodes under src/vm/http/*.c (or similar). The opcodes themselves perform
16 * VM stack marshalling and call these helpers for I/O glue. Keeping the
17 * concrete logic here mirrors other extensions (e.g., PCRE2, SQLite) and
18 * allows the opcode code to remain minimal.
19 *
20 * Build-time feature flag:
21 * - The code in this file is compiled only when FUN_WITH_CURL is enabled.
22 * When disabled, curl-related opcodes should be compiled with no-op
23 * fallbacks in their respective files.
24 *
25 * Buffering and ownership model:
26 * - FunCurlBuf is a small growable buffer intended for use with libcurl's
27 * CURLOPT_WRITEFUNCTION callback. The buffer expands with realloc() as data
28 * arrives and is maintained NUL-terminated for convenience when the content
29 * is treated as a C-string. The caller is responsible for allocating and
30 * freeing the FunCurlBuf fields (i.e., initialize { .d=NULL, .n=0 } before
31 * first use and free(b.d) afterwards).
32 *
33 * Callbacks provided:
34 * - fun_curl_write_cb(): appends incoming data to a FunCurlBuf, keeping it
35 * NUL-terminated. Returns the number of bytes handled (sz*nm) on success or
36 * 0 on allocation failure to signal an error to libcurl.
37 * - fun_curl_file_write_cb(): writes incoming data directly to a FILE* passed
38 * via CURLOPT_WRITEDATA. Returns the number of elements written as per
39 * fwrite().
40 *
41 * Error handling:
42 * - The write-to-buffer callback returns 0 on realloc failure, causing libcurl
43 * to abort the transfer and report CURLE_WRITE_ERROR. The file writer relies
44 * on fwrite()'s return value; callers should check the CURLcode after
45 * performing the transfer for final status.
46 *
47 * Thread-safety:
48 * - These helpers themselves are stateless and thread-safe as long as each
49 * CURL easy handle and associated buffers/FILE* are not shared concurrently
50 * across threads without external synchronization.
51 */
52
53/* Ensure libcurl headers and helpers are defined at file scope (not inside vm_run) */
54#ifdef FUN_WITH_CURL
55#include <curl/curl.h>
56
57/**
58 * @brief Simple growable buffer for libcurl write callbacks.
59 *
60 * The buffer grows via realloc as more data arrives. The content is kept
61 * NUL-terminated for convenience so it can be treated as a C-string.
62 *
63 * Usage pattern:
64 * - Initialize: FunCurlBuf b = { .d = NULL, .n = 0 };
65 * - Set CURLOPT_WRITEFUNCTION = fun_curl_write_cb and CURLOPT_WRITEDATA = &b
66 * - After curl_easy_perform(), b.d points to the collected data (length b.n).
67 * - Free with free(b.d) when done.
68 */
69typedef struct {
70 char *d; /**< Data pointer (NUL-terminated). */
71 size_t n; /**< Number of bytes stored (excluding NUL). */
73
74/**
75 * @brief libcurl write callback that appends data to a FunCurlBuf.
76 *
77 * Reallocates the destination buffer as needed and keeps it NUL-terminated.
78 * The buffer must be initialized by the caller with { .d=NULL, .n=0 } prior to
79 * first use.
80 *
81 * @param ptr Pointer to incoming data block provided by libcurl.
82 * @param sz Size of each data element (as provided by libcurl).
83 * @param nm Number of elements in this block (as provided by libcurl).
84 * @param ud User data; must be a FunCurlBuf* (passed via CURLOPT_WRITEDATA).
85 * @return Number of bytes actually handled (sz*nm) on success; 0 on failure to
86 * signal an error to libcurl (which will abort with CURLE_WRITE_ERROR).
87 */
88static size_t fun_curl_write_cb(void *ptr, size_t sz, size_t nm, void *ud) {
89 size_t add = sz * nm;
90 FunCurlBuf *b = (FunCurlBuf *)ud;
91 char *p = (char *)realloc(b->d, b->n + add + 1);
92 if (!p) return 0;
93 memcpy(p + b->n, ptr, add);
94 b->d = p;
95 b->n += add;
96 b->d[b->n] = '\0';
97 return add;
98}
99
100/**
101 * @brief libcurl write callback that writes directly to a FILE*.
102 *
103 * Suitable for large downloads or when incremental flushing to disk is
104 * desired. The FILE* should be opened in binary mode (e.g., "wb").
105 *
106 * @param ptr Pointer to incoming data.
107 * @param sz Size of each element.
108 * @param nm Number of elements.
109 * @param ud User data; must be a FILE* opened for writing in binary mode
110 * (passed via CURLOPT_WRITEDATA).
111 * @return Number of elements written (as returned by fwrite). Returning a
112 * value smaller than nm will signal an error to libcurl.
113 */
114static size_t fun_curl_file_write_cb(void *ptr, size_t sz, size_t nm, void *ud) {
115 FILE *f = (FILE *)ud;
116 return fwrite(ptr, sz, nm, f);
117}
118#endif
static size_t fun_curl_write_cb(void *ptr, size_t sz, size_t nm, void *ud)
libcurl write callback that appends data to a FunCurlBuf.
Definition curl.c:88
static size_t fun_curl_file_write_cb(void *ptr, size_t sz, size_t nm, void *ud)
libcurl write callback that writes directly to a FILE*.
Definition curl.c:114
Simple growable buffer for libcurl write callbacks.
Definition curl.c:69
size_t n
Definition curl.c:71
char * d
Definition curl.c:70