cURL for WebAssembly
v8.22.0WebAssemblycURL 8.22.0 for browsers, Node.js and edge runtimes, precompiled for wasm32, single-threaded and multi-threaded as @crossbind/port-curl-wasm.
Install
crossbind itself arrives with your bundler plugin, or with a new project from npm create crossbind@beta; Bundlers has Vite, Webpack, Rspack and Rollup.
Usage
Each example runs here, in this tab, and prints what the site build checked.
Each example also has a JavaScript only tab: the same task with no C++ file, calling cURL's own headers from @crossbind/port-curl directly. All 5 work that way.
Parse a URL the way curl will fetch it
libcurl's URL API: curl_url_set checks a URL and removes its dot segments, curl_url_get reads one part back, with CURLU_DEFAULT_PORT and CURLU_URLDECODE when asked, and curl_url_strerror explains a URL curl refuses. The host keeps the case it was written in.
The same curl_url_set and curl_url_get calls, imported from curl/urlapi.h: crossbind binds only what the imported header declares, so curl/curl.h does not bring the URL API. curl_url_get writes a char * into an allocPointer(1) slot, which JavaScript reads with readPointerAt and readCString and frees with curl_free; the CURLU_* flags are #defines the binding leaves out, so they are written as numbers. A failure is the returned CURLUcode, turned into text by curl_url_strerror, so the last line has no std::runtime_error: prefix.
Build a URL from parts without breaking it
curl_url_set with CURLU_APPENDQUERY and CURLU_URLENCODE adds a query pair with its value escaped, CURLU_URLENCODE on the path escapes a file name, and a relative reference set on a URL is resolved the way curl follows a redirect.
The same curl_url_set calls with the same flags, written as numbers because CURLU_APPENDQUERY and CURLU_URLENCODE are #defines the binding leaves out. One handle holds the URL and curl_url_dup copies it before the redirect is resolved; reading the result back is the allocPointer, readPointerAt, readCString and curl_free sequence of the previous example.
Percent-encode and decode text
curl_easy_escape encodes every byte except letters, digits and - . _ ~, the encoding the curl tool's --data-urlencode and --url-query use. JavaScript's encodeURIComponent leaves ( ) ! * ' alone. curl_easy_unescape decodes %XX only: + stays +, and a % that starts no valid sequence is kept.
Both functions return a char * that JavaScript reads with readCString and frees with curl_free, and they take null for the handle as the C++ does. The length arguments count bytes, so they are 0 here and curl measures the UTF-8 text itself: text.length counts UTF-16 units and cuts crème brûlée & tea (50%) three bytes short. readCString stops at the first zero byte, so a decoded %00 ends the text; to read past it, pass an allocBuffer(4) handle as the int * length and read that many bytes with readBytes, one character per byte.
Read the dates in HTTP headers
curl_getdate reads the three date formats HTTP allows, and variations such as zone names, as seconds since 1970 in UTC. A date without a zone is GMT, where JavaScript's Date.parse takes local time, and ISO 8601 is not a format it reads.
curl_getdate returns a time_t, 64 bits in this build, so the seconds arrive as a BigInt, and as -1n when curl cannot read the text as a date. JavaScript's Date writes the ISO form the C++ made with gmtime_r and strftime.
Check what this libcurl was built with
curl_version_info lists the protocols and features compiled in, so code can check before relying on one. This is the WebAssembly build: no HTTP/2, no compression, no IDN and no IPv6. Its protocols are compiled in, but in a browser a transfer goes through fetch, so only HTTP and HTTPS leave the page. The Android and iOS packages report the same protocols, plus libz.
curl_version returns a char *, read with readCString and not freed: it points at a static buffer. curl_version_info_data crosses with its number fields only, so the protocols and feature_names lists never reach JavaScript: the protocols here are the schemes libcurl 8.22.0 knows that the URL API accepts (the rest return CURLUE_UNSUPPORTED_SCHEME), and the features are the features bitmask decoded with the CURL_VERSION_* bits from curl.h. A feature without a bit, such as HTTPSRR or SSLS-EXPORT, cannot be seen this way.
What is different on WebAssembly
- In a browser the module runs in a Worker by default (
useWorker), so every call returns a promise:awaitcalls and constructors alike. - The module has its own filesystem:
m.FSwrites files,m.getFileBytesreads them back andm.autoMountFilesmountsFileobjects from an<input type=file>./memfslives in memory;/opfspersists across reloads and needs the Worker. See Filesystem. - In Node.js,
m.FSis the real disk, so use real paths there. - Multi-threaded builds (
runtime: 'mt') need COOP and COEP headers in production. See Threading.
Other platforms
- cURL overview: the apps, every platform's setup and the packages.
- cURL for Android: React Native apps on Android.
- cURL for iOS: React Native apps on iOS.
- cURL for WASI: command-line programs under wasmtime.
Facts on this page come from the port manifests in the repository and from what npm served on beta when the site was built. See the Libraries guide for the full consumer flow.