remove curl and openssl dependencies
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Successful in 1m44s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped

This commit is contained in:
2025-05-24 00:07:37 -05:00
parent f754d91e14
commit 1248b94244
6 changed files with 394 additions and 321 deletions

View File

@@ -65,6 +65,22 @@ endif
cmake = import('cmake')
mbedtls_opts = cmake.subproject_options()
mbedtls_opts.add_cmake_defines({
'ENABLE_PROGRAMS': 'OFF', # Disable Mbed TLS programs
'ENABLE_TESTING': 'OFF', # Disable Mbed TLS tests
'CMAKE_BUILD_TYPE': 'Release', # Optimize for release
'MBEDTLS_FATAL_WARNINGS': 'ON', # Treat warnings as errors
'USE_STATIC_MBEDTLS_LIBRARY': 'ON',# Build static libraries
'USE_SHARED_MBEDTLS_LIBRARY': 'OFF'# Disable shared libraries
})
mbedtls_proj = cmake.subproject('mbedtls', options: mbedtls_opts)
deps += [
mbedtls_proj.dependency('mbedtls'),
mbedtls_proj.dependency('mbedx509'),
mbedtls_proj.dependency('mbedcrypto')
]
sdl3_opts = cmake.subproject_options()
sdl3_opts.add_cmake_defines({
'SDL_STATIC': 'ON',
@@ -116,7 +132,6 @@ else
deps += sdl3_proj.dependency('SDL3-static')
endif
quickjs_opts = []
quickjs_opts += 'default_library=static'
@@ -156,76 +171,6 @@ src += [
'thirdparty/quirc/identify.c', 'thirdparty/quirc/version_db.c'
]
curl_opts = [
'http=enabled',
'ssl=enabled',
'openssl=enabled',
'schannel=disabled',
'secure-transport=disabled',
'dict=disabled',
'file=disabled',
'ftp=disabled',
'gopher=disabled',
'imap=disabled',
'ldap=disabled',
'ldaps=disabled',
'mqtt=disabled',
'pop3=disabled',
'rtmp=disabled',
'rtsp=disabled',
'smb=disabled',
'smtp=disabled',
'telnet=disabled',
'tftp=disabled',
'alt-svc=disabled',
'asynchdns=disabled',
'aws=disabled',
'basic-auth=disabled',
'bearer-auth=disabled',
'bindlocal=disabled',
'brotli=disabled',
'cookies=disabled',
'digest-auth=disabled',
'doh=disabled',
'form-api=disabled',
'getoptions=disabled',
'gsasl=disabled',
'gss-api=disabled',
'headers-api=disabled',
'hsts=disabled',
'http2=disabled',
'idn=disabled',
'kerberos-auth=disabled',
'libcurl-option=disabled',
'libz=disabled',
'mime=disabled',
'negotiate-auth=disabled',
'netrc=disabled',
'ntlm=disabled',
'parsedate=disabled',
'progress-meter=disabled',
'proxy=disabled',
'psl=disabled',
'sha512_256=disabled',
'shuffle-dns=disabled',
'socketpair=disabled',
'tls-srp=disabled',
'unixsockets=disabled',
'verbose-strings=disabled',
'zstd=disabled',
'debug=disabled',
'curldebug=false',
'libuv=disabled',
'tests=disabled',
'unittests=disabled',
'default_library=static'
]
curl_proj = subproject('curl', default_options: curl_opts)
deps += dependency('libcurl')
deps += dependency('zlib', static: true)
deps += dependency('openssl', static:true)
imsrc = [
'GraphEditor.cpp','ImCurveEdit.cpp','ImGradient.cpp','imgui_draw.cpp',
'imgui_tables.cpp','imgui_widgets.cpp','imgui.cpp','ImGuizmo.cpp','imnodes.cpp',

View File

@@ -15,12 +15,4 @@ This function enqueues an HTTP GET request for the specified URL. It supports bo
- An error if memory allocation or CURL initialization fails.
`
http.poll[prosperon.DOC] = `Process pending HTTP requests and invoke callbacks.
This function checks for I/O activity on all enqueued HTTP requests and processes any that have completed or received data. For completed requests, it invokes the 'callback' function (if provided) with the result. For streaming requests, it invokes the 'data' function (if provided) as data arrives. This function must be called repeatedly to drive the asynchronous request system.
:return: undefined
:throws: An error if CURL multi-handle processing fails.
`
return http

View File

@@ -1,269 +1,368 @@
#include "quickjs.h"
#include <curl/curl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/error.h>
// -----------------------------------------------------------------------------
// HTTP request structure
// -----------------------------------------------------------------------------
typedef struct {
char url[512]; // URL for the request
JSContext *ctx; // JS context for callbacks
JSValue callback; // Completion callback (optional)
JSValue on_data; // Streaming data callback (optional)
char *response; // Buffer for non-streaming mode
size_t size; // Size of response buffer
CURL *curl; // CURL easy handle
int done; // Request completion flag
int curl_result; // CURL result code
} HttpRequest;
char *data;
size_t size;
size_t capacity;
} buffer_t;
// -----------------------------------------------------------------------------
// Global data
// -----------------------------------------------------------------------------
static CURLM *g_curl_multi = NULL; // CURL multi-handle for async I/O
// -----------------------------------------------------------------------------
// Libcurl write callback for streaming or buffering
// -----------------------------------------------------------------------------
static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
HttpRequest *req = (HttpRequest *)userp;
// Streaming mode: call onData if provided
if (JS_IsFunction(req->ctx, req->on_data)) {
JSValue chunk = JS_NewStringLen(req->ctx, contents, realsize);
JSValue ret = JS_Call(req->ctx, req->on_data, JS_UNDEFINED, 1, &chunk);
JS_FreeValue(req->ctx, chunk);
JS_FreeValue(req->ctx, ret); // Ignore return value
return realsize;
}
// Non-streaming mode: buffer the response
char *ptr = realloc(req->response, req->size + realsize + 1);
if (!ptr) {
return 0; // Out of memory, tell CURL to abort
}
req->response = ptr;
memcpy(&(req->response[req->size]), contents, realsize);
req->size += realsize;
req->response[req->size] = '\0'; // Null-terminate
return realsize;
static void buffer_init(buffer_t *buf) {
buf->data = NULL;
buf->size = 0;
buf->capacity = 0;
}
// -----------------------------------------------------------------------------
// JS function: http.fetch(url, options)
// - Enqueues an async HTTP request with optional streaming
// -----------------------------------------------------------------------------
static JSValue js_http_fetch(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (argc < 2 || !JS_IsString(argv[0])) {
return JS_ThrowTypeError(ctx, "fetch expects a URL string and an options object or callback");
static int buffer_append(buffer_t *buf, const void *data, size_t len) {
if (buf->size + len > buf->capacity) {
size_t new_capacity = buf->capacity ? buf->capacity * 2 : 4096;
while (new_capacity < buf->size + len) {
new_capacity *= 2;
}
char *new_data = realloc(buf->data, new_capacity);
if (!new_data) return -1;
buf->data = new_data;
buf->capacity = new_capacity;
}
memcpy(buf->data + buf->size, data, len);
buf->size += len;
return 0;
}
static void buffer_free(buffer_t *buf) {
free(buf->data);
buf->data = NULL;
buf->size = 0;
buf->capacity = 0;
}
// Parse URL into components
static int parse_url(const char *url, char **host, char **port, char **path, int *use_ssl) {
*host = NULL;
*port = NULL;
*path = NULL;
*use_ssl = 0;
const char *p = url;
// Parse scheme
if (strncmp(p, "https://", 8) == 0) {
*use_ssl = 1;
p += 8;
} else if (strncmp(p, "http://", 7) == 0) {
*use_ssl = 0;
p += 7;
} else {
return -1; // Invalid scheme
}
// Find host end
const char *host_start = p;
const char *host_end = strchr(p, '/');
const char *port_start = strchr(p, ':');
if (port_start && (!host_end || port_start < host_end)) {
// Has explicit port
*host = strndup(host_start, port_start - host_start);
port_start++;
if (host_end) {
*port = strndup(port_start, host_end - port_start);
} else {
*port = strdup(port_start);
}
} else {
// No explicit port
if (host_end) {
*host = strndup(host_start, host_end - host_start);
} else {
*host = strdup(host_start);
}
*port = strdup(*use_ssl ? "443" : "80");
}
// Path
if (host_end) {
*path = strdup(host_end);
} else {
*path = strdup("/");
}
return 0;
}
// Perform HTTP request over plain socket
static int http_request(const char *host, const char *port, const char *request, size_t request_len, buffer_t *response) {
mbedtls_net_context server_fd;
int ret;
mbedtls_net_init(&server_fd);
// Connect to server
if ((ret = mbedtls_net_connect(&server_fd, host, port, MBEDTLS_NET_PROTO_TCP)) != 0) {
mbedtls_net_free(&server_fd);
return ret;
}
// Send request
size_t written = 0;
while (written < request_len) {
ret = mbedtls_net_send(&server_fd, (unsigned char *)request + written, request_len - written);
if (ret < 0) {
mbedtls_net_free(&server_fd);
return ret;
}
written += ret;
}
// Read response
unsigned char buf[4096];
do {
ret = mbedtls_net_recv(&server_fd, buf, sizeof(buf));
if (ret > 0) {
if (buffer_append(response, buf, ret) < 0) {
mbedtls_net_free(&server_fd);
return -1;
}
}
} while (ret > 0);
mbedtls_net_free(&server_fd);
return (ret == 0 || ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) ? 0 : ret;
}
// Perform HTTPS request over SSL
static int https_request(const char *host, const char *port, const char *request, size_t request_len, buffer_t *response) {
mbedtls_net_context server_fd;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
const char *pers = "qjs_https_client";
int ret;
// Initialize structures
mbedtls_net_init(&server_fd);
mbedtls_ssl_init(&ssl);
mbedtls_ssl_config_init(&conf);
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
// Seed RNG
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)pers, strlen(pers))) != 0) {
goto exit;
}
// Connect to server
if ((ret = mbedtls_net_connect(&server_fd, host, port, MBEDTLS_NET_PROTO_TCP)) != 0) {
goto exit;
}
// Configure SSL
if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
goto exit;
}
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
goto exit;
}
if ((ret = mbedtls_ssl_set_hostname(&ssl, host)) != 0) {
goto exit;
}
mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
// Handshake
while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
goto exit;
}
}
// Send request
size_t written = 0;
while (written < request_len) {
ret = mbedtls_ssl_write(&ssl, (const unsigned char *)request + written, request_len - written);
if (ret < 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_WANT_READ) {
goto exit;
}
} else {
written += ret;
}
}
// Read response
unsigned char buf[4096];
do {
ret = mbedtls_ssl_read(&ssl, buf, sizeof(buf));
if (ret > 0) {
if (buffer_append(response, buf, ret) < 0) {
ret = -1;
goto exit;
}
}
} while (ret > 0);
if (ret < 0 && ret != MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY &&
ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
goto exit;
}
ret = 0;
exit:
mbedtls_ssl_close_notify(&ssl);
mbedtls_net_free(&server_fd);
mbedtls_ssl_free(&ssl);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return ret;
}
// Extract body from HTTP response
static char *extract_body(const char *response, size_t response_len, size_t *body_len) {
const char *body_start = strstr(response, "\r\n\r\n");
if (!body_start) {
return NULL;
}
body_start += 4;
*body_len = response_len - (body_start - response);
return (char *)body_start;
}
// JS function: fetch(url, options)
static JSValue js_fetch(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
if (argc < 1 || !JS_IsString(argv[0])) {
return JS_ThrowTypeError(ctx, "fetch expects a URL string");
}
// Get URL
const char *url = JS_ToCString(ctx, argv[0]);
if (!url) {
return JS_ThrowTypeError(ctx, "Invalid URL");
}
// Allocate request object
HttpRequest *req = calloc(1, sizeof(*req));
if (!req) {
JS_FreeCString(ctx, url);
return JS_ThrowInternalError(ctx, "Failed to allocate memory");
}
strncpy(req->url, url, sizeof(req->url) - 1);
req->ctx = ctx;
req->callback = JS_NULL;
req->on_data = JS_NULL;
char *host = NULL;
char *port = NULL;
char *path = NULL;
int use_ssl = 0;
buffer_t request_buf;
buffer_t response_buf;
JSValue result = JS_EXCEPTION;
// Parse second argument: callback or options object
if (JS_IsFunction(ctx, argv[1])) {
req->callback = JS_DupValue(ctx, argv[1]);
} else if (JS_IsObject(argv[1])) {
JSValue callback = JS_GetPropertyStr(ctx, argv[1], "callback");
JSValue on_data = JS_GetPropertyStr(ctx, argv[1], "on_data");
if (JS_IsFunction(ctx, callback)) {
req->callback = JS_DupValue(ctx, callback);
buffer_init(&request_buf);
buffer_init(&response_buf);
// Parse URL
if (parse_url(url, &host, &port, &path, &use_ssl) < 0) {
JS_FreeCString(ctx, url);
return JS_ThrowTypeError(ctx, "Invalid URL format");
}
if (JS_IsFunction(ctx, on_data)) {
req->on_data = JS_DupValue(ctx, on_data);
// Build request
buffer_append(&request_buf, "GET ", 4);
buffer_append(&request_buf, path, strlen(path));
buffer_append(&request_buf, " HTTP/1.1\r\n", 11);
buffer_append(&request_buf, "Host: ", 6);
buffer_append(&request_buf, host, strlen(host));
buffer_append(&request_buf, "\r\n", 2);
// Add headers from options if provided
if (argc >= 2 && JS_IsObject(argv[1])) {
JSValue headers = JS_GetPropertyStr(ctx, argv[1], "headers");
if (JS_IsObject(headers)) {
JSPropertyEnum *tab;
uint32_t len;
if (JS_GetOwnPropertyNames(ctx, &tab, &len, headers, JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) == 0) {
for (uint32_t i = 0; i < len; i++) {
JSValue key = JS_AtomToString(ctx, tab[i].atom);
JSValue val = JS_GetProperty(ctx, headers, tab[i].atom);
const char *key_str = JS_ToCString(ctx, key);
const char *val_str = JS_ToCString(ctx, val);
if (key_str && val_str) {
buffer_append(&request_buf, key_str, strlen(key_str));
buffer_append(&request_buf, ": ", 2);
buffer_append(&request_buf, val_str, strlen(val_str));
buffer_append(&request_buf, "\r\n", 2);
}
JS_FreeValue(ctx, callback);
JS_FreeValue(ctx, on_data);
JS_FreeCString(ctx, key_str);
JS_FreeCString(ctx, val_str);
JS_FreeValue(ctx, key);
JS_FreeValue(ctx, val);
}
js_free(ctx, tab);
}
}
JS_FreeValue(ctx, headers);
}
buffer_append(&request_buf, "Connection: close\r\n\r\n", 21);
// Perform request
int ret;
if (use_ssl) {
ret = https_request(host, port, request_buf.data, request_buf.size, &response_buf);
} else {
JS_FreeCString(ctx, url);
free(req);
return JS_ThrowTypeError(ctx, "Second argument must be a callback or options object");
ret = http_request(host, port, request_buf.data, request_buf.size, &response_buf);
}
JS_FreeCString(ctx, url);
if (ret == 0 && response_buf.data) {
// Extract body
size_t body_len;
char *body = extract_body(response_buf.data, response_buf.size, &body_len);
// Initialize CURL easy handle
req->curl = curl_easy_init();
if (!req->curl) {
JS_FreeValue(ctx, req->callback);
JS_FreeValue(ctx, req->on_data);
free(req);
return JS_ThrowInternalError(ctx, "Failed to create CURL handle");
}
// Set CURL options
curl_easy_setopt(req->curl, CURLOPT_URL, req->url);
curl_easy_setopt(req->curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(req->curl, CURLOPT_WRITEDATA, req);
curl_easy_setopt(req->curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(req->curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(req->curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(req->curl, CURLOPT_USERAGENT, "prosperon");
curl_easy_setopt(req->curl, CURLOPT_PRIVATE, req);
// Add to multi-handle
if (!g_curl_multi) {
curl_easy_cleanup(req->curl);
JS_FreeValue(ctx, req->callback);
JS_FreeValue(ctx, req->on_data);
free(req);
return JS_ThrowInternalError(ctx, "CURL multi-handle not initialized");
}
CURLMcode mc = curl_multi_add_handle(g_curl_multi, req->curl);
if (mc != CURLM_OK) {
curl_easy_cleanup(req->curl);
JS_FreeValue(ctx, req->callback);
JS_FreeValue(ctx, req->on_data);
free(req);
return JS_ThrowInternalError(ctx, "curl_multi_add_handle failed: %s", curl_multi_strerror(mc));
}
return JS_UNDEFINED;
}
// -----------------------------------------------------------------------------
// JS function: http.poll()
// - Checks for I/O and completed requests, invoking callbacks as needed
// -----------------------------------------------------------------------------
static JSValue js_http_poll(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
if (!g_curl_multi) {
return JS_UNDEFINED;
}
// Perform pending transfers
int still_running = 0;
CURLMcode mc = curl_multi_perform(g_curl_multi, &still_running);
if (mc != CURLM_OK) {
return JS_ThrowInternalError(ctx, "curl_multi_perform failed: %s", curl_multi_strerror(mc));
}
// Check for completed requests
CURLMsg *msg;
int msgq = 0;
while ((msg = curl_multi_info_read(g_curl_multi, &msgq))) {
if (msg->msg == CURLMSG_DONE) {
CURL *easy = msg->easy_handle;
HttpRequest *req = NULL;
curl_easy_getinfo(easy, CURLINFO_PRIVATE, (char **)&req);
char *ct = NULL;
curl_easy_getinfo(easy, CURLINFO_CONTENT_TYPE, &ct);
// Remove from multi-handle
curl_multi_remove_handle(g_curl_multi, easy);
// Mark as done
req->curl_result = msg->data.result;
req->done = 1;
// Call completion callback if provided
if (JS_IsFunction(req->ctx, req->callback)) {
JSValue arg = JS_NewObject(req->ctx);
if (req->curl_result == CURLE_OK) {
JS_SetPropertyStr(req->ctx, arg, "data",
JS_NewArrayBufferCopy(req->ctx, req->response, req->size));
JS_SetPropertyStr(req->ctx, arg, "error", JS_UNDEFINED);
if (ct) JS_SetPropertyStr(req->ctx, arg, "type", JS_NewString(req->ctx, ct));
if (body) {
// Return body as ArrayBuffer
result = JS_NewArrayBufferCopy(ctx, (uint8_t *)body, body_len);
} else {
JS_DefinePropertyValueStr(req->ctx, arg, "data", JS_NULL, JS_PROP_C_W_E);
const char *err_str = curl_easy_strerror(req->curl_result);
JS_DefinePropertyValueStr(req->ctx, arg, "error",
JS_NewString(req->ctx, err_str ? err_str : "Unknown error"),
JS_PROP_C_W_E);
result = JS_ThrowInternalError(ctx, "Failed to parse HTTP response");
}
JSValue ret = JS_Call(req->ctx, req->callback, JS_UNDEFINED, 1, &arg);
JS_FreeValue(req->ctx, arg);
JS_FreeValue(req->ctx, ret);
} else {
char error_buf[256];
mbedtls_strerror(ret, error_buf, sizeof(error_buf));
result = JS_ThrowInternalError(ctx, "Request failed: %s", error_buf);
}
// Cleanup
JS_FreeValue(req->ctx, req->callback);
JS_FreeValue(req->ctx, req->on_data);
curl_easy_cleanup(req->curl);
free(req->response);
free(req);
}
}
JS_FreeCString(ctx, url);
free(host);
free(port);
free(path);
buffer_free(&request_buf);
buffer_free(&response_buf);
return JS_UNDEFINED;
return result;
}
// -----------------------------------------------------------------------------
// Module initialization
// -----------------------------------------------------------------------------
#define countof(a) (sizeof(a)/sizeof(*(a)))
// Module exports
static const JSCFunctionListEntry js_http_funcs[] = {
JS_CFUNC_DEF("fetch", 2, js_http_fetch),
JS_CFUNC_DEF("poll", 0, js_http_poll),
JS_CFUNC_DEF("fetch", 2, js_fetch),
};
JSValue js_http_use(JSContext *ctx)
JSValue js_http_use(JSContext *js)
{
// Initialize CURL globally (once per process)
static int s_curl_init_done = 0;
if (!s_curl_init_done) {
s_curl_init_done = 1;
if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
return JS_ThrowInternalError(ctx, "Failed to initialize CURL");
}
}
// Initialize multi-handle (once per module)
if (!g_curl_multi) {
g_curl_multi = curl_multi_init();
if (!g_curl_multi) {
return JS_ThrowInternalError(ctx, "Failed to initialize CURL multi-handle");
}
}
// Export fetch and poll functions
JSValue export_obj = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, export_obj, js_http_funcs,
sizeof(js_http_funcs) / sizeof(JSCFunctionListEntry));
return export_obj;
}
static int js_http_init(JSContext *ctx, JSModuleDef *m)
{
JS_SetModuleExport(ctx, m, "default", js_http_use(ctx));
return 0;
}
#ifdef JS_SHARED_LIBRARY
#define JS_INIT_MODULE js_init_module
#else
#define JS_INIT_MODULE js_init_module_http
#endif
JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
{
JSModuleDef *m = JS_NewCModule(ctx, module_name, js_http_init);
if (!m) {
return NULL;
}
JS_AddModuleExport(ctx, m, "default");
return m;
JSValue exp = JS_NewObject(js);
JS_SetPropertyFunctionList(js, exp, js_http_funcs, countof(js_http_funcs));
return exp;
}

View File

@@ -193,6 +193,32 @@ JSC_CCALL(os_on,
rt->on_exception = JS_DupValue(js,argv[1]);
)
JSC_CCALL(os_buffer2string,
if (argc < 1) {
return JS_ThrowTypeError(js, "buffer2string expects an ArrayBuffer");
}
size_t len;
uint8_t *buf = JS_GetArrayBuffer(js, &len, argv[0]);
if (!buf) {
return JS_ThrowTypeError(js, "First argument must be an ArrayBuffer");
}
// Create a null-terminated string from the buffer
char *str = js_malloc(js, len + 1);
if (!str) {
return JS_ThrowInternalError(js, "Failed to allocate memory");
}
memcpy(str, buf, len);
str[len] = '\0';
JSValue result = JS_NewString(js, str);
js_free(js, str);
return result;
)
#define JSOBJ_ADD_FIELD(OBJ, STRUCT, FIELD, TYPE) \
JS_SetPropertyStr(js, OBJ, #FIELD, TYPE##2js(js,STRUCT.FIELD));\
@@ -254,6 +280,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, on, 2),
MIST_FUNC_DEF(os, rusage, 0),
MIST_FUNC_DEF(os, mallinfo, 0),
MIST_FUNC_DEF(os, buffer2string, 1),
};
JSValue js_os_use(JSContext *js) {

4
subprojects/mbedtls.wrap Normal file
View File

@@ -0,0 +1,4 @@
[wrap-git]
url = https://github.com/Mbed-TLS/mbedtls.git
revision = v3.6.3.1
depth = 1

6
tests/https.js Normal file
View File

@@ -0,0 +1,6 @@
var http = use('http')
var os = use('os')
var res = http.fetch("https://dictionary.ink/find?word=palm")
console.log(os.buffer2string(res))