From ca7ed90ffb105f9655157da009ab75fcce910836 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Thu, 26 Mar 2026 15:57:41 -0700 Subject: [PATCH] improve json module --- examples/results.txt | 2 +- include/modules/json.h | 3 + src/esm/loader.c | 2 +- src/modules/fetch.c | 15 +- src/modules/json.c | 316 +++++++++++++++++------------------ src/modules/request.c | 2 +- src/modules/response.c | 58 +++++-- src/modules/server.c | 4 +- src/modules/util.c | 3 +- src/modules/worker_threads.c | 12 +- src/streams/pipes.c | 18 +- 11 files changed, 237 insertions(+), 198 deletions(-) diff --git a/examples/results.txt b/examples/results.txt index 44a37f6..009ffd6 100644 --- a/examples/results.txt +++ b/examples/results.txt @@ -905,7 +905,7 @@ compat-table/es6/misc.Proxy.get.Error.toString.js: OK compat-table/es6/misc.Proxy.get.Function.bind.js: TypeError: bind requires a function compat-table/es6/misc.Proxy.get.HasBinding.js: failed compat-table/es6/misc.Proxy.get.IteratorComplete.js: OK -compat-table/es6/misc.Proxy.get.JSON.stringify.js: failed +compat-table/es6/misc.Proxy.get.JSON.stringify.js: OK compat-table/es6/misc.Proxy.get.Object.assign.js: failed compat-table/es6/misc.Proxy.get.Object.defineProperties.js: failed compat-table/es6/misc.Proxy.get.Promise.resolve.js: failed diff --git a/include/modules/json.h b/include/modules/json.h index a937527..42c8cf1 100644 --- a/include/modules/json.h +++ b/include/modules/json.h @@ -9,4 +9,7 @@ void init_json_module(void); ant_value_t js_json_parse(ant_t *js, ant_value_t *args, int nargs); ant_value_t js_json_stringify(ant_t *js, ant_value_t *args, int nargs); +ant_value_t json_parse_value(ant_t *js, ant_value_t value); +ant_value_t json_stringify_value(ant_t *js, ant_value_t value); + #endif diff --git a/src/esm/loader.c b/src/esm/loader.c index e19a644..987bb34 100644 --- a/src/esm/loader.c +++ b/src/esm/loader.c @@ -924,7 +924,7 @@ static ant_value_t esm_load_json(ant_t *js, const char *path) { ant_value_t json_str = js_mkstr(js, file.data, file.size); free(file.data); - return js_json_parse(js, &json_str, 1); + return json_parse_value(js, json_str); } static ant_value_t esm_load_text(ant_t *js, const char *path) { diff --git a/src/modules/fetch.c b/src/modules/fetch.c index dfe6e34..4503a62 100644 --- a/src/modules/fetch.c +++ b/src/modules/fetch.c @@ -86,7 +86,7 @@ static ant_value_t response_text(ant_t *js, ant_value_t *args, int nargs) { static ant_value_t response_json(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this = js_getthis(js); ant_value_t body = js_get_slot(this, SLOT_DATA); - ant_value_t parsed = js_json_parse(js, &body, 1); + ant_value_t parsed = json_parse_value(js, body); ant_value_t promise = js_mkpromise(js); if (vtype(parsed) == T_ERR) { @@ -349,12 +349,11 @@ int has_pending_fetches(void) { void gc_mark_fetch(ant_t *js, gc_mark_fn mark) { if (!pending_requests) return; unsigned int len = utarray_len(pending_requests); + for (unsigned int i = 0; i < len; i++) { - fetch_request_t **reqp = (fetch_request_t **)utarray_eltptr(pending_requests, i); - if (reqp && *reqp) { - mark(js, (*reqp)->promise); - mark(js, (*reqp)->headers_obj); - } - } + fetch_request_t **reqp = (fetch_request_t **)utarray_eltptr(pending_requests, i); + if (reqp && *reqp) { + mark(js, (*reqp)->promise); + mark(js, (*reqp)->headers_obj); + }} } - diff --git a/src/modules/json.c b/src/modules/json.c index 2e27485..8921add 100644 --- a/src/modules/json.c +++ b/src/modules/json.c @@ -106,88 +106,128 @@ static inline void json_cycle_pop(json_cycle_ctx *ctx) { if (ctx->stack_size > 0) ctx->stack_size--; } -typedef struct { char *key; size_t key_len; ant_value_t value; } prop_entry; - -static int should_skip_prop(ant_t *js, const char *key, size_t key_len, ant_value_t value) { - if (is_internal_prop(key, (ant_offset_t)key_len)) return 1; - if (!is_special_object(value)) return 0; - return vtype(js_get_slot(value, SLOT_CODE)) == T_CFUNC; +static inline int key_matches(const char *a, size_t a_len, const char *b, size_t b_len) { + return a_len == b_len && memcmp(a, b, a_len) == 0; } -static prop_entry *collect_props(ant_t *js, ant_value_t val, int *out_count) { - prop_entry *props = NULL; - int count = 0, cap = 0; - const char *key; - size_t key_len; - ant_value_t value; - - ant_iter_t iter = js_prop_iter_begin(js, val); - while (js_prop_iter_next(&iter, &key, &key_len, &value)) { - if (should_skip_prop(js, key, key_len, value)) continue; - - if (count >= cap) { - cap = cap ? cap * 2 : 8; - props = realloc(props, cap * sizeof(prop_entry)); - } - - props[count].key = malloc(key_len + 1); - memcpy(props[count].key, key, key_len); - props[count].key[key_len] = '\0'; - props[count].key_len = key_len; - props[count].value = value; - count++; - } - js_prop_iter_end(&iter); - - *out_count = count; - return props; +static inline bool json_is_array(ant_value_t value) { + return vtype(value) == T_ARR; } -static inline void free_props(prop_entry *props, int from, int to) { - for (int i = from; i <= to; i++) free(props[i].key); - free(props); -} - -static inline int key_matches(const char *a, size_t a_len, const char *b, size_t b_len) { - return a_len == b_len && memcmp(a, b, a_len) == 0; +static inline ant_value_t json_snapshot_keys(ant_t *js, ant_value_t value) { + if (!is_special_object(value)) return js_mkarr(js); + return js_for_in_keys(js, value); } static int is_key_in_replacer_arr(ant_t *js, json_cycle_ctx *ctx, const char *key, size_t key_len) { if (!is_special_object(ctx->replacer_arr)) return 1; for (int i = 0; i < ctx->replacer_arr_len; i++) { + char idxstr[32]; + snprintf(idxstr, sizeof(idxstr), "%d", i); + + ant_value_t item = js_get(js, ctx->replacer_arr, idxstr); + int type = vtype(item); + + if (type == T_STR) { + size_t item_len; + char *item_str = js_getstr(js, item, &item_len); + if (key_matches(item_str, item_len, key, key_len)) return 1; + } else if (type == T_NUM) { + char numstr[32]; + snprintf(numstr, sizeof(numstr), "%.0f", js_getnum(item)); + if (key_matches(numstr, strlen(numstr), key, key_len)) return 1; + }} + + return 0; +} + +static yyjson_mut_val *ant_value_to_yyjson_with_key( + ant_t *js, yyjson_mut_doc *doc, const char *key, + ant_value_t val, json_cycle_ctx *ctx, int in_array +); + +static ant_value_t apply_reviver( + ant_t *js, ant_value_t holder, + const char *key, ant_value_t reviver +); + +static yyjson_mut_val *json_array_to_yyjson( + ant_t *js, yyjson_mut_doc *doc, ant_value_t val, json_cycle_ctx *ctx +) { + yyjson_mut_val *arr = yyjson_mut_arr(doc); + ant_offset_t length = js_arr_len(js, val); + ant_value_t saved_holder = ctx->holder; + + ctx->holder = val; + for (ant_offset_t i = 0; i < length; i++) { char idxstr[32]; - snprintf(idxstr, sizeof(idxstr), "%d", i); - ant_value_t item = js_get(js, ctx->replacer_arr, idxstr); - int type = vtype(item); - - if (type == T_STR) { - size_t item_len; - char *item_str = js_getstr(js, item, &item_len); - if (key_matches(item_str, item_len, key, key_len)) return 1; - } else if (type == T_NUM) { - char numstr[32]; - snprintf(numstr, sizeof(numstr), "%.0f", js_getnum(item)); - if (key_matches(numstr, strlen(numstr), key, key_len)) return 1; + uint_to_str(idxstr, sizeof(idxstr), (uint64_t)i); + ant_value_t elem = js_arr_get(js, val, i); + yyjson_mut_val *item = ant_value_to_yyjson_with_key(js, doc, idxstr, elem, ctx, 1); + if (ctx->has_cycle) { + ctx->holder = saved_holder; + return NULL; } + yyjson_mut_arr_add_val(arr, item); } - return 0; + + ctx->holder = saved_holder; + return arr; } -static yyjson_mut_val *ant_value_to_yyjson_with_key(ant_t *js, yyjson_mut_doc *doc, const char *key, ant_value_t val, json_cycle_ctx *ctx, int in_array); +static yyjson_mut_val *json_object_to_yyjson( + ant_t *js, yyjson_mut_doc *doc, ant_value_t val, json_cycle_ctx *ctx +) { + yyjson_mut_val *obj = yyjson_mut_obj(doc); + ant_value_t keys = json_snapshot_keys(js, val); + ant_value_t saved_holder = ctx->holder; + + if (is_err(keys)) { + ctx->has_cycle = 1; + return NULL; + } + + ctx->holder = val; + ant_offset_t key_count = js_arr_len(js, keys); + + for (ant_offset_t i = 0; i < key_count; i++) { + ant_value_t key_val = js_arr_get(js, keys, i); + size_t key_len = 0; + char *key = js_getstr(js, key_val, &key_len); + + if (!key) continue; + if (!is_key_in_replacer_arr(js, ctx, key, key_len)) continue; + + ant_value_t prop = js_get(js, val, key); + int ptype = vtype(prop); + if (ptype == T_UNDEF || ptype == T_FUNC) continue; + + yyjson_mut_val *jval = ant_value_to_yyjson_with_key(js, doc, key, prop, ctx, 0); + if (ctx->has_cycle) { + ctx->holder = saved_holder; + return NULL; + } + + if (jval == YYJSON_SKIP_VALUE) continue; + yyjson_mut_obj_add(obj, yyjson_mut_strncpy(doc, key, key_len), jval); + } + + ctx->holder = saved_holder; + return obj; +} static yyjson_mut_val *ant_value_to_yyjson_impl(ant_t *js, yyjson_mut_doc *doc, ant_value_t val, json_cycle_ctx *ctx, int in_array) { int type = vtype(val); yyjson_mut_val *result = NULL; if (is_special_object(val)) { - ant_value_t toJSON = js_get(js, val, "toJSON"); - if (vtype(toJSON) == T_FUNC) { - ant_value_t r = sv_vm_call(js->vm, js, toJSON, js_mkundef(), &val, 1, NULL, false); - if (vtype(r) == T_ERR) { ctx->has_cycle = 1; return NULL; } - return ant_value_to_yyjson_impl(js, doc, r, ctx, in_array); - } - } + ant_value_t toJSON = js_get(js, val, "toJSON"); + if (vtype(toJSON) == T_FUNC) { + ant_value_t r = sv_vm_call(js->vm, js, toJSON, js_mkundef(), &val, 1, NULL, false); + if (vtype(r) == T_ERR) { ctx->has_cycle = 1; return NULL; } + return ant_value_to_yyjson_impl(js, doc, r, ctx, in_array); + }} switch (type) { case T_NULL: return yyjson_mut_null(doc); @@ -220,64 +260,19 @@ static yyjson_mut_val *ant_value_to_yyjson_impl(ant_t *js, yyjson_mut_doc *doc, if (json_cycle_check(ctx, val)) return NULL; json_cycle_push(ctx, val); - - ant_value_t length_val = js_get(js, val, "length"); - - if (vtype(length_val) == T_NUM) { - yyjson_mut_val *arr = yyjson_mut_arr(doc); - int length = (int)js_getnum(length_val); - - ant_value_t saved_holder = ctx->holder; - ctx->holder = val; - - for (int i = 0; i < length; i++) { - char idxstr[32]; - snprintf(idxstr, sizeof(idxstr), "%d", i); - ant_value_t elem = js_get(js, val, idxstr); - yyjson_mut_val *item = ant_value_to_yyjson_with_key(js, doc, idxstr, elem, ctx, 1); - if (ctx->has_cycle) { ctx->holder = saved_holder; goto done; } - yyjson_mut_arr_add_val(arr, item); - } - ctx->holder = saved_holder; - result = arr; - goto done; - } - - yyjson_mut_val *obj = yyjson_mut_obj(doc); - int prop_count; - prop_entry *props = collect_props(js, val, &prop_count); - - ant_value_t saved_holder = ctx->holder; - ctx->holder = val; - - for (int i = 0; i < prop_count; i++) { - prop_entry *p = &props[i]; - - if (!is_key_in_replacer_arr(js, ctx, p->key, p->key_len)) { - free(p->key); continue; - } - - int ptype = vtype(p->value); - if (ptype == T_UNDEF || ptype == T_FUNC) { free(p->key); continue; } - - yyjson_mut_val *jval = ant_value_to_yyjson_with_key(js, doc, p->key, p->value, ctx, 0); - if (ctx->has_cycle) { free_props(props, 0, i); ctx->holder = saved_holder; goto done; } - if (jval == YYJSON_SKIP_VALUE) { free(p->key); continue; } - - yyjson_mut_obj_add(obj, yyjson_mut_strncpy(doc, p->key, p->key_len), jval); - free(p->key); - } - - ctx->holder = saved_holder; - free(props); - result = obj; -done: + result = json_is_array(val) + ? json_array_to_yyjson(js, doc, val, ctx) + : json_object_to_yyjson(js, doc, val, ctx); + json_cycle_pop(ctx); return result; } -static yyjson_mut_val *ant_value_to_yyjson_with_key(ant_t *js, yyjson_mut_doc *doc, const char *key, ant_value_t val, json_cycle_ctx *ctx, int in_array) { +static yyjson_mut_val *ant_value_to_yyjson_with_key( + ant_t *js, yyjson_mut_doc *doc, const char *key, + ant_value_t val, json_cycle_ctx *ctx, int in_array +) { if (vtype(ctx->replacer_func) != T_FUNC) return ant_value_to_yyjson_impl(js, doc, val, ctx, in_array); @@ -297,56 +292,49 @@ static yyjson_mut_val *ant_value_to_yyjson(ant_t *js, yyjson_mut_doc *doc, ant_v return ant_value_to_yyjson_with_key(js, doc, "", val, ctx, 0); } -static ant_value_t apply_reviver(ant_t *js, ant_value_t holder, const char *key, ant_value_t reviver) { - ant_value_t val = js_get(js, holder, key); - - if (is_special_object(val)) { - ant_value_t len_val = js_get(js, val, "length"); - if (vtype(len_val) == T_NUM) { - int length = (int)js_getnum(len_val); - for (int i = 0; i < length; i++) { - char idxstr[32]; - snprintf(idxstr, sizeof(idxstr), "%d", i); - ant_value_t new_elem = apply_reviver(js, val, idxstr, reviver); - if (vtype(new_elem) == T_UNDEF) js_delete_prop(js, val, idxstr, strlen(idxstr)); - else js_set(js, val, idxstr, new_elem); - } - } else { - const char *prop_key; - size_t prop_key_len; - ant_value_t prop_value; - - ant_value_t keys_arr = js_mkobj(js); - int key_count = 0; - ant_iter_t iter = js_prop_iter_begin(js, val); - while (js_prop_iter_next(&iter, &prop_key, &prop_key_len, &prop_value)) { - if (is_internal_prop(prop_key, (ant_offset_t)prop_key_len)) continue; - char idxstr[32]; - snprintf(idxstr, sizeof(idxstr), "%d", key_count); - js_set(js, keys_arr, idxstr, js_mkstr(js, prop_key, prop_key_len)); - key_count++; - } - js_prop_iter_end(&iter); - - for (int i = 0; i < key_count; i++) { - char idxstr[32]; - snprintf(idxstr, sizeof(idxstr), "%d", i); - ant_value_t key_str = js_get(js, keys_arr, idxstr); - size_t klen; - char *kstr = js_getstr(js, key_str, &klen); - ant_value_t new_val = apply_reviver(js, val, kstr, reviver); - if (vtype(new_val) == T_UNDEF) js_delete_prop(js, val, kstr, strlen(kstr)); - else js_set(js, val, kstr, new_val); - } - } - } - +static ant_value_t apply_reviver_call(ant_t *js, ant_value_t holder, const char *key, ant_value_t reviver) { ant_value_t key_str = js_mkstr(js, key, strlen(key)); ant_value_t call_args[2] = { key_str, js_get(js, holder, key) }; - return sv_vm_call(js->vm, js, reviver, holder, call_args, 2, NULL, false); } +static void apply_reviver_to_array(ant_t *js, ant_value_t value, ant_value_t reviver) { + ant_offset_t length = js_arr_len(js, value); + + for (ant_offset_t i = 0; i < length; i++) { + char idxstr[32]; + size_t idx_len = uint_to_str(idxstr, sizeof(idxstr), (uint64_t)i); + ant_value_t new_elem = apply_reviver(js, value, idxstr, reviver); + if (vtype(new_elem) == T_UNDEF) js_delete_prop(js, value, idxstr, idx_len); + else js_set(js, value, idxstr, new_elem); + } +} + +static void apply_reviver_to_object(ant_t *js, ant_value_t value, ant_value_t reviver) { + ant_value_t keys = json_snapshot_keys(js, value); + if (is_err(keys) || vtype(keys) != T_ARR) return; + + ant_offset_t key_count = js_arr_len(js, keys); + for (ant_offset_t i = 0; i < key_count; i++) { + ant_value_t key_val = js_arr_get(js, keys, i); + size_t key_len = 0; + char *key = js_getstr(js, key_val, &key_len); + if (!key) continue; + ant_value_t new_val = apply_reviver(js, value, key, reviver); + if (vtype(new_val) == T_UNDEF) js_delete_prop(js, value, key, key_len); + else js_set(js, value, key, new_val); + } +} + +static ant_value_t apply_reviver(ant_t *js, ant_value_t holder, const char *key, ant_value_t reviver) { + ant_value_t val = js_get(js, holder, key); + + if (json_is_array(val)) apply_reviver_to_array(js, val, reviver); + else if (vtype(val) == T_OBJ) apply_reviver_to_object(js, val, reviver); + + return apply_reviver_call(js, holder, key, reviver); +} + ant_value_t js_json_parse(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "JSON.parse() requires at least 1 argument"); if (vtype(args[0]) != T_STR) return js_mkerr(js, "JSON.parse() argument must be a string"); @@ -370,6 +358,11 @@ ant_value_t js_json_parse(ant_t *js, ant_value_t *args, int nargs) { return result; } +ant_value_t json_parse_value(ant_t *js, ant_value_t value) { + ant_value_t args[1] = { value }; + return js_json_parse(js, args, 1); +} + static yyjson_write_flag get_write_flags(ant_value_t *args, int nargs) { if (nargs < 3) return 0; @@ -448,6 +441,11 @@ cleanup: return result; } +ant_value_t json_stringify_value(ant_t *js, ant_value_t value) { + ant_value_t args[1] = { value }; + return js_json_stringify(js, args, 1); +} + void init_json_module() { ant_t *js = rt->js; ant_value_t json_obj = js_mkobj(js); diff --git a/src/modules/request.c b/src/modules/request.c index 8e0d4cb..3c2ef4e 100644 --- a/src/modules/request.c +++ b/src/modules/request.c @@ -364,7 +364,7 @@ static void resolve_body_promise( ant_value_t str = (data && size > 0) ? js_mkstr(js, (const char *)data, size) : js_mkstr(js, "", 0); - ant_value_t parsed = js_json_parse(js, &str, 1); + ant_value_t parsed = json_parse_value(js, str); if (is_err(parsed)) js_reject_promise(js, promise, request_rejection_reason(js, parsed)); else js_resolve_promise(js, promise, parsed); break; diff --git a/src/modules/response.c b/src/modules/response.c index a6e6770..5537a41 100644 --- a/src/modules/response.c +++ b/src/modules/response.c @@ -304,7 +304,7 @@ static void resolve_body_promise( } case BODY_JSON: { ant_value_t str = (data && size > 0) ? js_mkstr(js, (const char *)data, size) : js_mkstr(js, "", 0); - ant_value_t parsed = js_json_parse(js, &str, 1); + ant_value_t parsed = json_parse_value(js, str); if (is_err(parsed)) js_reject_promise(js, promise, response_rejection_reason(js, parsed)); else js_resolve_promise(js, promise, parsed); break; @@ -343,27 +343,52 @@ static void resolve_body_promise( }} } -static uint8_t *concat_chunks(ant_t *js, ant_value_t chunks, size_t *out_size) { +static bool response_chunk_is_uint8_array(ant_value_t chunk, TypedArrayData **out_ta) { + if (!is_object_type(chunk)) return false; + ant_value_t slot = js_get_slot(chunk, SLOT_BUFFER); + TypedArrayData *ta = (TypedArrayData *)js_gettypedarray(slot); + if (!ta || !ta->buffer || ta->buffer->is_detached) return false; + if (ta->type != TYPED_ARRAY_UINT8) return false; + *out_ta = ta; + return true; +} + +static uint8_t *concat_uint8_chunks( + ant_t *js, ant_value_t chunks, + size_t *out_size, ant_value_t *err_out +) { ant_offset_t n = js_arr_len(js, chunks); size_t total = 0; size_t pos = 0; uint8_t *buf = NULL; + TypedArrayData *ta = NULL; + + *out_size = 0; + *err_out = js_mkundef(); for (ant_offset_t i = 0; i < n; i++) { ant_value_t chunk = js_arr_get(js, chunks, i); - if (vtype(chunk) != T_TYPEDARRAY) continue; - TypedArrayData *ta = (TypedArrayData *)js_gettypedarray(chunk); - if (ta && ta->buffer && !ta->buffer->is_detached) total += ta->byte_length; + if (!response_chunk_is_uint8_array(chunk, &ta)) { + *err_out = js_mkerr_typed(js, JS_ERR_TYPE, "Response body stream chunk must be a Uint8Array"); + return NULL; + } + total += ta->byte_length; } buf = total > 0 ? malloc(total) : NULL; - if (total > 0 && !buf) return NULL; + if (total > 0 && !buf) { + *err_out = js_mkerr(js, "out of memory"); + return NULL; + } for (ant_offset_t i = 0; i < n; i++) { ant_value_t chunk = js_arr_get(js, chunks, i); - if (vtype(chunk) != T_TYPEDARRAY) continue; - TypedArrayData *ta = (TypedArrayData *)js_gettypedarray(chunk); - if (!ta || !ta->buffer || ta->buffer->is_detached || ta->byte_length == 0) continue; + if (!response_chunk_is_uint8_array(chunk, &ta)) { + free(buf); + *err_out = js_mkerr_typed(js, JS_ERR_TYPE, "Response body stream chunk must be a Uint8Array"); + return NULL; + } + if (ta->byte_length == 0) continue; memcpy(buf + pos, ta->buffer->data + ta->byte_offset, ta->byte_length); pos += ta->byte_length; } @@ -402,7 +427,12 @@ static ant_value_t stream_body_read(ant_t *js, ant_value_t *args, int nargs) { if (vtype(done_val) == T_BOOL && done_val == js_true) { size_t size = 0; - uint8_t *data = concat_chunks(js, chunks, &size); + ant_value_t chunk_err = js_mkundef(); + uint8_t *data = concat_uint8_chunks(js, chunks, &size, &chunk_err); + if (is_err(chunk_err)) { + js_reject_promise(js, promise, response_rejection_reason(js, chunk_err)); + return js_mkundef(); + } ant_value_t type_v = js_get(js, state, "type"); const char *body_type = (vtype(type_v) == T_STR) ? js_getstr(js, type_v, NULL) : NULL; resolve_body_promise(js, promise, data, size, body_type, mode, true); @@ -461,14 +491,14 @@ static ant_value_t consume_body(ant_t *js, int mode) { } stream = js_get_slot(this, SLOT_RESPONSE_BODY_STREAM); - if (d->body_used || (d->body_is_stream && rs_is_stream(stream) && rs_stream_unusable(stream))) { + if (d->body_used || (rs_is_stream(stream) && rs_stream_unusable(stream))) { js_reject_promise(js, promise, response_rejection_reason(js, js_mkerr_typed(js, JS_ERR_TYPE, "body stream is disturbed or locked"))); return promise; } d->body_used = true; - if (rs_is_stream(stream) && d->body_is_stream) + if (rs_is_stream(stream)) return consume_body_from_stream(js, stream, promise, mode, response_effective_body_type(js, this, d)); resolve_body_promise(js, promise, d->body_data, d->body_size, response_effective_body_type(js, this, d), mode, true); @@ -778,7 +808,7 @@ static ant_value_t js_response_json_static(ant_t *js, ant_value_t *args, int nar bool init_has_content_type = false; if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "Response.json requires 1 argument"); - stringify = js_json_stringify(js, args, 1); + stringify = json_stringify_value(js, args[0]); if (is_err(stringify)) return stringify; if (vtype(stringify) == T_UNDEF) { return js_mkerr_typed(js, JS_ERR_TYPE, "Response.json data is not JSON serializable"); @@ -882,7 +912,7 @@ RES_GETTER_END RES_GETTER_START(body_used) ant_value_t stored_stream = js_get_slot(this, SLOT_RESPONSE_BODY_STREAM); - bool used = d->body_used || (d->body_is_stream && rs_is_stream(stored_stream) && rs_stream_disturbed(stored_stream)); + bool used = d->body_used || (rs_is_stream(stored_stream) && rs_stream_disturbed(stored_stream)); return js_bool(used); RES_GETTER_END diff --git a/src/modules/server.c b/src/modules/server.c index d2e2d74..29d507e 100644 --- a/src/modules/server.c +++ b/src/modules/server.c @@ -503,8 +503,7 @@ static ant_value_t res_json(ant_t *js, ant_value_t *args, int nargs) { response_ctx_t *ctx = (response_ctx_t *)(unsigned long)js_getnum(ctx_val); if (!ctx) return js_mkundef(); - ant_value_t stringify_args[1] = { args[0] }; - ant_value_t result = js_json_stringify(js, stringify_args, 1); + ant_value_t result = json_stringify_value(js, args[0]); if (vtype(result) == T_STR) { size_t len; @@ -1031,4 +1030,3 @@ void gc_mark_server(ant_t *js, gc_mark_fn mark) { void init_server_module() { js_set(rt->js, rt->ant_obj, "serve", js_mkfun(js_serve)); } - diff --git a/src/modules/util.c b/src/modules/util.c index 0702f51..8bfe5f1 100644 --- a/src/modules/util.c +++ b/src/modules/util.c @@ -97,8 +97,7 @@ static bool util_sb_append_jsval(ant_t *js, util_sb_t *sb, ant_value_t v) { } static bool util_sb_append_json(ant_t *js, util_sb_t *sb, ant_value_t v) { - ant_value_t stringify_args[1] = {v}; - ant_value_t json = js_json_stringify(js, stringify_args, 1); + ant_value_t json = json_stringify_value(js, v); if (vtype(json) != T_STR) { return util_sb_append_n(sb, "[Circular]", 10); } diff --git a/src/modules/worker_threads.c b/src/modules/worker_threads.c index ae2044a..8100b8a 100644 --- a/src/modules/worker_threads.c +++ b/src/modules/worker_threads.c @@ -81,8 +81,7 @@ static void wt_init_env_store(ant_t *js, bool is_worker) { const char *raw = getenv(WT_ENV_STORE_JSON); if (raw && raw[0]) { ant_value_t input = js_mkstr(js, raw, strlen(raw)); - ant_value_t parse_args[1] = {input}; - ant_value_t parsed = js_json_parse(js, parse_args, 1); + ant_value_t parsed = json_parse_value(js, input); if (is_object_type(parsed)) store = parsed; } } @@ -411,8 +410,7 @@ static void wt_emit_message_from_json(ant_worker_thread_t *wt, const char *json, ant_t *js = wt->js; ant_value_t s = js_mkstr(js, json, len); - ant_value_t parse_args[1] = {s}; - ant_value_t msg = js_json_parse(js, parse_args, 1); + ant_value_t msg = json_parse_value(js, s); if (is_err(msg)) msg = s; wt_emit(wt, "message", msg); @@ -914,8 +912,7 @@ static ant_value_t worker_threads_set_environment_data(ant_t *js, ant_value_t *a ant_value_t value_json = js_json_stringify(js, value_stringify_args, 1); if (vtype(value_json) != T_STR) return js_mkerr(js, "setEnvironmentData value must be JSON-serializable"); - ant_value_t parse_args[1] = {value_json}; - ant_value_t cloned = js_json_parse(js, parse_args, 1); + ant_value_t cloned = json_parse_value(js, value_json); if (is_err(cloned)) return js_mkerr(js, "setEnvironmentData value must be JSON-serializable"); size_t key_len = 0; @@ -1016,8 +1013,7 @@ ant_value_t worker_threads_library(ant_t *js) { const char *worker_data_json = getenv(WT_ENV_DATA_JSON); if (worker_data_json && worker_data_json[0]) { ant_value_t raw = js_mkstr(js, worker_data_json, strlen(worker_data_json)); - ant_value_t parse_args[1] = {raw}; - ant_value_t parsed = js_json_parse(js, parse_args, 1); + ant_value_t parsed = json_parse_value(js, raw); js_set(js, lib, "workerData", is_err(parsed) ? js_mkundef() : parsed); } else js_set(js, lib, "workerData", js_mkundef()); } else { diff --git a/src/streams/pipes.c b/src/streams/pipes.c index d877a03..59e40d3 100644 --- a/src/streams/pipes.c +++ b/src/streams/pipes.c @@ -11,6 +11,7 @@ #include "streams/pipes.h" #include "streams/readable.h" #include "streams/writable.h" +#include "modules/structured-clone.h" static void pipes_chain_promise( ant_t *js, ant_value_t value, @@ -365,10 +366,13 @@ ant_value_t readable_stream_pipe_to( ant_value_t reader_args[1] = { source }; ant_value_t saved = js->new_target; + js->new_target = g_reader_proto; ant_value_t reader = js_rs_reader_ctor(js, reader_args, 1); js->new_target = saved; + if (is_err(reader)) return pipe_create_rejected(js, js->thrown_value); + rs->disturbed = true; ant_value_t writer = ws_acquire_writer(js, dest); if (is_err(writer)) { @@ -585,6 +589,7 @@ static void tee_error_branch(ant_t *js, ant_value_t branch_stream, ant_value_t e } static void tee_pull(ant_t *js, ant_value_t state); +static ant_value_t tee_read_reject(ant_t *js, ant_value_t *args, int nargs); static ant_value_t tee_cancel_both_resolve(ant_t *js, ant_value_t *args, int nargs) { ant_value_t state = js_get_slot(js->current_func, SLOT_DATA); @@ -622,8 +627,19 @@ static ant_value_t tee_read_resolve(ant_t *js, ant_value_t *args, int nargs) { } ant_value_t value = js_get(js, result, "value"); + ant_value_t clone = value; + + if (!st->canceled1 && !st->canceled2) { + ant_value_t clone_args[1] = { value }; + clone = js_structured_clone(js, clone_args, 1); + if (is_err(clone)) { + tee_read_reject(js, &clone, 1); + return js_mkundef(); + }} + if (!st->canceled1) tee_enqueue_branch(js, branch1, value); - if (!st->canceled2) tee_enqueue_branch(js, branch2, value); + if (!st->canceled2) tee_enqueue_branch(js, branch2, clone); + return js_mkundef(); } -- 2.51.2