MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ensure proper memory management for response context

+150 -23
+6 -6
README.md
··· 9 9 10 10 ## Table of contents 11 11 12 - * [Installation](#installation) 13 - * [Building Ant](#building-ant) 14 - * [Security](#security) 15 - * [Contributing to Ant](#contributing-to-ant) 16 - * [Current project team members](#current-project-team-members) 12 + - [Installation](#installation) 13 + - [Building Ant](#building-ant) 14 + - [Security](#security) 15 + - [Contributing to Ant](#contributing-to-ant) 16 + - [Project team members](#current-project-team-members) 17 17 18 18 ## Installation 19 19 ··· 37 37 We welcome contributions through pull request. See [CONTRIBUTING.md](CONTRIBUTING.md) for more details. <br> 38 38 For more information about Ant's internal structure, read the [Ant DeepWiki](https://deepwiki.com/theMackabu/ant). 39 39 40 - ## Current project team members 40 + ## Project team members 41 41 42 42 For information about the governance of Ant, see [GOVERNANCE.md](GOVERNANCE.md).
+2
src/ant.c
··· 9855 9855 js_parse_state_t saved; 9856 9856 JS_SAVE_STATE(js, saved); 9857 9857 uint8_t saved_flags = js->flags; 9858 + jsval_t saved_current_func = js->current_func; 9858 9859 mco_result mco_res = mco_yield(current_mco); 9859 9860 9860 9861 JS_RESTORE_STATE(js, saved); 9861 9862 js->flags = saved_flags; 9863 + js->current_func = saved_current_func; 9862 9864 9863 9865 if (mco_res != MCO_SUCCESS) return js_mkerr(js, "failed to yield coroutine"); 9864 9866
+72 -17
src/modules/server.c
··· 66 66 int sent; 67 67 int supports_gzip; 68 68 int should_free_body; 69 + int should_free_content_type; 70 + int should_free_redirect; 69 71 UT_array *custom_headers; 70 72 char *redirect_location; 71 73 uv_tcp_t *client_handle; ··· 400 402 401 403 if (vtype(args[0]) == T_STR && vtype(args[1]) == T_STR) { 402 404 custom_header_t header; 403 - header.name = js_getstr(js, args[0], NULL); 404 - header.value = js_getstr(js, args[1], NULL); 405 + header.name = strdup(js_getstr(js, args[0], NULL)); 406 + header.value = strdup(js_getstr(js, args[1], NULL)); 405 407 utarray_push_back(ctx->custom_headers, &header); 406 408 } 407 409 ··· 436 438 if (!ctx) return js_mkundef(); 437 439 438 440 if (vtype(args[0]) == T_STR) { 439 - ctx->body = js_getstr(js, args[0], &ctx->body_len); 441 + size_t len; 442 + const char *src = js_getstr(js, args[0], &len); 443 + char *copy = malloc(len + 1); 444 + if (copy) { 445 + memcpy(copy, src, len); 446 + copy[len] = '\0'; 447 + } 448 + ctx->body = copy; 449 + ctx->body_len = len; 450 + ctx->should_free_body = 1; 440 451 } 441 452 442 453 if (nargs >= 2 && vtype(args[1]) == T_NUM) { ··· 444 455 } 445 456 446 457 if (nargs >= 3 && vtype(args[2]) == T_STR) { 447 - ctx->content_type = js_getstr(js, args[2], NULL); 448 - } else { 449 - ctx->content_type = "text/plain"; 450 - } 458 + ctx->content_type = strdup(js_getstr(js, args[2], NULL)); 459 + ctx->should_free_content_type = 1; 460 + } else ctx->content_type = "text/plain"; 451 461 452 462 ctx->sent = 1; 453 - 454 463 return js_mkundef(); 455 464 } 456 465 ··· 465 474 if (!ctx) return js_mkundef(); 466 475 467 476 if (vtype(args[0]) == T_STR) { 468 - ctx->body = js_getstr(js, args[0], &ctx->body_len); 477 + size_t len; 478 + const char *src = js_getstr(js, args[0], &len); 479 + char *copy = malloc(len + 1); 480 + if (copy) { 481 + memcpy(copy, src, len); 482 + copy[len] = '\0'; 483 + } 484 + ctx->body = copy; 485 + ctx->body_len = len; 486 + ctx->should_free_body = 1; 469 487 } 470 488 471 489 if (nargs >= 2 && vtype(args[1]) == T_NUM) { ··· 492 510 jsval_t result = js_json_stringify(js, stringify_args, 1); 493 511 494 512 if (vtype(result) == T_STR) { 495 - ctx->body = js_getstr(js, result, &ctx->body_len); 513 + size_t len; 514 + const char *src = js_getstr(js, result, &len); 515 + char *copy = malloc(len + 1); 516 + if (copy) { 517 + memcpy(copy, src, len); 518 + copy[len] = '\0'; 519 + } 520 + ctx->body = copy; 521 + ctx->body_len = len; 522 + ctx->should_free_body = 1; 496 523 } else if (vtype(result) == T_ERR) { 497 524 const char *json_str = js_str(js, args[0]); 498 525 if (json_str) { 499 - ctx->body = (char *)json_str; 500 - ctx->body_len = strlen(json_str); 526 + size_t len = strlen(json_str); 527 + char *copy = malloc(len + 1); 528 + if (copy) { 529 + memcpy(copy, json_str, len); 530 + copy[len] = '\0'; 531 + } 532 + ctx->body = copy; 533 + ctx->body_len = len; 534 + ctx->should_free_body = 1; 501 535 } 502 536 } 503 537 ··· 541 575 if (!ctx) return js_mkundef(); 542 576 543 577 if (vtype(args[0]) == T_STR) { 544 - ctx->redirect_location = js_getstr(js, args[0], NULL); 578 + ctx->redirect_location = strdup(js_getstr(js, args[0], NULL)); 579 + ctx->should_free_redirect = 1; 545 580 } 546 581 547 582 ctx->status = 302; ··· 714 749 res_ctx->sent = 0; 715 750 res_ctx->supports_gzip = http_req->accepts_gzip; 716 751 res_ctx->should_free_body = 0; 752 + res_ctx->should_free_content_type = 0; 753 + res_ctx->should_free_redirect = 0; 717 754 utarray_new(res_ctx->custom_headers, &custom_header_icd); 718 755 res_ctx->redirect_location = NULL; 719 756 res_ctx->client_handle = &client->handle; ··· 762 799 res_ctx->body_len = strlen(clean_error); 763 800 res_ctx->should_free_body = 1; 764 801 } else { 765 - res_ctx->body = (char *)error_msg; 766 - res_ctx->body_len = strlen(error_msg); 767 - res_ctx->should_free_body = 0; 802 + size_t err_len = strlen(error_msg); 803 + char *err_copy = malloc(err_len + 1); 804 + if (err_copy) { 805 + memcpy(err_copy, error_msg, err_len); 806 + err_copy[err_len] = '\0'; 807 + } 808 + res_ctx->body = err_copy; 809 + res_ctx->body_len = err_len; 810 + res_ctx->should_free_body = 1; 768 811 } 769 812 res_ctx->status = 500; 770 813 res_ctx->content_type = "text/plain"; ··· 809 852 uv_close((uv_handle_t *)ctx->client_handle, on_close); 810 853 } 811 854 812 - if (ctx->custom_headers) utarray_free(ctx->custom_headers); 855 + if (ctx->custom_headers) { 856 + custom_header_t *h = NULL; 857 + while ((h = (custom_header_t*)utarray_next(ctx->custom_headers, h))) { 858 + if (h->name) free(h->name); 859 + if (h->value) free(h->value); 860 + } 861 + utarray_free(ctx->custom_headers); 862 + } 863 + 813 864 if (ctx->should_free_body && ctx->body) free(ctx->body); 865 + if (ctx->should_free_content_type && ctx->content_type) free(ctx->content_type); 866 + if (ctx->should_free_redirect && ctx->redirect_location) free(ctx->redirect_location); 814 867 815 868 free(ctx); 816 869 } else { current = &ctx->next; } ··· 874 927 res_ctx->sent = 1; 875 928 res_ctx->supports_gzip = 0; 876 929 res_ctx->should_free_body = 0; 930 + res_ctx->should_free_content_type = 0; 931 + res_ctx->should_free_redirect = 0; 877 932 utarray_new(res_ctx->custom_headers, &custom_header_icd); 878 933 res_ctx->redirect_location = NULL; 879 934 res_ctx->client_handle = &client->handle;
+70
tests/test_inline_await.js
··· 1 + async function delayed(val) { 2 + return val; 3 + } 4 + 5 + function add(a, b, c) { 6 + return a + b + c; 7 + } 8 + 9 + async function run() { 10 + // 1: basic inline await in call args 11 + console.log('=== Test 1: inline await in call args ==='); 12 + const r1 = add(await delayed(1), 2, 3); 13 + console.log(r1 === 6 ? 'โœ“' : 'โœ—', 'add(await delayed(1), 2, 3) =', r1); 14 + 15 + // 2: multiple inline awaits 16 + console.log('\n=== Test 2: multiple inline awaits ==='); 17 + const r2 = add(await delayed(10), await delayed(20), await delayed(30)); 18 + console.log(r2 === 60 ? 'โœ“' : 'โœ—', 'add(await, await, await) =', r2); 19 + 20 + // 3: inline await as method call arg 21 + console.log('\n=== Test 3: method call with inline await ==='); 22 + const obj = { greet(name) { return 'hello ' + name; } }; 23 + const r3 = obj.greet(await delayed('world')); 24 + console.log(r3 === 'hello world' ? 'โœ“' : 'โœ—', 'obj.greet(await) =', r3); 25 + 26 + // 4: chained property method with inline await 27 + console.log('\n=== Test 4: chained method with inline await ==='); 28 + const nested = { inner: { say(msg) { return 'said: ' + msg; } } }; 29 + const r4 = nested.inner.say(await delayed('hi')); 30 + console.log(r4 === 'said: hi' ? 'โœ“' : 'โœ—', 'nested.inner.say(await) =', r4); 31 + 32 + // 5: inline await with async fs (the real-world case) 33 + console.log('\n=== Test 5: console.log with inline await ==='); 34 + console.log('value:', await delayed(42)); 35 + 36 + // 6: array push with inline await 37 + console.log('\n=== Test 6: array method with inline await ==='); 38 + const arr = [1, 2]; 39 + arr.push(await delayed(3)); 40 + console.log(arr.length === 3 && arr[2] === 3 ? 'โœ“' : 'โœ—', 'arr.push(await) =', arr); 41 + 42 + // 7: inline await with real fs stream 43 + console.log('\n=== Test 7: inline await stream (real fs) ==='); 44 + const { stream } = await import('ant:fs'); 45 + const file = import.meta.dirname + '/test_inline_await.js'; 46 + const data = await stream(file); 47 + console.log(data.length > 0 ? 'โœ“' : 'โœ—', 'assigned await stream:', data.length, 'bytes'); 48 + 49 + // 8: inline await stream as function arg 50 + console.log('\n=== Test 8: fn(await stream(...)) ==='); 51 + function getLen(s) { return s.length; } 52 + const r8 = getLen(await stream(file)); 53 + console.log(r8 > 0 ? 'โœ“' : 'โœ—', 'getLen(await stream()) =', r8); 54 + 55 + // 9: inline await stream as method arg 56 + console.log('\n=== Test 9: obj.method(await stream(...)) ==='); 57 + const helper = { size(s) { return s.length; } }; 58 + const r9 = helper.size(await stream(file)); 59 + console.log(r9 > 0 ? 'โœ“' : 'โœ—', 'helper.size(await stream()) =', r9); 60 + 61 + // 10: chained method with inline await stream 62 + console.log('\n=== Test 10: a.b.method(await stream(...)) ==='); 63 + const deep = { util: { size(s) { return s.length; } } }; 64 + const r10 = deep.util.size(await stream(file)); 65 + console.log(r10 > 0 ? 'โœ“' : 'โœ—', 'deep.util.size(await stream()) =', r10); 66 + 67 + console.log('\nโœ“ done'); 68 + } 69 + 70 + run();