/* ading2210/libcurl.js - A port of libcurl to WASM for the browser. Copyright (C) 2023 ading2210 This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ //everything is wrapped in a function to prevent emscripten from polluting the global scope const libcurl = (function() { //emscripten compiled code is inserted here /* __emscripten_output__ */ //extra client code goes here /* __extra_libraries__ */ var websocket_url = null; var wasm_ready = false; var version_dict = null; var api = null; var main_session = null; const libcurl_version = "__library_version__"; const wisp_version = "__wisp_version__"; function check_loaded(check_websocket) { if (!wasm_ready) { throw new Error("wasm not loaded yet, please call libcurl.load_wasm first"); } if (!websocket_url && check_websocket) { throw new Error("websocket proxy url not set, please call libcurl.set_websocket"); } } //wrap perform_request in a promise function perform_request_async(url, params, body) { return new Promise((resolve, reject) => { let stream_controller; let http_handle; let response_obj; let aborted = false; //handle abort signals if (params.signal instanceof AbortSignal) { params.signal.addEventListener("abort", () => { if (aborted) return; aborted = true; _cleanup_handle(http_handle); if (!response_obj) { reject(new DOMException("The operation was aborted.")); } else { stream_controller.error("The operation was aborted."); } }); } let stream = new ReadableStream({ start(controller) { stream_controller = controller; } }); function data_callback(new_data) { try { stream_controller.enqueue(new_data); } catch (e) { //the readable stream has been closed elsewhere, so cancel the request if (e instanceof TypeError) { _cleanup_handle(http_handle); } else { throw e; } } } function headers_callback() { let response_json = c_func_str(_http_get_info, [http_handle]); response_obj = create_response(stream, JSON.parse(response_json)); resolve(response_obj); } function finish_callback(error) { if (error != 0) { error_msg(`Request "${url}" failed with error code ${error}: ${get_error_str(error)}`); reject(`Request failed with error code ${error}: ${get_error_str(error)}`); return; } try { stream_controller.close(); } //this will only fail if the stream is already errored or closed, which isn't a problem catch {} } let body_length = body ? body.length : 0; let params_json = JSON.stringify(params); http_handle = create_request(url, data_callback, finish_callback, headers_callback); c_func(_http_set_options, [http_handle, params_json, body, body_length]); start_request(http_handle); }); } async function libcurl_fetch(url, params={}) { check_loaded(true); let body = await create_options(params); return await perform_request_async(url, params, body); } function set_websocket_url(url) { websocket_url = url; if (Module.websocket) { Module.websocket.url = url; } } function get_version() { if (!wasm_ready) return null; if (version_dict) return version_dict; let version_ptr = _get_version(); let version_str = UTF8ToString(version_ptr); _free(version_ptr); version_dict = JSON.parse(version_str); version_dict.lib = libcurl_version; version_dict.wisp = wisp_version; return version_dict; } function get_cacert() { return UTF8ToString(_get_cacert()); } function main() { wasm_ready = true; _init_curl(); set_websocket_url(websocket_url); if (ENVIRONMENT_IS_WEB) { let load_event = new Event("libcurl_load"); document.dispatchEvent(load_event); } main_session = new HTTPSession(); api.fetch = main_session.fetch.bind(main_session); api.onload(); } function load_wasm(url) { wasmBinaryFile = url; createWasm(); run(); } Module.onRuntimeInitialized = main; api = { set_websocket: set_websocket_url, load_wasm: load_wasm, get_cacert: get_cacert, get_error_string: get_error_str, wisp_connections: _wisp_connections, WispConnection: WispConnection, transport: "wisp", WebSocket: WebSocket, CurlWebSocket: CurlWebSocket, TLSSocket: TLSSocket, fetch: () => {throw "not ready"}, get copyright() {return copyright_notice}, get version() {return get_version()}, get ready() {return wasm_ready}, get websocket_url() {return websocket_url}, get stdout() {return out}, set stdout(callback) {out = callback}, get stderr() {return err}, set stderr(callback) {err = callback}, get logger() {return logger}, set logger(func) {logger = func}, onload() {} }; return api; })()