@scriptc/runtime 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/package.json +16 -6
- package/src/scr_array.c +488 -0
- package/src/scr_assert.c +1393 -0
- package/src/scr_async.c +2593 -0
- package/src/scr_async_dyn.c +607 -0
- package/src/scr_bytes.c +1425 -0
- package/src/scr_bytes_io.c +161 -0
- package/src/scr_child.c +3587 -0
- package/src/scr_closure.c +214 -0
- package/src/scr_console.c +143 -0
- package/src/scr_cycle.c +218 -0
- package/src/scr_dc.c +805 -0
- package/src/scr_dgram.c +1007 -0
- package/src/scr_dyn_handle.c +154 -0
- package/src/scr_dyn_invoke.c +644 -0
- package/src/scr_error.c +332 -0
- package/src/scr_events.c +714 -0
- package/src/scr_events_emitter.c +699 -0
- package/src/scr_exception.c +242 -0
- package/src/scr_fetch.c +1130 -0
- package/src/scr_fetch_curl.c +654 -0
- package/src/scr_http.c +3482 -0
- package/src/scr_http2.c +3030 -0
- package/src/scr_inspect.c +803 -0
- package/src/scr_inspect_island.c +51 -0
- package/src/scr_island.c +9363 -0
- package/src/scr_json.c +2151 -0
- package/src/scr_lib.c +3612 -0
- package/src/scr_loop_epoll.c +241 -0
- package/src/scr_loop_kqueue.c +121 -0
- package/src/scr_loop_wsapoll.c +208 -0
- package/src/scr_map.c +591 -0
- package/src/scr_net.c +3017 -0
- package/src/scr_net_island.c +458 -0
- package/src/scr_number.c +115 -0
- package/src/scr_object.c +25 -0
- package/src/scr_path.c +1266 -0
- package/src/scr_platform.h +119 -0
- package/src/scr_readline.c +287 -0
- package/src/scr_regex.c +1080 -0
- package/src/scr_runtime.h +5046 -0
- package/src/scr_stream.c +2877 -0
- package/src/scr_string.c +1264 -0
- package/src/scr_symbol.c +132 -0
- package/src/scr_test.c +662 -0
- package/src/scr_tls.c +1520 -0
- package/src/scr_union.c +105 -0
- package/src/scr_url.c +911 -0
- package/src/scr_url_internal.h +29 -0
- package/src/scr_url_params.c +561 -0
- package/src/scr_watch.c +568 -0
- package/src/scr_web.c +1778 -0
- package/src/scr_win.c +76 -0
- package/src/scr_zlib.c +197 -0
- package/src/scr_zlib_island.c +15 -0
- package/vendor/README.md +52 -0
- package/vendor/curl/COPYRIGHT +534 -0
- package/vendor/curl/include/curl/curl.h +3214 -0
- package/vendor/curl/include/curl/curlver.h +79 -0
- package/vendor/curl/include/curl/easy.h +125 -0
- package/vendor/curl/include/curl/header.h +74 -0
- package/vendor/curl/include/curl/mprintf.h +52 -0
- package/vendor/curl/include/curl/multi.h +460 -0
- package/vendor/curl/include/curl/options.h +70 -0
- package/vendor/curl/include/curl/stdcheaders.h +35 -0
- package/vendor/curl/include/curl/system.h +508 -0
- package/vendor/curl/include/curl/typecheck-gcc.h +716 -0
- package/vendor/curl/include/curl/urlapi.h +149 -0
- package/vendor/curl/include/curl/websockets.h +84 -0
- package/vendor/mbedtls/LICENSE +553 -0
- package/vendor/mbedtls/include/CMakeLists.txt +22 -0
- package/vendor/mbedtls/include/mbedtls/aes.h +631 -0
- package/vendor/mbedtls/include/mbedtls/aria.h +343 -0
- package/vendor/mbedtls/include/mbedtls/asn1.h +642 -0
- package/vendor/mbedtls/include/mbedtls/asn1write.h +390 -0
- package/vendor/mbedtls/include/mbedtls/base64.h +82 -0
- package/vendor/mbedtls/include/mbedtls/bignum.h +1088 -0
- package/vendor/mbedtls/include/mbedtls/block_cipher.h +76 -0
- package/vendor/mbedtls/include/mbedtls/build_info.h +194 -0
- package/vendor/mbedtls/include/mbedtls/camellia.h +305 -0
- package/vendor/mbedtls/include/mbedtls/ccm.h +526 -0
- package/vendor/mbedtls/include/mbedtls/chacha20.h +209 -0
- package/vendor/mbedtls/include/mbedtls/chachapoly.h +351 -0
- package/vendor/mbedtls/include/mbedtls/check_config.h +1149 -0
- package/vendor/mbedtls/include/mbedtls/cipher.h +1250 -0
- package/vendor/mbedtls/include/mbedtls/cmac.h +246 -0
- package/vendor/mbedtls/include/mbedtls/compat-2.x.h +46 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h +578 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_legacy_from_psa.h +873 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h +359 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_psa_superset_legacy.h +145 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h +91 -0
- package/vendor/mbedtls/include/mbedtls/config_adjust_x509.h +35 -0
- package/vendor/mbedtls/include/mbedtls/config_psa.h +61 -0
- package/vendor/mbedtls/include/mbedtls/constant_time.h +36 -0
- package/vendor/mbedtls/include/mbedtls/ctr_drbg.h +596 -0
- package/vendor/mbedtls/include/mbedtls/debug.h +156 -0
- package/vendor/mbedtls/include/mbedtls/des.h +385 -0
- package/vendor/mbedtls/include/mbedtls/dhm.h +972 -0
- package/vendor/mbedtls/include/mbedtls/ecdh.h +455 -0
- package/vendor/mbedtls/include/mbedtls/ecdsa.h +674 -0
- package/vendor/mbedtls/include/mbedtls/ecjpake.h +298 -0
- package/vendor/mbedtls/include/mbedtls/ecp.h +1517 -0
- package/vendor/mbedtls/include/mbedtls/entropy.h +274 -0
- package/vendor/mbedtls/include/mbedtls/error.h +201 -0
- package/vendor/mbedtls/include/mbedtls/gcm.h +387 -0
- package/vendor/mbedtls/include/mbedtls/hkdf.h +124 -0
- package/vendor/mbedtls/include/mbedtls/hmac_drbg.h +434 -0
- package/vendor/mbedtls/include/mbedtls/lms.h +440 -0
- package/vendor/mbedtls/include/mbedtls/mbedtls_config.h +4446 -0
- package/vendor/mbedtls/include/mbedtls/md.h +526 -0
- package/vendor/mbedtls/include/mbedtls/md5.h +190 -0
- package/vendor/mbedtls/include/mbedtls/memory_buffer_alloc.h +142 -0
- package/vendor/mbedtls/include/mbedtls/net_sockets.h +299 -0
- package/vendor/mbedtls/include/mbedtls/nist_kw.h +166 -0
- package/vendor/mbedtls/include/mbedtls/oid.h +727 -0
- package/vendor/mbedtls/include/mbedtls/pem.h +160 -0
- package/vendor/mbedtls/include/mbedtls/pk.h +1303 -0
- package/vendor/mbedtls/include/mbedtls/pkcs12.h +186 -0
- package/vendor/mbedtls/include/mbedtls/pkcs5.h +198 -0
- package/vendor/mbedtls/include/mbedtls/pkcs7.h +252 -0
- package/vendor/mbedtls/include/mbedtls/platform.h +516 -0
- package/vendor/mbedtls/include/mbedtls/platform_time.h +79 -0
- package/vendor/mbedtls/include/mbedtls/platform_util.h +247 -0
- package/vendor/mbedtls/include/mbedtls/poly1305.h +168 -0
- package/vendor/mbedtls/include/mbedtls/private_access.h +20 -0
- package/vendor/mbedtls/include/mbedtls/psa_util.h +207 -0
- package/vendor/mbedtls/include/mbedtls/ripemd160.h +136 -0
- package/vendor/mbedtls/include/mbedtls/rsa.h +1170 -0
- package/vendor/mbedtls/include/mbedtls/sha1.h +219 -0
- package/vendor/mbedtls/include/mbedtls/sha256.h +200 -0
- package/vendor/mbedtls/include/mbedtls/sha3.h +172 -0
- package/vendor/mbedtls/include/mbedtls/sha512.h +208 -0
- package/vendor/mbedtls/include/mbedtls/ssl.h +5887 -0
- package/vendor/mbedtls/include/mbedtls/ssl_cache.h +187 -0
- package/vendor/mbedtls/include/mbedtls/ssl_ciphersuites.h +482 -0
- package/vendor/mbedtls/include/mbedtls/ssl_cookie.h +106 -0
- package/vendor/mbedtls/include/mbedtls/ssl_ticket.h +199 -0
- package/vendor/mbedtls/include/mbedtls/threading.h +167 -0
- package/vendor/mbedtls/include/mbedtls/timing.h +94 -0
- package/vendor/mbedtls/include/mbedtls/version.h +78 -0
- package/vendor/mbedtls/include/mbedtls/x509.h +500 -0
- package/vendor/mbedtls/include/mbedtls/x509_crl.h +184 -0
- package/vendor/mbedtls/include/mbedtls/x509_crt.h +1208 -0
- package/vendor/mbedtls/include/mbedtls/x509_csr.h +382 -0
- package/vendor/mbedtls/include/psa/build_info.h +20 -0
- package/vendor/mbedtls/include/psa/crypto.h +4998 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_auto_enabled.h +31 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_dependencies.h +51 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_key_pair_types.h +101 -0
- package/vendor/mbedtls/include/psa/crypto_adjust_config_synonyms.h +49 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_composites.h +214 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_key_derivation.h +118 -0
- package/vendor/mbedtls/include/psa/crypto_builtin_primitives.h +114 -0
- package/vendor/mbedtls/include/psa/crypto_compat.h +230 -0
- package/vendor/mbedtls/include/psa/crypto_config.h +145 -0
- package/vendor/mbedtls/include/psa/crypto_driver_common.h +44 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_composites.h +151 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_key_derivation.h +52 -0
- package/vendor/mbedtls/include/psa/crypto_driver_contexts_primitives.h +105 -0
- package/vendor/mbedtls/include/psa/crypto_extra.h +2145 -0
- package/vendor/mbedtls/include/psa/crypto_legacy.h +88 -0
- package/vendor/mbedtls/include/psa/crypto_platform.h +102 -0
- package/vendor/mbedtls/include/psa/crypto_se_driver.h +1383 -0
- package/vendor/mbedtls/include/psa/crypto_sizes.h +1319 -0
- package/vendor/mbedtls/include/psa/crypto_struct.h +527 -0
- package/vendor/mbedtls/include/psa/crypto_types.h +508 -0
- package/vendor/mbedtls/include/psa/crypto_values.h +2782 -0
- package/vendor/mbedtls/library/aes.c +2294 -0
- package/vendor/mbedtls/library/aesce.c +624 -0
- package/vendor/mbedtls/library/aesce.h +136 -0
- package/vendor/mbedtls/library/aesni.c +846 -0
- package/vendor/mbedtls/library/aesni.h +162 -0
- package/vendor/mbedtls/library/alignment.h +704 -0
- package/vendor/mbedtls/library/aria.c +969 -0
- package/vendor/mbedtls/library/asn1parse.c +468 -0
- package/vendor/mbedtls/library/asn1write.c +440 -0
- package/vendor/mbedtls/library/base64.c +322 -0
- package/vendor/mbedtls/library/base64_internal.h +45 -0
- package/vendor/mbedtls/library/bignum.c +2583 -0
- package/vendor/mbedtls/library/bignum_core.c +1240 -0
- package/vendor/mbedtls/library/bignum_core.h +872 -0
- package/vendor/mbedtls/library/bignum_core_invasive.h +38 -0
- package/vendor/mbedtls/library/bignum_internal.h +122 -0
- package/vendor/mbedtls/library/bignum_mod.c +394 -0
- package/vendor/mbedtls/library/bignum_mod.h +452 -0
- package/vendor/mbedtls/library/bignum_mod_raw.c +276 -0
- package/vendor/mbedtls/library/bignum_mod_raw.h +416 -0
- package/vendor/mbedtls/library/bignum_mod_raw_invasive.h +34 -0
- package/vendor/mbedtls/library/block_cipher.c +207 -0
- package/vendor/mbedtls/library/block_cipher_internal.h +99 -0
- package/vendor/mbedtls/library/bn_mul.h +1094 -0
- package/vendor/mbedtls/library/camellia.c +1058 -0
- package/vendor/mbedtls/library/ccm.c +777 -0
- package/vendor/mbedtls/library/chacha20.c +563 -0
- package/vendor/mbedtls/library/chacha20_internal.h +23 -0
- package/vendor/mbedtls/library/chachapoly.c +487 -0
- package/vendor/mbedtls/library/check_crypto_config.h +136 -0
- package/vendor/mbedtls/library/cipher.c +1712 -0
- package/vendor/mbedtls/library/cipher_invasive.h +28 -0
- package/vendor/mbedtls/library/cipher_wrap.c +2482 -0
- package/vendor/mbedtls/library/cipher_wrap.h +178 -0
- package/vendor/mbedtls/library/cmac.c +1067 -0
- package/vendor/mbedtls/library/common.h +487 -0
- package/vendor/mbedtls/library/constant_time.c +247 -0
- package/vendor/mbedtls/library/constant_time_impl.h +541 -0
- package/vendor/mbedtls/library/constant_time_internal.h +579 -0
- package/vendor/mbedtls/library/ctr.h +35 -0
- package/vendor/mbedtls/library/ctr_drbg.c +1016 -0
- package/vendor/mbedtls/library/debug.c +475 -0
- package/vendor/mbedtls/library/debug_internal.h +185 -0
- package/vendor/mbedtls/library/des.c +1042 -0
- package/vendor/mbedtls/library/dhm.c +700 -0
- package/vendor/mbedtls/library/ecdh.c +696 -0
- package/vendor/mbedtls/library/ecdsa.c +858 -0
- package/vendor/mbedtls/library/ecjpake.c +1216 -0
- package/vendor/mbedtls/library/ecp.c +3674 -0
- package/vendor/mbedtls/library/ecp_curves.c +6125 -0
- package/vendor/mbedtls/library/ecp_curves_new.c +9 -0
- package/vendor/mbedtls/library/ecp_internal_alt.h +287 -0
- package/vendor/mbedtls/library/ecp_invasive.h +305 -0
- package/vendor/mbedtls/library/entropy.c +680 -0
- package/vendor/mbedtls/library/entropy_poll.c +233 -0
- package/vendor/mbedtls/library/entropy_poll.h +64 -0
- package/vendor/mbedtls/library/error.c +878 -0
- package/vendor/mbedtls/library/gcm.c +1330 -0
- package/vendor/mbedtls/library/hkdf.c +161 -0
- package/vendor/mbedtls/library/hmac_drbg.c +633 -0
- package/vendor/mbedtls/library/lmots.c +789 -0
- package/vendor/mbedtls/library/lmots.h +288 -0
- package/vendor/mbedtls/library/lms.c +778 -0
- package/vendor/mbedtls/library/md.c +1108 -0
- package/vendor/mbedtls/library/md5.c +426 -0
- package/vendor/mbedtls/library/md_psa.h +26 -0
- package/vendor/mbedtls/library/md_wrap.h +46 -0
- package/vendor/mbedtls/library/memory_buffer_alloc.c +751 -0
- package/vendor/mbedtls/library/mps_common.h +181 -0
- package/vendor/mbedtls/library/mps_error.h +89 -0
- package/vendor/mbedtls/library/mps_reader.c +538 -0
- package/vendor/mbedtls/library/mps_reader.h +366 -0
- package/vendor/mbedtls/library/mps_trace.c +112 -0
- package/vendor/mbedtls/library/mps_trace.h +154 -0
- package/vendor/mbedtls/library/net_sockets.c +694 -0
- package/vendor/mbedtls/library/nist_kw.c +729 -0
- package/vendor/mbedtls/library/oid.c +1166 -0
- package/vendor/mbedtls/library/padlock.c +157 -0
- package/vendor/mbedtls/library/padlock.h +111 -0
- package/vendor/mbedtls/library/pem.c +554 -0
- package/vendor/mbedtls/library/pk.c +1602 -0
- package/vendor/mbedtls/library/pk_ecc.c +261 -0
- package/vendor/mbedtls/library/pk_internal.h +241 -0
- package/vendor/mbedtls/library/pk_wrap.c +1618 -0
- package/vendor/mbedtls/library/pk_wrap.h +138 -0
- package/vendor/mbedtls/library/pkcs12.c +437 -0
- package/vendor/mbedtls/library/pkcs5.c +500 -0
- package/vendor/mbedtls/library/pkcs7.c +787 -0
- package/vendor/mbedtls/library/pkparse.c +1392 -0
- package/vendor/mbedtls/library/pkwrite.c +631 -0
- package/vendor/mbedtls/library/pkwrite.h +121 -0
- package/vendor/mbedtls/library/platform.c +402 -0
- package/vendor/mbedtls/library/platform_util.c +258 -0
- package/vendor/mbedtls/library/poly1305.c +492 -0
- package/vendor/mbedtls/library/psa_crypto.c +9532 -0
- package/vendor/mbedtls/library/psa_crypto_aead.c +646 -0
- package/vendor/mbedtls/library/psa_crypto_aead.h +499 -0
- package/vendor/mbedtls/library/psa_crypto_cipher.c +747 -0
- package/vendor/mbedtls/library/psa_crypto_cipher.h +316 -0
- package/vendor/mbedtls/library/psa_crypto_client.c +22 -0
- package/vendor/mbedtls/library/psa_crypto_core.h +983 -0
- package/vendor/mbedtls/library/psa_crypto_core_common.h +52 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers.h +2896 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.c +256 -0
- package/vendor/mbedtls/library/psa_crypto_driver_wrappers_no_static.h +31 -0
- package/vendor/mbedtls/library/psa_crypto_ecp.c +594 -0
- package/vendor/mbedtls/library/psa_crypto_ecp.h +267 -0
- package/vendor/mbedtls/library/psa_crypto_ffdh.c +361 -0
- package/vendor/mbedtls/library/psa_crypto_ffdh.h +131 -0
- package/vendor/mbedtls/library/psa_crypto_hash.c +470 -0
- package/vendor/mbedtls/library/psa_crypto_hash.h +211 -0
- package/vendor/mbedtls/library/psa_crypto_invasive.h +92 -0
- package/vendor/mbedtls/library/psa_crypto_its.h +131 -0
- package/vendor/mbedtls/library/psa_crypto_mac.c +505 -0
- package/vendor/mbedtls/library/psa_crypto_mac.h +264 -0
- package/vendor/mbedtls/library/psa_crypto_pake.c +571 -0
- package/vendor/mbedtls/library/psa_crypto_pake.h +159 -0
- package/vendor/mbedtls/library/psa_crypto_random.c +181 -0
- package/vendor/mbedtls/library/psa_crypto_random.h +72 -0
- package/vendor/mbedtls/library/psa_crypto_random_impl.h +200 -0
- package/vendor/mbedtls/library/psa_crypto_rsa.c +714 -0
- package/vendor/mbedtls/library/psa_crypto_rsa.h +321 -0
- package/vendor/mbedtls/library/psa_crypto_se.c +373 -0
- package/vendor/mbedtls/library/psa_crypto_se.h +192 -0
- package/vendor/mbedtls/library/psa_crypto_slot_management.c +1137 -0
- package/vendor/mbedtls/library/psa_crypto_slot_management.h +344 -0
- package/vendor/mbedtls/library/psa_crypto_storage.c +481 -0
- package/vendor/mbedtls/library/psa_crypto_storage.h +392 -0
- package/vendor/mbedtls/library/psa_its_file.c +254 -0
- package/vendor/mbedtls/library/psa_util.c +614 -0
- package/vendor/mbedtls/library/psa_util_internal.h +100 -0
- package/vendor/mbedtls/library/ripemd160.c +490 -0
- package/vendor/mbedtls/library/rsa.c +3121 -0
- package/vendor/mbedtls/library/rsa_alt_helpers.c +455 -0
- package/vendor/mbedtls/library/rsa_alt_helpers.h +209 -0
- package/vendor/mbedtls/library/rsa_internal.h +188 -0
- package/vendor/mbedtls/library/sha1.c +480 -0
- package/vendor/mbedtls/library/sha256.c +983 -0
- package/vendor/mbedtls/library/sha3.c +721 -0
- package/vendor/mbedtls/library/sha512.c +1115 -0
- package/vendor/mbedtls/library/ssl_cache.c +410 -0
- package/vendor/mbedtls/library/ssl_ciphersuites.c +2050 -0
- package/vendor/mbedtls/library/ssl_ciphersuites_internal.h +154 -0
- package/vendor/mbedtls/library/ssl_client.c +1023 -0
- package/vendor/mbedtls/library/ssl_client.h +22 -0
- package/vendor/mbedtls/library/ssl_cookie.c +384 -0
- package/vendor/mbedtls/library/ssl_debug_helpers.h +85 -0
- package/vendor/mbedtls/library/ssl_debug_helpers_generated.c +251 -0
- package/vendor/mbedtls/library/ssl_misc.h +3198 -0
- package/vendor/mbedtls/library/ssl_msg.c +6619 -0
- package/vendor/mbedtls/library/ssl_ticket.c +556 -0
- package/vendor/mbedtls/library/ssl_tls.c +10234 -0
- package/vendor/mbedtls/library/ssl_tls12_client.c +3688 -0
- package/vendor/mbedtls/library/ssl_tls12_server.c +4311 -0
- package/vendor/mbedtls/library/ssl_tls13_client.c +3208 -0
- package/vendor/mbedtls/library/ssl_tls13_generic.c +1793 -0
- package/vendor/mbedtls/library/ssl_tls13_invasive.h +23 -0
- package/vendor/mbedtls/library/ssl_tls13_keys.c +1918 -0
- package/vendor/mbedtls/library/ssl_tls13_keys.h +668 -0
- package/vendor/mbedtls/library/ssl_tls13_server.c +3624 -0
- package/vendor/mbedtls/library/threading.c +193 -0
- package/vendor/mbedtls/library/threading_internal.h +28 -0
- package/vendor/mbedtls/library/timing.c +152 -0
- package/vendor/mbedtls/library/version.c +32 -0
- package/vendor/mbedtls/library/version_features.c +856 -0
- package/vendor/mbedtls/library/x509.c +1776 -0
- package/vendor/mbedtls/library/x509_create.c +570 -0
- package/vendor/mbedtls/library/x509_crl.c +708 -0
- package/vendor/mbedtls/library/x509_crt.c +3311 -0
- package/vendor/mbedtls/library/x509_csr.c +648 -0
- package/vendor/mbedtls/library/x509_internal.h +101 -0
- package/vendor/mbedtls/library/x509write.c +174 -0
- package/vendor/mbedtls/library/x509write_crt.c +688 -0
- package/vendor/mbedtls/library/x509write_csr.c +336 -0
- package/vendor/quickjs-ng/CMakeLists.txt +566 -0
- package/vendor/quickjs-ng/LICENSE +24 -0
- package/vendor/quickjs-ng/README.md +24 -0
- package/vendor/quickjs-ng/api-test.c +1195 -0
- package/vendor/quickjs-ng/builtin-array-fromasync.h +119 -0
- package/vendor/quickjs-ng/builtin-iterator-zip-keyed.h +332 -0
- package/vendor/quickjs-ng/builtin-iterator-zip.h +337 -0
- package/vendor/quickjs-ng/cutils.h +1998 -0
- package/vendor/quickjs-ng/dtoa.c +1619 -0
- package/vendor/quickjs-ng/dtoa.h +87 -0
- package/vendor/quickjs-ng/gen/function_source.c +81 -0
- package/vendor/quickjs-ng/gen/hello.c +53 -0
- package/vendor/quickjs-ng/gen/hello_module.c +106 -0
- package/vendor/quickjs-ng/gen/repl.c +3036 -0
- package/vendor/quickjs-ng/gen/standalone.c +323 -0
- package/vendor/quickjs-ng/gen/test_fib.c +81 -0
- package/vendor/quickjs-ng/libregexp-opcode.h +73 -0
- package/vendor/quickjs-ng/libregexp.c +3474 -0
- package/vendor/quickjs-ng/libregexp.h +101 -0
- package/vendor/quickjs-ng/libunicode-table.h +5173 -0
- package/vendor/quickjs-ng/libunicode.c +2069 -0
- package/vendor/quickjs-ng/libunicode.h +172 -0
- package/vendor/quickjs-ng/list.h +107 -0
- package/vendor/quickjs-ng/lre-test.c +52 -0
- package/vendor/quickjs-ng/qjs.c +762 -0
- package/vendor/quickjs-ng/qjsc.c +673 -0
- package/vendor/quickjs-ng/quickjs-atom.h +280 -0
- package/vendor/quickjs-ng/quickjs-c-atomics.h +54 -0
- package/vendor/quickjs-ng/quickjs-libc.c +5037 -0
- package/vendor/quickjs-ng/quickjs-libc.h +87 -0
- package/vendor/quickjs-ng/quickjs-opcode.h +377 -0
- package/vendor/quickjs-ng/quickjs.c +64041 -0
- package/vendor/quickjs-ng/quickjs.h +1447 -0
- package/vendor/quickjs-ng/run-test262.c +2374 -0
- package/vendor/quickjs-ng/unicode_gen.c +3121 -0
- package/vendor/quickjs-ng/unicode_gen_def.h +310 -0
- package/vendor/ryu/LICENSE-Boost +23 -0
- package/vendor/ryu/common.h +114 -0
- package/vendor/ryu/d2s.c +509 -0
- package/vendor/ryu/d2s_full_table.h +367 -0
- package/vendor/ryu/d2s_intrinsics.h +357 -0
- package/vendor/ryu/d2s_small_table.h +186 -0
- package/vendor/ryu/digit_table.h +35 -0
- package/vendor/ryu/ryu.h +46 -0
- package/vendor/zlib/LICENSE +22 -0
- package/vendor/zlib/adler32.c +164 -0
- package/vendor/zlib/compress.c +75 -0
- package/vendor/zlib/crc32.c +1049 -0
- package/vendor/zlib/crc32.h +9446 -0
- package/vendor/zlib/deflate.c +2139 -0
- package/vendor/zlib/deflate.h +377 -0
- package/vendor/zlib/gzclose.c +23 -0
- package/vendor/zlib/gzguts.h +214 -0
- package/vendor/zlib/gzlib.c +582 -0
- package/vendor/zlib/gzread.c +602 -0
- package/vendor/zlib/gzwrite.c +631 -0
- package/vendor/zlib/infback.c +628 -0
- package/vendor/zlib/inffast.c +320 -0
- package/vendor/zlib/inffast.h +11 -0
- package/vendor/zlib/inffixed.h +94 -0
- package/vendor/zlib/inflate.c +1526 -0
- package/vendor/zlib/inflate.h +126 -0
- package/vendor/zlib/inftrees.c +299 -0
- package/vendor/zlib/inftrees.h +62 -0
- package/vendor/zlib/trees.c +1117 -0
- package/vendor/zlib/trees.h +128 -0
- package/vendor/zlib/uncompr.c +85 -0
- package/vendor/zlib/zconf.h +543 -0
- package/vendor/zlib/zlib.h +1938 -0
- package/vendor/zlib/zutil.c +299 -0
- package/vendor/zlib/zutil.h +254 -0
- package/README.md +0 -3
- package/index.js +0 -2
package/src/scr_fetch.c
ADDED
|
@@ -0,0 +1,1130 @@
|
|
|
1
|
+
/* fetch for the dynamic island, over scriptc's OWN net stack — the
|
|
2
|
+
* scr_platform poller + scr_net sockets, scr_http's HTTP/1.1 client
|
|
3
|
+
* parser, scr_tls (vendored mbedTLS) for https, and zlib for response
|
|
4
|
+
* decompression. No libcurl anywhere: the architecture is Node's own
|
|
5
|
+
* (libuv sockets + OpenSSL + undici; ours: poller + mbedTLS + this
|
|
6
|
+
* unit), which is what lets fetch compile for every target the socket
|
|
7
|
+
* units reach — win32 included, where no system-libcurl contract
|
|
8
|
+
* exists. The curl implementation this replaces stays compilable for
|
|
9
|
+
* one release as the reference (scr_fetch_curl.c, selected by
|
|
10
|
+
* SCRIPTC_FETCH_CURL=1 at build time; same install symbol, same island
|
|
11
|
+
* surface, same fixture suite).
|
|
12
|
+
*
|
|
13
|
+
* Architecture (the JS half is UNCHANGED from the curl bridge):
|
|
14
|
+
* - The JS half (fetch_glue below) defines globalThis.fetch over two host
|
|
15
|
+
* functions: host.start(req, cbs) begins a transfer and host.abort(id)
|
|
16
|
+
* cancels one (response-body cancel). fetch() returns a REAL island
|
|
17
|
+
* promise; the Response's body is an island ReadableStream fed by
|
|
18
|
+
* C→engine callbacks as data arrives.
|
|
19
|
+
* - The C half is a fetch-layer client over scr_http's client machinery:
|
|
20
|
+
* one ScrHttpClientReq per hop, minted runtime closures (caps[0] boxes
|
|
21
|
+
* the transfer) as its response/data/end/error listeners, callbacks
|
|
22
|
+
* firing from the net unit's dispatch station — the loop's own poller
|
|
23
|
+
* sleeps on socket readiness, so this unit registers NO poll hook with
|
|
24
|
+
* the island (the curl bridge needed one to sleep on curl's fds).
|
|
25
|
+
* AbortSignal.timeout stays punctual through the loop's island-timer
|
|
26
|
+
* deadline hook (scr_loop_set_island_deadline — armed island timers cap
|
|
27
|
+
* the idle sleep exactly the way the curl poll capped its own).
|
|
28
|
+
* - fetch SEMANTICS, matched to Node/undici: HTTP errors RESOLVE (only
|
|
29
|
+
* network failure rejects, with TypeError "fetch failed" — Node's exact
|
|
30
|
+
* message); redirects are followed IN THIS UNIT (20 hops, fetch's
|
|
31
|
+
* limit; 303 — and 301/302 for POST — rewrite to GET and drop the body
|
|
32
|
+
* and its content-* headers, the fetch spec's rules; authorization is
|
|
33
|
+
* stripped on cross-origin hops; response.url = the final URL without
|
|
34
|
+
* its fragment, response.redirected set; a redirect hop's own body
|
|
35
|
+
* never reaches the island). The request head carries undici's exact
|
|
36
|
+
* default header set in undici's order (host, connection, the user
|
|
37
|
+
* headers, accept, accept-language, sec-fetch-mode, user-agent,
|
|
38
|
+
* accept-encoding — captured from Node 24 on the wire); gzip/zlib
|
|
39
|
+
* response bodies arrive decompressed (accept-encoding advertises
|
|
40
|
+
* "gzip, deflate", and content-encoding: gzip/x-gzip/deflate inflates
|
|
41
|
+
* through zlib's 15+32 auto-detect — raw-deflate servers and br/zstd
|
|
42
|
+
* are out of the slice, honestly: br/zstd are never offered).
|
|
43
|
+
* - DNS: scr_net dials IP literals only (Node's shape for its slice), so
|
|
44
|
+
* this unit resolves hostnames with getaddrinfo AT HOP START — the
|
|
45
|
+
* dns.lookup precedent (scr_dgram.c): synchronous resolution, first
|
|
46
|
+
* answer wins; failures ride the socket's deferred
|
|
47
|
+
* "getaddrinfo ENOTFOUND host" error so the rejection's cause is
|
|
48
|
+
* Node's exact shape. TLS handshakes verify/SNI against the URL
|
|
49
|
+
* HOSTNAME while the socket dials the resolved IP.
|
|
50
|
+
* - Proxies, matched to Node: undici's global fetch IGNORES http_proxy/
|
|
51
|
+
* https_proxy unless NODE_USE_ENV_PROXY=1 opts in (Node 24's
|
|
52
|
+
* EnvHttpProxyAgent). Opted in, http:// targets relay through the
|
|
53
|
+
* proxy as absolute-URI requests (the classic forward-proxy wire form;
|
|
54
|
+
* undici tunnels CONNECT, but the fixture proxy counts either form
|
|
55
|
+
* identically), no_proxy exclusions honored. https-over-proxy
|
|
56
|
+
* (CONNECT) is out of the slice.
|
|
57
|
+
* - AbortSignal is wired exactly as before (init.signal, or the
|
|
58
|
+
* Request's): an already-aborted signal rejects with its reason before
|
|
59
|
+
* any transfer starts; aborting a live transfer destroys the hop's
|
|
60
|
+
* connection through host.abort (silent on the C side — the glue owns
|
|
61
|
+
* the rejection); AbortSignal.timeout's TimeoutError rides the island
|
|
62
|
+
* timer machinery in scr_web.c.
|
|
63
|
+
* - Error causes, Node's shapes: connect ECONNREFUSED ip:port /
|
|
64
|
+
* getaddrinfo ENOTFOUND host pass through from the net layer with
|
|
65
|
+
* their codes; a server that dies before the response head maps to
|
|
66
|
+
* undici's cause exactly — "other side closed", code UND_ERR_SOCKET
|
|
67
|
+
* (the curl bridge could only offer curl's own string there).
|
|
68
|
+
* - Ownership: each transfer is refcounted — the live registry holds +1
|
|
69
|
+
* and every minted listener closure's box holds +1; settling releases
|
|
70
|
+
* the engine callback object and the hop client, and teardown
|
|
71
|
+
* (registered with the island) frees whatever is still live before the
|
|
72
|
+
* engine goes down, so the island audit stays zero. */
|
|
73
|
+
#ifdef SCR_DYNAMIC
|
|
74
|
+
|
|
75
|
+
#include "scr_runtime.h"
|
|
76
|
+
#include "scr_url_internal.h"
|
|
77
|
+
|
|
78
|
+
#include <stdio.h>
|
|
79
|
+
#include <stdlib.h>
|
|
80
|
+
#include <string.h>
|
|
81
|
+
|
|
82
|
+
#include <zlib.h>
|
|
83
|
+
|
|
84
|
+
#include "quickjs.h"
|
|
85
|
+
|
|
86
|
+
static void fx_oom(void) {
|
|
87
|
+
fputs("scriptc: out of memory\n", stderr);
|
|
88
|
+
abort();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ── small string helpers (ScrStr names are not NUL-guaranteed at the
|
|
92
|
+
* lengths we compare, so everything is len-aware, ASCII-case-folded) ── */
|
|
93
|
+
|
|
94
|
+
static bool fx_eq_ci(const char *a, size_t alen, const char *b) {
|
|
95
|
+
size_t blen = strlen(b);
|
|
96
|
+
if (alen != blen) return false;
|
|
97
|
+
for (size_t i = 0; i < alen; i++) {
|
|
98
|
+
char c = a[i];
|
|
99
|
+
if (c >= 'A' && c <= 'Z') c = (char)(c - 'A' + 'a');
|
|
100
|
+
if (c != b[i]) return false;
|
|
101
|
+
}
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static bool fx_str_is(const ScrStr *s, const char *lit) { return fx_eq_ci(s->data, s->len, lit); }
|
|
106
|
+
|
|
107
|
+
/* Does the flat [name, value, ...] pairs array carry `name`? */
|
|
108
|
+
static bool fx_pairs_have(ScrArr *pairs, const char *name) {
|
|
109
|
+
size_t n = (size_t)scr_arr_len(pairs);
|
|
110
|
+
bool found = false;
|
|
111
|
+
for (size_t i = 0; i + 1 < n && !found; i += 2) {
|
|
112
|
+
ScrStr *nm = (ScrStr *)scr_arr_get_ref(pairs, (double)i);
|
|
113
|
+
found = fx_eq_ci(nm->data, nm->len, name);
|
|
114
|
+
scr_str_release(nm);
|
|
115
|
+
}
|
|
116
|
+
return found;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static void fx_pairs_push(ScrArr *pairs, const char *name, const char *value, size_t vlen) {
|
|
120
|
+
scr_arr_push_ref(pairs, scr_str_new(name, strlen(name)));
|
|
121
|
+
scr_arr_push_ref(pairs, scr_str_new(value, vlen));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ── transfers ───────────────────────────────────────────────────────── */
|
|
125
|
+
|
|
126
|
+
typedef struct FxTransfer {
|
|
127
|
+
size_t rc; /* the live registry's +1 plus one per minted listener box */
|
|
128
|
+
int id;
|
|
129
|
+
JSContext *ctx;
|
|
130
|
+
JSValue cbs; /* { onResponse, onData, onEnd, onError } — owned while live */
|
|
131
|
+
bool cbs_live;
|
|
132
|
+
/* the request, as it evolves across redirect hops */
|
|
133
|
+
ScrStr *method; /* owned */
|
|
134
|
+
ScrArr *headers; /* flat [name, value, ...] user pairs — owned */
|
|
135
|
+
ScrBytes *body; /* owned, NULL = none */
|
|
136
|
+
ScrUrl *url; /* the CURRENT hop's URL — owned */
|
|
137
|
+
int hops;
|
|
138
|
+
bool redirected;
|
|
139
|
+
/* the live hop */
|
|
140
|
+
ScrHttpClientReq *client; /* +1, NULL between/after hops */
|
|
141
|
+
bool responded; /* onResponse fired (the final response) */
|
|
142
|
+
bool cancelled; /* island aborted/cancelled: die silently */
|
|
143
|
+
bool done; /* settled: no callback ever fires again */
|
|
144
|
+
/* response decompression */
|
|
145
|
+
bool inflating;
|
|
146
|
+
z_stream zs;
|
|
147
|
+
struct FxTransfer *next;
|
|
148
|
+
} FxTransfer;
|
|
149
|
+
|
|
150
|
+
static FxTransfer *fx_live = NULL; /* registry: +1 each */
|
|
151
|
+
static size_t fx_nlive = 0;
|
|
152
|
+
static int fx_next_id = 1;
|
|
153
|
+
|
|
154
|
+
static FxTransfer *fx_retain(FxTransfer *t) {
|
|
155
|
+
t->rc++;
|
|
156
|
+
return t;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static void fx_release(FxTransfer *t) {
|
|
160
|
+
if (--t->rc > 0) return;
|
|
161
|
+
scr_str_release(t->method);
|
|
162
|
+
scr_arr_release(t->headers);
|
|
163
|
+
if (t->body) scr_bytes_release(t->body);
|
|
164
|
+
if (t->url) scr_url_release(t->url);
|
|
165
|
+
if (t->client) scr_http_client_release(t->client);
|
|
166
|
+
if (t->inflating) inflateEnd(&t->zs);
|
|
167
|
+
if (t->cbs_live) JS_FreeValue(t->ctx, t->cbs);
|
|
168
|
+
free(t);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static void *fx_retain_v(void *p) { return fx_retain((FxTransfer *)p); }
|
|
172
|
+
static void fx_release_v(void *p) { fx_release((FxTransfer *)p); }
|
|
173
|
+
|
|
174
|
+
/* Settle: the transfer is over (delivered, failed, or aborted) — drop the
|
|
175
|
+
* hop client, free the engine callbacks, and leave the registry. Idempotent. */
|
|
176
|
+
static void fx_settle(FxTransfer *t) {
|
|
177
|
+
if (t->done) return;
|
|
178
|
+
t->done = true;
|
|
179
|
+
if (t->client) {
|
|
180
|
+
scr_http_client_release(t->client);
|
|
181
|
+
t->client = NULL;
|
|
182
|
+
}
|
|
183
|
+
if (t->cbs_live) {
|
|
184
|
+
JS_FreeValue(t->ctx, t->cbs);
|
|
185
|
+
t->cbs = JS_UNDEFINED;
|
|
186
|
+
t->cbs_live = false;
|
|
187
|
+
}
|
|
188
|
+
for (FxTransfer **link = &fx_live; *link; link = &(*link)->next) {
|
|
189
|
+
if (*link == t) {
|
|
190
|
+
*link = t->next;
|
|
191
|
+
fx_nlive--;
|
|
192
|
+
fx_release(t); /* the registry's +1 */
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Calls one callback off the cbs object, swallowing (but reporting) any
|
|
199
|
+
* engine exception — the callbacks are our own glue and must not throw.
|
|
200
|
+
* Entered from the net dispatch station (the main stack): re-anchor the
|
|
201
|
+
* engine's stack-overflow check first, the every-island-entry rule. */
|
|
202
|
+
static void fx_call(FxTransfer *t, const char *name, int argc, JSValueConst *argv) {
|
|
203
|
+
if (!t->cbs_live) return;
|
|
204
|
+
scr_island_host_enter();
|
|
205
|
+
JSContext *ctx = t->ctx;
|
|
206
|
+
JSValue fn = JS_GetPropertyStr(ctx, t->cbs, name);
|
|
207
|
+
JSValue r = JS_Call(ctx, fn, JS_UNDEFINED, argc, argv);
|
|
208
|
+
JS_FreeValue(ctx, fn);
|
|
209
|
+
if (JS_IsException(r)) {
|
|
210
|
+
JSValue e = JS_GetException(ctx);
|
|
211
|
+
const char *msg = JS_ToCString(ctx, e);
|
|
212
|
+
fprintf(stderr, "scriptc: fetch internal callback '%s' threw: %s\n", name,
|
|
213
|
+
msg ? msg : "?");
|
|
214
|
+
if (msg) JS_FreeCString(ctx, msg);
|
|
215
|
+
JS_FreeValue(ctx, e);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
JS_FreeValue(ctx, r);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* Network failure → onError(detail, code) → the glue's TypeError "fetch
|
|
222
|
+
* failed" with the classified cause. Settles the transfer. */
|
|
223
|
+
static void fx_error(FxTransfer *t, const char *detail, const char *code) {
|
|
224
|
+
if (t->done || t->cancelled) {
|
|
225
|
+
fx_settle(t);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
JSContext *ctx = t->ctx;
|
|
229
|
+
JSValue args[2];
|
|
230
|
+
args[0] = JS_NewString(ctx, detail);
|
|
231
|
+
args[1] = code ? JS_NewString(ctx, code) : JS_UNDEFINED;
|
|
232
|
+
fx_call(t, "onError", 2, (JSValueConst *)args);
|
|
233
|
+
JS_FreeValue(ctx, args[0]);
|
|
234
|
+
JS_FreeValue(ctx, args[1]);
|
|
235
|
+
fx_settle(t);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* ── minted listener closures (caps[0] boxes the transfer) ───────────── */
|
|
239
|
+
|
|
240
|
+
static ScrClosure *fx_closure(FxTransfer *t, void *fn) {
|
|
241
|
+
/* fn doubles as the closure's own entry: zero-payload lists (req 'end')
|
|
242
|
+
* call cb->fn(cb) directly, payload lists call the fn stored beside the
|
|
243
|
+
* registration — both routes land on the same handler here. */
|
|
244
|
+
ScrClosure *cb = scr_closure_new(fn, 1);
|
|
245
|
+
ScrBox *box = scr_box_new_obj(&fx_retain_v, &fx_release_v, NULL);
|
|
246
|
+
scr_box_set_ref(box, fx_retain(t));
|
|
247
|
+
cb->caps[0] = box;
|
|
248
|
+
return cb;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/* +1 — release after use. */
|
|
252
|
+
static FxTransfer *fx_from(ScrClosure *cb) { return (FxTransfer *)scr_box_get_ref(cb->caps[0]); }
|
|
253
|
+
|
|
254
|
+
/* ── URL helpers ─────────────────────────────────────────────────────── */
|
|
255
|
+
|
|
256
|
+
/* scheme://[userinfo@]host[:port]path[?query][#fragment] — response.url
|
|
257
|
+
* and the proxy's absolute-URI form exclude the fragment (Node). */
|
|
258
|
+
static ScrStr *fx_url_serialize(const ScrUrl *u, bool with_fragment) {
|
|
259
|
+
size_t cap = u->scheme->len + u->userinfo->len + u->host->len + u->port->len +
|
|
260
|
+
u->path->len + u->query->len + u->fragment->len + 8;
|
|
261
|
+
char *buf = malloc(cap);
|
|
262
|
+
if (!buf) fx_oom();
|
|
263
|
+
size_t n = 0;
|
|
264
|
+
memcpy(buf + n, u->scheme->data, u->scheme->len);
|
|
265
|
+
n += u->scheme->len;
|
|
266
|
+
buf[n++] = ':';
|
|
267
|
+
if (u->has_authority) {
|
|
268
|
+
buf[n++] = '/';
|
|
269
|
+
buf[n++] = '/';
|
|
270
|
+
if (u->userinfo->len > 0) {
|
|
271
|
+
memcpy(buf + n, u->userinfo->data, u->userinfo->len);
|
|
272
|
+
n += u->userinfo->len;
|
|
273
|
+
buf[n++] = '@';
|
|
274
|
+
}
|
|
275
|
+
memcpy(buf + n, u->host->data, u->host->len);
|
|
276
|
+
n += u->host->len;
|
|
277
|
+
if (u->port->len > 0) {
|
|
278
|
+
buf[n++] = ':';
|
|
279
|
+
memcpy(buf + n, u->port->data, u->port->len);
|
|
280
|
+
n += u->port->len;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (u->path->len > 0) {
|
|
284
|
+
memcpy(buf + n, u->path->data, u->path->len);
|
|
285
|
+
n += u->path->len;
|
|
286
|
+
} else {
|
|
287
|
+
buf[n++] = '/';
|
|
288
|
+
}
|
|
289
|
+
memcpy(buf + n, u->query->data, u->query->len);
|
|
290
|
+
n += u->query->len;
|
|
291
|
+
if (with_fragment) {
|
|
292
|
+
memcpy(buf + n, u->fragment->data, u->fragment->len);
|
|
293
|
+
n += u->fragment->len;
|
|
294
|
+
}
|
|
295
|
+
ScrStr *out = scr_str_new(buf, n);
|
|
296
|
+
free(buf);
|
|
297
|
+
return out;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* Parse an absolute URL, answering NULL (static exception CLEARED) instead
|
|
301
|
+
* of throwing — this unit runs inside engine host calls and the net
|
|
302
|
+
* dispatch, where a pending static exception belongs to nobody. */
|
|
303
|
+
static ScrUrl *fx_url_parse(ScrStr *s) {
|
|
304
|
+
ScrUrl *u = scr_url_new(s);
|
|
305
|
+
if (!u) scr_exc_clear();
|
|
306
|
+
return u;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* Resolve a Location header against the current hop's URL. Handles the
|
|
310
|
+
* absolute form plus the relative shapes real servers send (//authority,
|
|
311
|
+
* /rooted, ?query, plain relative); everything reparses through the
|
|
312
|
+
* WHATWG parser so dot segments and encoding normalize consistently. */
|
|
313
|
+
static ScrUrl *fx_resolve(const ScrUrl *base, const ScrStr *loc) {
|
|
314
|
+
ScrStr *abs_try = scr_str_new(loc->data, loc->len);
|
|
315
|
+
ScrUrl *u = fx_url_parse(abs_try);
|
|
316
|
+
scr_str_release(abs_try);
|
|
317
|
+
if (u) return u;
|
|
318
|
+
/* relative: assemble scheme://authority + resolved path/query */
|
|
319
|
+
size_t cap = base->scheme->len + base->userinfo->len + base->host->len + base->port->len +
|
|
320
|
+
base->path->len + base->query->len + loc->len + 16;
|
|
321
|
+
char *buf = malloc(cap);
|
|
322
|
+
if (!buf) fx_oom();
|
|
323
|
+
size_t n = 0;
|
|
324
|
+
memcpy(buf + n, base->scheme->data, base->scheme->len);
|
|
325
|
+
n += base->scheme->len;
|
|
326
|
+
buf[n++] = ':';
|
|
327
|
+
if (loc->len >= 2 && loc->data[0] == '/' && loc->data[1] == '/') {
|
|
328
|
+
memcpy(buf + n, loc->data, loc->len);
|
|
329
|
+
n += loc->len;
|
|
330
|
+
} else {
|
|
331
|
+
buf[n++] = '/';
|
|
332
|
+
buf[n++] = '/';
|
|
333
|
+
if (base->userinfo->len > 0) {
|
|
334
|
+
memcpy(buf + n, base->userinfo->data, base->userinfo->len);
|
|
335
|
+
n += base->userinfo->len;
|
|
336
|
+
buf[n++] = '@';
|
|
337
|
+
}
|
|
338
|
+
memcpy(buf + n, base->host->data, base->host->len);
|
|
339
|
+
n += base->host->len;
|
|
340
|
+
if (base->port->len > 0) {
|
|
341
|
+
buf[n++] = ':';
|
|
342
|
+
memcpy(buf + n, base->port->data, base->port->len);
|
|
343
|
+
n += base->port->len;
|
|
344
|
+
}
|
|
345
|
+
if (loc->len > 0 && loc->data[0] == '/') {
|
|
346
|
+
memcpy(buf + n, loc->data, loc->len);
|
|
347
|
+
n += loc->len;
|
|
348
|
+
} else if (loc->len > 0 && loc->data[0] == '?') {
|
|
349
|
+
memcpy(buf + n, base->path->data, base->path->len);
|
|
350
|
+
n += base->path->len;
|
|
351
|
+
memcpy(buf + n, loc->data, loc->len);
|
|
352
|
+
n += loc->len;
|
|
353
|
+
} else {
|
|
354
|
+
/* plain relative: replace everything after the path's last '/' */
|
|
355
|
+
size_t keep = 0;
|
|
356
|
+
for (size_t i = 0; i < base->path->len; i++) {
|
|
357
|
+
if (base->path->data[i] == '/') keep = i + 1;
|
|
358
|
+
}
|
|
359
|
+
memcpy(buf + n, base->path->data, keep);
|
|
360
|
+
n += keep;
|
|
361
|
+
if (keep == 0) buf[n++] = '/';
|
|
362
|
+
memcpy(buf + n, loc->data, loc->len);
|
|
363
|
+
n += loc->len;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
ScrStr *s = scr_str_new(buf, n);
|
|
367
|
+
free(buf);
|
|
368
|
+
ScrUrl *out = fx_url_parse(s);
|
|
369
|
+
scr_str_release(s);
|
|
370
|
+
return out;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* The URL host with IPv6 brackets stripped (the dial/SNI form). +1. */
|
|
374
|
+
static ScrStr *fx_bare_host(const ScrStr *host) {
|
|
375
|
+
if (host->len >= 2 && host->data[0] == '[' && host->data[host->len - 1] == ']') {
|
|
376
|
+
return scr_str_new(host->data + 1, host->len - 2);
|
|
377
|
+
}
|
|
378
|
+
return scr_str_retain((ScrStr *)host);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
static int fx_url_port(const ScrUrl *u, int deflt) {
|
|
382
|
+
if (u->port->len == 0) return deflt;
|
|
383
|
+
int p = 0;
|
|
384
|
+
for (size_t i = 0; i < u->port->len; i++) p = p * 10 + (u->port->data[i] - '0');
|
|
385
|
+
return p;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* ── env proxy (NODE_USE_ENV_PROXY=1, undici's EnvHttpProxyAgent) ────── */
|
|
389
|
+
|
|
390
|
+
static const char *fx_env2(const char *lower, const char *upper) {
|
|
391
|
+
const char *v = getenv(lower);
|
|
392
|
+
if (v == NULL || v[0] == '\0') v = getenv(upper);
|
|
393
|
+
return (v != NULL && v[0] != '\0') ? v : NULL;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/* no_proxy: comma/space-separated host suffixes; "*" excludes everything;
|
|
397
|
+
* a leading dot is stripped; entries match the host exactly or at a dot
|
|
398
|
+
* boundary. Port qualifiers (host:port) require the port to match. */
|
|
399
|
+
static bool fx_no_proxy_match(const char *list, const ScrStr *host, int port) {
|
|
400
|
+
const char *p = list;
|
|
401
|
+
while (*p) {
|
|
402
|
+
while (*p == ',' || *p == ' ' || *p == '\t') p++;
|
|
403
|
+
const char *start = p;
|
|
404
|
+
while (*p && *p != ',' && *p != ' ' && *p != '\t') p++;
|
|
405
|
+
size_t len = (size_t)(p - start);
|
|
406
|
+
if (len == 0) continue;
|
|
407
|
+
if (len == 1 && start[0] == '*') return true;
|
|
408
|
+
/* split a :port qualifier */
|
|
409
|
+
size_t hlen = len;
|
|
410
|
+
long eport = -1;
|
|
411
|
+
for (size_t i = 0; i < len; i++) {
|
|
412
|
+
if (start[i] == ':') {
|
|
413
|
+
hlen = i;
|
|
414
|
+
eport = strtol(start + i + 1, NULL, 10);
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (hlen > 0 && start[0] == '.') {
|
|
419
|
+
start++;
|
|
420
|
+
hlen--;
|
|
421
|
+
}
|
|
422
|
+
if (hlen == 0) continue;
|
|
423
|
+
if (eport >= 0 && eport != port) continue;
|
|
424
|
+
if (host->len == hlen) {
|
|
425
|
+
bool eq = true;
|
|
426
|
+
for (size_t i = 0; i < hlen && eq; i++) {
|
|
427
|
+
char a = host->data[i], b = start[i];
|
|
428
|
+
if (a >= 'A' && a <= 'Z') a = (char)(a - 'A' + 'a');
|
|
429
|
+
if (b >= 'A' && b <= 'Z') b = (char)(b - 'A' + 'a');
|
|
430
|
+
eq = a == b;
|
|
431
|
+
}
|
|
432
|
+
if (eq) return true;
|
|
433
|
+
} else if (host->len > hlen && host->data[host->len - hlen - 1] == '.') {
|
|
434
|
+
bool eq = true;
|
|
435
|
+
for (size_t i = 0; i < hlen && eq; i++) {
|
|
436
|
+
char a = host->data[host->len - hlen + i], b = start[i];
|
|
437
|
+
if (a >= 'A' && a <= 'Z') a = (char)(a - 'A' + 'a');
|
|
438
|
+
if (b >= 'A' && b <= 'Z') b = (char)(b - 'A' + 'a');
|
|
439
|
+
eq = a == b;
|
|
440
|
+
}
|
|
441
|
+
if (eq) return true;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/* The proxy for this hop's target, parsed (+1), or NULL for direct. */
|
|
448
|
+
static ScrUrl *fx_proxy_for(const ScrUrl *target, bool https, int target_port) {
|
|
449
|
+
const char *optin = getenv("NODE_USE_ENV_PROXY");
|
|
450
|
+
if (optin == NULL || strcmp(optin, "1") != 0) return NULL;
|
|
451
|
+
const char *proxy = https ? fx_env2("https_proxy", "HTTPS_PROXY")
|
|
452
|
+
: fx_env2("http_proxy", "HTTP_PROXY");
|
|
453
|
+
if (proxy == NULL) return NULL;
|
|
454
|
+
const char *no = fx_env2("no_proxy", "NO_PROXY");
|
|
455
|
+
if (no != NULL && fx_no_proxy_match(no, target->host, target_port)) return NULL;
|
|
456
|
+
ScrStr *ps = scr_str_new(proxy, strlen(proxy));
|
|
457
|
+
ScrUrl *u = fx_url_parse(ps);
|
|
458
|
+
scr_str_release(ps);
|
|
459
|
+
return u;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/* ── DNS (the dns.lookup precedent: getaddrinfo at hop start) ────────── */
|
|
463
|
+
|
|
464
|
+
/* The address to DIAL for `host` (+1): brackets strip, then the shared
|
|
465
|
+
* blocking lookup (scr_net.c) — IP literals and localhost pass through,
|
|
466
|
+
* hostnames resolve first-answer, and resolution failure answers the
|
|
467
|
+
* HOSTNAME unchanged so the dial's deferred "getaddrinfo ENOTFOUND host"
|
|
468
|
+
* error is Node's exact cause. */
|
|
469
|
+
static ScrStr *fx_dial_host(const ScrStr *host) {
|
|
470
|
+
ScrStr *bare = fx_bare_host(host);
|
|
471
|
+
ScrStr *out = scr_net_blocking_lookup(bare);
|
|
472
|
+
scr_str_release(bare);
|
|
473
|
+
return out;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* ── the hop ─────────────────────────────────────────────────────────── */
|
|
477
|
+
|
|
478
|
+
static void fx_on_response(ScrClosure *cb, ScrHttpReq *res /*+1*/);
|
|
479
|
+
static void fx_on_client_error(ScrClosure *cb, ScrStr *msg /*borrowed*/);
|
|
480
|
+
|
|
481
|
+
static void fx_start_hop(FxTransfer *t) {
|
|
482
|
+
ScrUrl *u = t->url;
|
|
483
|
+
bool https = fx_str_is(u->scheme, "https");
|
|
484
|
+
int default_port = https ? 443 : 80;
|
|
485
|
+
int port = fx_url_port(u, default_port);
|
|
486
|
+
ScrUrl *proxy = https ? NULL : fx_proxy_for(u, https, port);
|
|
487
|
+
|
|
488
|
+
/* undici's request head, in undici's order: host, connection, the user
|
|
489
|
+
* headers, then the fetch defaults for whatever the user left unset. */
|
|
490
|
+
size_t nuser = (size_t)scr_arr_len(t->headers);
|
|
491
|
+
ScrArr *pairs = scr_arr_new(SCR_ELEM_STR, nuser + 16);
|
|
492
|
+
if (!fx_pairs_have(t->headers, "host")) {
|
|
493
|
+
char authority[300];
|
|
494
|
+
int alen;
|
|
495
|
+
if (port != default_port) {
|
|
496
|
+
alen = snprintf(authority, sizeof authority, "%.*s:%d", (int)u->host->len, u->host->data, port);
|
|
497
|
+
} else {
|
|
498
|
+
alen = snprintf(authority, sizeof authority, "%.*s", (int)u->host->len, u->host->data);
|
|
499
|
+
}
|
|
500
|
+
fx_pairs_push(pairs, "host", authority, (size_t)alen);
|
|
501
|
+
}
|
|
502
|
+
if (!fx_pairs_have(t->headers, "connection")) {
|
|
503
|
+
fx_pairs_push(pairs, "connection", "keep-alive", 10);
|
|
504
|
+
}
|
|
505
|
+
for (size_t i = 0; i + 1 < nuser; i += 2) {
|
|
506
|
+
scr_arr_push_ref(pairs, scr_arr_get_ref(t->headers, (double)i));
|
|
507
|
+
scr_arr_push_ref(pairs, scr_arr_get_ref(t->headers, (double)(i + 1)));
|
|
508
|
+
}
|
|
509
|
+
if (!fx_pairs_have(t->headers, "accept")) fx_pairs_push(pairs, "accept", "*/*", 3);
|
|
510
|
+
if (!fx_pairs_have(t->headers, "accept-language")) fx_pairs_push(pairs, "accept-language", "*", 1);
|
|
511
|
+
if (!fx_pairs_have(t->headers, "sec-fetch-mode")) fx_pairs_push(pairs, "sec-fetch-mode", "cors", 4);
|
|
512
|
+
if (!fx_pairs_have(t->headers, "user-agent")) fx_pairs_push(pairs, "user-agent", "node", 4);
|
|
513
|
+
if (!fx_pairs_have(t->headers, "accept-encoding")) {
|
|
514
|
+
fx_pairs_push(pairs, "accept-encoding", "gzip, deflate", 13);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/* the request-target and the wire to dial */
|
|
518
|
+
ScrStr *path;
|
|
519
|
+
ScrStr *dial;
|
|
520
|
+
int dial_port;
|
|
521
|
+
if (proxy != NULL) {
|
|
522
|
+
path = fx_url_serialize(u, false); /* absolute-URI through the proxy */
|
|
523
|
+
dial = fx_dial_host(proxy->host);
|
|
524
|
+
dial_port = fx_url_port(proxy, 80);
|
|
525
|
+
} else {
|
|
526
|
+
if (u->query->len > 0) {
|
|
527
|
+
size_t plen = (u->path->len > 0 ? u->path->len : 1) + u->query->len;
|
|
528
|
+
char *pb = malloc(plen);
|
|
529
|
+
if (!pb) fx_oom();
|
|
530
|
+
size_t n = 0;
|
|
531
|
+
if (u->path->len > 0) {
|
|
532
|
+
memcpy(pb, u->path->data, u->path->len);
|
|
533
|
+
n = u->path->len;
|
|
534
|
+
} else {
|
|
535
|
+
pb[n++] = '/';
|
|
536
|
+
}
|
|
537
|
+
memcpy(pb + n, u->query->data, u->query->len);
|
|
538
|
+
n += u->query->len;
|
|
539
|
+
path = scr_str_new(pb, n);
|
|
540
|
+
free(pb);
|
|
541
|
+
} else {
|
|
542
|
+
path = u->path->len > 0 ? scr_str_retain(u->path) : scr_str_new("/", 1);
|
|
543
|
+
}
|
|
544
|
+
dial = fx_dial_host(u->host);
|
|
545
|
+
dial_port = port;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
ScrHttpClientReq *c;
|
|
549
|
+
if (https) {
|
|
550
|
+
ScrStr *sni = fx_bare_host(u->host);
|
|
551
|
+
void *cli = scr_tls_fetch_client_ctx(sni, true);
|
|
552
|
+
scr_str_release(sni);
|
|
553
|
+
c = scr_http_request_ex(dial, dial_port, path, t->method, 0, pairs, false, NULL, NULL,
|
|
554
|
+
443, &scr_tls_fetch_client_wrap, cli);
|
|
555
|
+
} else {
|
|
556
|
+
c = scr_http_request_ex(dial, dial_port, path, t->method, 0, pairs, false, NULL, NULL,
|
|
557
|
+
80, NULL, NULL);
|
|
558
|
+
}
|
|
559
|
+
scr_str_release(dial);
|
|
560
|
+
scr_str_release(path);
|
|
561
|
+
scr_arr_release(pairs);
|
|
562
|
+
if (proxy) scr_url_release(proxy);
|
|
563
|
+
|
|
564
|
+
t->client = c; /* the constructor's +1 */
|
|
565
|
+
scr_http_client_on_response(c, fx_closure(t, (void *)&fx_on_response), &fx_on_response, true);
|
|
566
|
+
scr_http_client_on_error(c, fx_closure(t, (void *)&fx_on_client_error), &fx_on_client_error, false);
|
|
567
|
+
if (t->body != NULL) scr_http_client_end_bytes(c, t->body);
|
|
568
|
+
else scr_http_client_end(c);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/* ── redirects ───────────────────────────────────────────────────────── */
|
|
572
|
+
|
|
573
|
+
static void fx_strip_header(ScrArr **headers, const char *name) {
|
|
574
|
+
ScrArr *old = *headers;
|
|
575
|
+
size_t n = (size_t)scr_arr_len(old);
|
|
576
|
+
ScrArr *out = scr_arr_new(SCR_ELEM_STR, n);
|
|
577
|
+
for (size_t i = 0; i + 1 < n; i += 2) {
|
|
578
|
+
ScrStr *nm = (ScrStr *)scr_arr_get_ref(old, (double)i);
|
|
579
|
+
if (fx_eq_ci(nm->data, nm->len, name)) {
|
|
580
|
+
scr_str_release(nm);
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
scr_arr_push_ref(out, nm);
|
|
584
|
+
scr_arr_push_ref(out, scr_arr_get_ref(old, (double)(i + 1)));
|
|
585
|
+
}
|
|
586
|
+
scr_arr_release(old);
|
|
587
|
+
*headers = out;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* Follows one redirect hop: rewrites the request per the fetch spec and
|
|
591
|
+
* dials the next URL. Consumes nothing; the caller drops res/client. */
|
|
592
|
+
static bool fx_redirect(FxTransfer *t, int status, const ScrStr *loc) {
|
|
593
|
+
if (t->hops >= 20) {
|
|
594
|
+
fx_error(t, "redirect count exceeded", NULL);
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
t->hops++;
|
|
598
|
+
t->redirected = true;
|
|
599
|
+
ScrUrl *next = fx_resolve(t->url, loc);
|
|
600
|
+
if (next == NULL ||
|
|
601
|
+
!(fx_str_is(next->scheme, "http") || fx_str_is(next->scheme, "https"))) {
|
|
602
|
+
if (next) scr_url_release(next);
|
|
603
|
+
fx_error(t, "invalid redirect URL", NULL);
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
/* 303 rewrites everything but GET/HEAD to GET; 301/302 rewrite POST —
|
|
607
|
+
* the body and its content-* headers drop with the rewrite. */
|
|
608
|
+
bool is_get = fx_str_is(t->method, "GET");
|
|
609
|
+
bool is_head = fx_str_is(t->method, "HEAD");
|
|
610
|
+
if ((status == 303 && !is_get && !is_head) ||
|
|
611
|
+
((status == 301 || status == 302) && fx_str_is(t->method, "POST"))) {
|
|
612
|
+
scr_str_release(t->method);
|
|
613
|
+
t->method = scr_str_new("GET", 3);
|
|
614
|
+
if (t->body) {
|
|
615
|
+
scr_bytes_release(t->body);
|
|
616
|
+
t->body = NULL;
|
|
617
|
+
}
|
|
618
|
+
fx_strip_header(&t->headers, "content-type");
|
|
619
|
+
fx_strip_header(&t->headers, "content-length");
|
|
620
|
+
fx_strip_header(&t->headers, "content-encoding");
|
|
621
|
+
fx_strip_header(&t->headers, "content-language");
|
|
622
|
+
fx_strip_header(&t->headers, "content-location");
|
|
623
|
+
}
|
|
624
|
+
/* cross-origin hop: credentials do not follow (the fetch spec's
|
|
625
|
+
* authorization rule; cookies are not modeled as ambient state). */
|
|
626
|
+
bool same_origin = t->url->host->len == next->host->len &&
|
|
627
|
+
memcmp(t->url->host->data, next->host->data, next->host->len) == 0 &&
|
|
628
|
+
fx_url_port(t->url, 0) == fx_url_port(next, 0) &&
|
|
629
|
+
t->url->scheme->len == next->scheme->len &&
|
|
630
|
+
memcmp(t->url->scheme->data, next->scheme->data, next->scheme->len) == 0;
|
|
631
|
+
if (!same_origin) {
|
|
632
|
+
fx_strip_header(&t->headers, "authorization");
|
|
633
|
+
fx_strip_header(&t->headers, "proxy-authorization");
|
|
634
|
+
fx_strip_header(&t->headers, "cookie");
|
|
635
|
+
}
|
|
636
|
+
scr_url_release(t->url);
|
|
637
|
+
t->url = next;
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/* ── response delivery ───────────────────────────────────────────────── */
|
|
642
|
+
|
|
643
|
+
static void fx_emit_chunk(FxTransfer *t, const uint8_t *data, size_t len) {
|
|
644
|
+
if (len == 0) return;
|
|
645
|
+
JSValue chunk = JS_NewUint8ArrayCopy(t->ctx, data, len);
|
|
646
|
+
fx_call(t, "onData", 1, (JSValueConst *)&chunk);
|
|
647
|
+
JS_FreeValue(t->ctx, chunk);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
static void fx_on_data(ScrClosure *cb, ScrBytes *chunk /*borrowed*/) {
|
|
651
|
+
FxTransfer *t = fx_from(cb);
|
|
652
|
+
if (t == NULL) return;
|
|
653
|
+
if (t->done || t->cancelled || !t->responded) {
|
|
654
|
+
fx_release(t);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
if (!t->inflating) {
|
|
658
|
+
fx_emit_chunk(t, chunk->data, chunk->len);
|
|
659
|
+
fx_release(t);
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
t->zs.next_in = (Bytef *)chunk->data;
|
|
663
|
+
t->zs.avail_in = (uInt)chunk->len;
|
|
664
|
+
unsigned char out[16384];
|
|
665
|
+
while (t->zs.avail_in > 0 && !t->done) {
|
|
666
|
+
t->zs.next_out = out;
|
|
667
|
+
t->zs.avail_out = sizeof out;
|
|
668
|
+
int r = inflate(&t->zs, Z_NO_FLUSH);
|
|
669
|
+
size_t produced = sizeof out - t->zs.avail_out;
|
|
670
|
+
if (produced > 0) fx_emit_chunk(t, out, produced);
|
|
671
|
+
if (r == Z_STREAM_END) break; /* trailing bytes (if any) are dropped */
|
|
672
|
+
if (r != Z_OK && r != Z_BUF_ERROR) {
|
|
673
|
+
/* corrupt encoding: the body errors (the glue turns a post-resolve
|
|
674
|
+
* onError into controller.error — undici's terminated shape) */
|
|
675
|
+
const char *detail = t->zs.msg ? t->zs.msg : "invalid compressed body";
|
|
676
|
+
ScrHttpClientReq *c = t->client;
|
|
677
|
+
if (c) scr_http_client_destroy(c);
|
|
678
|
+
fx_error(t, detail, NULL);
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
681
|
+
if (r == Z_BUF_ERROR && produced == 0) break; /* need more input */
|
|
682
|
+
}
|
|
683
|
+
fx_release(t);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
static void fx_on_end(ScrClosure *cb) {
|
|
687
|
+
FxTransfer *t = fx_from(cb);
|
|
688
|
+
if (t == NULL) return;
|
|
689
|
+
if (t->done || t->cancelled) {
|
|
690
|
+
fx_release(t);
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
fx_call(t, "onEnd", 0, NULL);
|
|
694
|
+
fx_settle(t);
|
|
695
|
+
fx_release(t);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/* Mid-body death ('aborted' on the response): the body errors. */
|
|
699
|
+
static void fx_on_res_error(ScrClosure *cb, ScrStr *msg /*borrowed*/) {
|
|
700
|
+
FxTransfer *t = fx_from(cb);
|
|
701
|
+
if (t == NULL) return;
|
|
702
|
+
if (t->done || t->cancelled) {
|
|
703
|
+
fx_release(t);
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
fx_error(t, msg->len > 0 ? msg->data : "aborted", NULL);
|
|
707
|
+
fx_release(t);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
static void fx_on_response(ScrClosure *cb, ScrHttpReq *res /*+1*/) {
|
|
711
|
+
FxTransfer *t = fx_from(cb);
|
|
712
|
+
if (t == NULL) {
|
|
713
|
+
scr_http_req_release(res);
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
if (t->done || t->cancelled) {
|
|
717
|
+
scr_http_req_release(res);
|
|
718
|
+
fx_release(t);
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
int status = (int)scr_http_req_status(res);
|
|
722
|
+
|
|
723
|
+
/* a redirect hop? (Location present, a redirect status) */
|
|
724
|
+
if (status == 301 || status == 302 || status == 303 || status == 307 || status == 308) {
|
|
725
|
+
ScrStr *locname = scr_str_new("location", 8);
|
|
726
|
+
ScrStr *loc = scr_http_req_header(res, locname);
|
|
727
|
+
scr_str_release(locname);
|
|
728
|
+
if (loc != NULL) {
|
|
729
|
+
/* drop this hop's connection (its body never reaches the island) */
|
|
730
|
+
ScrHttpClientReq *old = t->client;
|
|
731
|
+
t->client = NULL;
|
|
732
|
+
bool go = fx_redirect(t, status, loc);
|
|
733
|
+
scr_str_release(loc);
|
|
734
|
+
if (old) {
|
|
735
|
+
scr_http_client_destroy(old);
|
|
736
|
+
scr_http_client_release(old);
|
|
737
|
+
}
|
|
738
|
+
if (go) fx_start_hop(t);
|
|
739
|
+
scr_http_req_release(res);
|
|
740
|
+
fx_release(t);
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
/* a FINAL 3xx (no Location) resolves with its own body, like Node —
|
|
744
|
+
* the curl bridge documented this corner away; this unit delivers it */
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
t->responded = true;
|
|
748
|
+
|
|
749
|
+
/* content-encoding: gzip/x-gzip/deflate inflate transparently (zlib's
|
|
750
|
+
* 15+32 auto-detects the gzip and zlib framings) */
|
|
751
|
+
{
|
|
752
|
+
ScrStr *cename = scr_str_new("content-encoding", 16);
|
|
753
|
+
ScrStr *ce = scr_http_req_header(res, cename);
|
|
754
|
+
scr_str_release(cename);
|
|
755
|
+
if (ce != NULL) {
|
|
756
|
+
if (fx_str_is(ce, "gzip") || fx_str_is(ce, "x-gzip") || fx_str_is(ce, "deflate")) {
|
|
757
|
+
memset(&t->zs, 0, sizeof t->zs);
|
|
758
|
+
if (inflateInit2(&t->zs, 15 + 32) == Z_OK) t->inflating = true;
|
|
759
|
+
}
|
|
760
|
+
scr_str_release(ce);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
JSContext *ctx = t->ctx;
|
|
765
|
+
ScrArr *raw = scr_http_req_raw_headers(res);
|
|
766
|
+
size_t nraw = (size_t)scr_arr_len(raw);
|
|
767
|
+
JSValue hdrs = JS_NewArray(ctx);
|
|
768
|
+
for (size_t i = 0; i < nraw; i++) {
|
|
769
|
+
ScrStr *s = (ScrStr *)scr_arr_get_ref(raw, (double)i);
|
|
770
|
+
JS_SetPropertyUint32(ctx, hdrs, (uint32_t)i, JS_NewStringLen(ctx, s->data, s->len));
|
|
771
|
+
scr_str_release(s);
|
|
772
|
+
}
|
|
773
|
+
scr_arr_release(raw);
|
|
774
|
+
ScrStr *stext = scr_http_req_status_message(res);
|
|
775
|
+
ScrStr *final_url = fx_url_serialize(t->url, false);
|
|
776
|
+
JSValue argv[5] = {
|
|
777
|
+
JS_NewInt32(ctx, status),
|
|
778
|
+
JS_NewStringLen(ctx, stext ? stext->data : "", stext ? stext->len : 0),
|
|
779
|
+
hdrs,
|
|
780
|
+
JS_NewStringLen(ctx, final_url->data, final_url->len),
|
|
781
|
+
JS_NewBool(ctx, t->redirected),
|
|
782
|
+
};
|
|
783
|
+
if (stext) scr_str_release(stext);
|
|
784
|
+
scr_str_release(final_url);
|
|
785
|
+
fx_call(t, "onResponse", 5, argv);
|
|
786
|
+
for (int i = 0; i < 5; i++) JS_FreeValue(ctx, argv[i]);
|
|
787
|
+
|
|
788
|
+
/* body listeners (registered inside the 'response' emit — the parser
|
|
789
|
+
* delivers body bytes only after this returns, ended bodies fire 'end'
|
|
790
|
+
* right behind us) */
|
|
791
|
+
scr_http_req_on_data(res, fx_closure(t, (void *)&fx_on_data), &fx_on_data, false);
|
|
792
|
+
scr_http_req_on_end(res, fx_closure(t, (void *)&fx_on_end), false);
|
|
793
|
+
scr_http_req_on_error(res, fx_closure(t, (void *)&fx_on_res_error), &fx_on_res_error, false);
|
|
794
|
+
|
|
795
|
+
scr_http_req_release(res);
|
|
796
|
+
fx_release(t);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/* Pre-response failure on the hop client: classify into Node's causes. */
|
|
800
|
+
static void fx_on_client_error(ScrClosure *cb, ScrStr *msg /*borrowed*/) {
|
|
801
|
+
FxTransfer *t = fx_from(cb);
|
|
802
|
+
if (t == NULL) return;
|
|
803
|
+
if (t->done || t->cancelled || t->responded) {
|
|
804
|
+
fx_release(t);
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
const char *detail = msg->data;
|
|
808
|
+
const char *code = NULL;
|
|
809
|
+
char codebuf[32];
|
|
810
|
+
if (msg->len > 8 && memcmp(detail, "connect E", 9) == 0) {
|
|
811
|
+
/* "connect ECONNREFUSED ip:port" and family: the code is the token */
|
|
812
|
+
const char *s = detail + 8;
|
|
813
|
+
size_t n = 0;
|
|
814
|
+
while (s[n] != '\0' && s[n] != ' ' && n < sizeof codebuf - 1) n++;
|
|
815
|
+
memcpy(codebuf, s, n);
|
|
816
|
+
codebuf[n] = '\0';
|
|
817
|
+
code = codebuf;
|
|
818
|
+
} else if (msg->len > 12 && memcmp(detail, "getaddrinfo E", 13) == 0) {
|
|
819
|
+
const char *s = detail + 12;
|
|
820
|
+
size_t n = 0;
|
|
821
|
+
while (s[n] != '\0' && s[n] != ' ' && n < sizeof codebuf - 1) n++;
|
|
822
|
+
memcpy(codebuf, s, n);
|
|
823
|
+
codebuf[n] = '\0';
|
|
824
|
+
code = codebuf;
|
|
825
|
+
} else if (fx_eq_ci(detail, msg->len, "socket hang up")) {
|
|
826
|
+
/* undici's cause for a server that died before the response head */
|
|
827
|
+
detail = "other side closed";
|
|
828
|
+
code = "UND_ERR_SOCKET";
|
|
829
|
+
}
|
|
830
|
+
fx_error(t, detail, code);
|
|
831
|
+
fx_release(t);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/* ── host functions (called by the fetch glue, inside the engine) ────── */
|
|
835
|
+
|
|
836
|
+
/* host.start({url, method, headers: [n,v,...], body: Uint8Array|undefined},
|
|
837
|
+
* cbs) → transfer id. Everything is copied out of the engine before the
|
|
838
|
+
* net stack sees it. An unparsable URL throws the engine TypeError the
|
|
839
|
+
* promise executor turns into Node's rejection shape. */
|
|
840
|
+
static JSValue fx_host_start(JSContext *ctx, JSValueConst this_val, int argc,
|
|
841
|
+
JSValueConst *argv) {
|
|
842
|
+
(void)this_val;
|
|
843
|
+
(void)argc;
|
|
844
|
+
JSValueConst req = argv[0];
|
|
845
|
+
|
|
846
|
+
JSValue urlv = JS_GetPropertyStr(ctx, req, "url");
|
|
847
|
+
const char *url = JS_ToCString(ctx, urlv);
|
|
848
|
+
JS_FreeValue(ctx, urlv);
|
|
849
|
+
if (!url) return JS_EXCEPTION;
|
|
850
|
+
ScrStr *urlstr = scr_str_new(url, strlen(url));
|
|
851
|
+
ScrUrl *u = fx_url_parse(urlstr);
|
|
852
|
+
scr_str_release(urlstr);
|
|
853
|
+
if (u == NULL) {
|
|
854
|
+
JSValue e = JS_ThrowTypeError(ctx, "Failed to parse URL from %s", url);
|
|
855
|
+
JS_FreeCString(ctx, url);
|
|
856
|
+
return e;
|
|
857
|
+
}
|
|
858
|
+
JS_FreeCString(ctx, url);
|
|
859
|
+
if (!(fx_str_is(u->scheme, "http") || fx_str_is(u->scheme, "https"))) {
|
|
860
|
+
scr_url_release(u);
|
|
861
|
+
return JS_ThrowTypeError(ctx, "fetch failed");
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
FxTransfer *t = calloc(1, sizeof *t);
|
|
865
|
+
if (!t) fx_oom();
|
|
866
|
+
t->rc = 1; /* the registry's */
|
|
867
|
+
t->ctx = ctx;
|
|
868
|
+
t->id = fx_next_id++;
|
|
869
|
+
t->cbs = JS_DupValue(ctx, argv[1]);
|
|
870
|
+
t->cbs_live = true;
|
|
871
|
+
t->url = u;
|
|
872
|
+
|
|
873
|
+
JSValue methodv = JS_GetPropertyStr(ctx, req, "method");
|
|
874
|
+
const char *method = JS_ToCString(ctx, methodv);
|
|
875
|
+
JS_FreeValue(ctx, methodv);
|
|
876
|
+
t->method = scr_str_new(method ? method : "GET", method ? strlen(method) : 3);
|
|
877
|
+
if (method) JS_FreeCString(ctx, method);
|
|
878
|
+
|
|
879
|
+
JSValue hdrs = JS_GetPropertyStr(ctx, req, "headers");
|
|
880
|
+
JSValue lenv = JS_GetPropertyStr(ctx, hdrs, "length");
|
|
881
|
+
uint32_t hn = 0;
|
|
882
|
+
JS_ToUint32(ctx, &hn, lenv);
|
|
883
|
+
JS_FreeValue(ctx, lenv);
|
|
884
|
+
t->headers = scr_arr_new(SCR_ELEM_STR, hn);
|
|
885
|
+
for (uint32_t i = 0; i + 1 < hn; i += 2) {
|
|
886
|
+
JSValue nv = JS_GetPropertyUint32(ctx, hdrs, i);
|
|
887
|
+
JSValue vv = JS_GetPropertyUint32(ctx, hdrs, i + 1);
|
|
888
|
+
size_t nlen = 0, vlen = 0;
|
|
889
|
+
const char *hname = JS_ToCStringLen(ctx, &nlen, nv);
|
|
890
|
+
const char *hvalue = JS_ToCStringLen(ctx, &vlen, vv);
|
|
891
|
+
if (hname && hvalue) {
|
|
892
|
+
scr_arr_push_ref(t->headers, scr_str_new(hname, nlen));
|
|
893
|
+
scr_arr_push_ref(t->headers, scr_str_new(hvalue, vlen));
|
|
894
|
+
}
|
|
895
|
+
if (hname) JS_FreeCString(ctx, hname);
|
|
896
|
+
if (hvalue) JS_FreeCString(ctx, hvalue);
|
|
897
|
+
JS_FreeValue(ctx, nv);
|
|
898
|
+
JS_FreeValue(ctx, vv);
|
|
899
|
+
}
|
|
900
|
+
JS_FreeValue(ctx, hdrs);
|
|
901
|
+
|
|
902
|
+
JSValue bodyv = JS_GetPropertyStr(ctx, req, "body");
|
|
903
|
+
if (!JS_IsUndefined(bodyv) && !JS_IsNull(bodyv)) {
|
|
904
|
+
size_t blen = 0;
|
|
905
|
+
uint8_t *bytes = JS_GetUint8Array(ctx, &blen, bodyv);
|
|
906
|
+
if (bytes != NULL || blen == 0) {
|
|
907
|
+
t->body = scr_bytes_new(SCR_BYTES_U8, (double)blen);
|
|
908
|
+
if (blen > 0) memcpy(t->body->data, bytes, blen);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
JS_FreeValue(ctx, bodyv);
|
|
912
|
+
|
|
913
|
+
t->next = fx_live;
|
|
914
|
+
fx_live = t;
|
|
915
|
+
fx_nlive++;
|
|
916
|
+
fx_start_hop(t);
|
|
917
|
+
return JS_NewInt32(ctx, t->id);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/* host.abort(id): the island aborted the fetch or cancelled the response
|
|
921
|
+
* body stream. The transfer dies quietly — no onError, no onEnd. */
|
|
922
|
+
static JSValue fx_host_abort(JSContext *ctx, JSValueConst this_val, int argc,
|
|
923
|
+
JSValueConst *argv) {
|
|
924
|
+
(void)this_val;
|
|
925
|
+
(void)argc;
|
|
926
|
+
int32_t id = 0;
|
|
927
|
+
JS_ToInt32(ctx, &id, argv[0]);
|
|
928
|
+
for (FxTransfer *t = fx_live; t; t = t->next) {
|
|
929
|
+
if (t->id == id) {
|
|
930
|
+
t->cancelled = true;
|
|
931
|
+
if (t->client) scr_http_client_destroy(t->client);
|
|
932
|
+
fx_settle(t);
|
|
933
|
+
break;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return JS_UNDEFINED;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/* ── the JS half (UNCHANGED from the curl bridge — the island surface,
|
|
940
|
+
* abort wiring, and error shaping are the contract the fixture suite
|
|
941
|
+
* pins) ──────────────────────────────────────────────────────────────── */
|
|
942
|
+
|
|
943
|
+
static const char fx_glue[] =
|
|
944
|
+
"(host) => {\n"
|
|
945
|
+
" 'use strict';\n"
|
|
946
|
+
" const g = globalThis;\n"
|
|
947
|
+
" const NULL_BODY = { 204: true, 205: true, 304: true };\n"
|
|
948
|
+
" g.fetch = function fetch(input, init) {\n"
|
|
949
|
+
" return new Promise((resolve, reject) => {\n"
|
|
950
|
+
" let url;\n"
|
|
951
|
+
" let method = 'GET';\n"
|
|
952
|
+
" let headers = null;\n"
|
|
953
|
+
" let body = null;\n"
|
|
954
|
+
" let signal = null;\n"
|
|
955
|
+
" if (input instanceof g.Request) {\n"
|
|
956
|
+
" url = input.url;\n"
|
|
957
|
+
" method = input.method;\n"
|
|
958
|
+
" headers = new g.Headers(input.headers);\n"
|
|
959
|
+
" body = input._body instanceof Uint8Array ? input._body : null;\n"
|
|
960
|
+
" signal = input._signal;\n"
|
|
961
|
+
" } else {\n"
|
|
962
|
+
" url = String(input);\n"
|
|
963
|
+
" }\n"
|
|
964
|
+
" init = init === undefined || init === null ? {} : init;\n"
|
|
965
|
+
" // An explicit init.signal overrides the Request's, null included.\n"
|
|
966
|
+
" if (init.signal !== undefined) {\n"
|
|
967
|
+
" if (init.signal !== null && !(init.signal instanceof g.AbortSignal)) {\n"
|
|
968
|
+
" throw new TypeError('fetch init.signal must be an AbortSignal or null');\n"
|
|
969
|
+
" }\n"
|
|
970
|
+
" signal = init.signal;\n"
|
|
971
|
+
" }\n"
|
|
972
|
+
" if (init.redirect !== undefined && init.redirect !== 'follow') {\n"
|
|
973
|
+
" throw new Error(\"scriptc: only redirect: 'follow' is supported by the embedded fetch\");\n"
|
|
974
|
+
" }\n"
|
|
975
|
+
" // Reuse Request's init handling: method normalization, header\n"
|
|
976
|
+
" // collection, body coercion with its implicit content-type, and the\n"
|
|
977
|
+
" // GET/HEAD-with-body TypeError.\n"
|
|
978
|
+
" const reqInit = {};\n"
|
|
979
|
+
" if (init.method !== undefined) reqInit.method = init.method;\n"
|
|
980
|
+
" if (init.headers !== undefined) reqInit.headers = init.headers;\n"
|
|
981
|
+
" if (init.body !== undefined && init.body !== null) reqInit.body = init.body;\n"
|
|
982
|
+
" if (reqInit.method !== undefined || reqInit.headers !== undefined || reqInit.body !== undefined || headers === null) {\n"
|
|
983
|
+
" const base = input instanceof g.Request ? input : url;\n"
|
|
984
|
+
" const r = new g.Request(base, reqInit);\n"
|
|
985
|
+
" method = r.method;\n"
|
|
986
|
+
" headers = r.headers;\n"
|
|
987
|
+
" if (r._body instanceof Uint8Array) body = r._body;\n"
|
|
988
|
+
" }\n"
|
|
989
|
+
" if (body !== null && !(body instanceof Uint8Array)) {\n"
|
|
990
|
+
" throw new TypeError('streaming request bodies are not supported in the scriptc island');\n"
|
|
991
|
+
" }\n"
|
|
992
|
+
" // An already-aborted signal rejects with ITS reason before any\n"
|
|
993
|
+
" // transfer starts (Node: validation above still throws first).\n"
|
|
994
|
+
" if (signal !== null && signal.aborted) {\n"
|
|
995
|
+
" reject(signal.reason);\n"
|
|
996
|
+
" return;\n"
|
|
997
|
+
" }\n"
|
|
998
|
+
" let controller = null;\n"
|
|
999
|
+
" let resolved = false;\n"
|
|
1000
|
+
" let done = false;\n"
|
|
1001
|
+
" let id = 0;\n"
|
|
1002
|
+
" // The transfer is over (delivered, failed, cancelled, or aborted):\n"
|
|
1003
|
+
" // a later signal abort must not touch it.\n"
|
|
1004
|
+
" const finish = () => {\n"
|
|
1005
|
+
" done = true;\n"
|
|
1006
|
+
" if (signal !== null) signal.removeEventListener('abort', onAbort);\n"
|
|
1007
|
+
" };\n"
|
|
1008
|
+
" const onAbort = () => {\n"
|
|
1009
|
+
" if (done) return;\n"
|
|
1010
|
+
" finish();\n"
|
|
1011
|
+
" host.abort(id); // the C side dies quietly; rejection is ours\n"
|
|
1012
|
+
" if (!resolved) {\n"
|
|
1013
|
+
" resolved = true;\n"
|
|
1014
|
+
" reject(signal.reason);\n"
|
|
1015
|
+
" } else if (controller !== null) {\n"
|
|
1016
|
+
" // Mid-stream: pending and future reads reject with the reason,\n"
|
|
1017
|
+
" // exactly Node's aborted-body behavior.\n"
|
|
1018
|
+
" try { controller.error(signal.reason); } catch (_e) { /* already closed */ }\n"
|
|
1019
|
+
" controller = null;\n"
|
|
1020
|
+
" }\n"
|
|
1021
|
+
" };\n"
|
|
1022
|
+
" const flat = [];\n"
|
|
1023
|
+
" for (const pair of headers) { flat.push(pair[0], pair[1]); }\n"
|
|
1024
|
+
" id = host.start(\n"
|
|
1025
|
+
" { url, method, headers: flat, body: body === null ? undefined : body },\n"
|
|
1026
|
+
" {\n"
|
|
1027
|
+
" onResponse(status, statusText, raw, finalUrl, redirected) {\n"
|
|
1028
|
+
" resolved = true;\n"
|
|
1029
|
+
" const h = new g.Headers();\n"
|
|
1030
|
+
" for (let i = 0; i + 1 < raw.length; i += 2) {\n"
|
|
1031
|
+
" try { h.append(raw[i], raw[i + 1]); } catch (_e) { /* junk line */ }\n"
|
|
1032
|
+
" }\n"
|
|
1033
|
+
" let stream = null;\n"
|
|
1034
|
+
" if (method !== 'HEAD' && NULL_BODY[status] !== true) {\n"
|
|
1035
|
+
" stream = new g.ReadableStream({\n"
|
|
1036
|
+
" start(c) { controller = c; },\n"
|
|
1037
|
+
" cancel() { controller = null; finish(); host.abort(id); },\n"
|
|
1038
|
+
" });\n"
|
|
1039
|
+
" }\n"
|
|
1040
|
+
" resolve(g.__scr_mk_response(status, statusText, h, finalUrl, redirected, stream));\n"
|
|
1041
|
+
" },\n"
|
|
1042
|
+
" onData(chunk) {\n"
|
|
1043
|
+
" if (controller !== null) {\n"
|
|
1044
|
+
" try { controller.enqueue(chunk); } catch (_e) { /* consumer went away */ }\n"
|
|
1045
|
+
" }\n"
|
|
1046
|
+
" },\n"
|
|
1047
|
+
" onEnd() {\n"
|
|
1048
|
+
" finish();\n"
|
|
1049
|
+
" if (controller !== null) {\n"
|
|
1050
|
+
" try { controller.close(); } catch (_e) { /* already errored */ }\n"
|
|
1051
|
+
" controller = null;\n"
|
|
1052
|
+
" }\n"
|
|
1053
|
+
" },\n"
|
|
1054
|
+
" onError(detail, code) {\n"
|
|
1055
|
+
" finish();\n"
|
|
1056
|
+
" if (!resolved) {\n"
|
|
1057
|
+
" // Node's shape: TypeError 'fetch failed' with a CAUSE the\n"
|
|
1058
|
+
" // wrappers classify (message + code for the network cases).\n"
|
|
1059
|
+
" const cause = new Error(String(detail));\n"
|
|
1060
|
+
" if (code !== undefined) cause.code = code;\n"
|
|
1061
|
+
" if (code === 'ECONNREFUSED') cause.syscall = 'connect';\n"
|
|
1062
|
+
" else if (code === 'ENOTFOUND') cause.syscall = 'getaddrinfo';\n"
|
|
1063
|
+
" const err = new TypeError('fetch failed');\n"
|
|
1064
|
+
" err.cause = cause;\n"
|
|
1065
|
+
" reject(err);\n"
|
|
1066
|
+
" } else if (controller !== null) {\n"
|
|
1067
|
+
" try { controller.error(new TypeError('terminated')); } catch (_e) { /* already closed */ }\n"
|
|
1068
|
+
" controller = null;\n"
|
|
1069
|
+
" }\n"
|
|
1070
|
+
" },\n"
|
|
1071
|
+
" },\n"
|
|
1072
|
+
" );\n"
|
|
1073
|
+
" if (signal !== null) signal.addEventListener('abort', onAbort, { once: true });\n"
|
|
1074
|
+
" });\n"
|
|
1075
|
+
" };\n"
|
|
1076
|
+
"}\n";
|
|
1077
|
+
|
|
1078
|
+
/* ── boot / teardown (registered with the island) ────────────────────── */
|
|
1079
|
+
|
|
1080
|
+
static void fx_boot(void *jsctx) {
|
|
1081
|
+
JSContext *ctx = (JSContext *)jsctx;
|
|
1082
|
+
JSValue fn = JS_Eval(ctx, fx_glue, sizeof fx_glue - 1, "<scr-fetch>", JS_EVAL_TYPE_GLOBAL);
|
|
1083
|
+
if (JS_IsException(fn)) {
|
|
1084
|
+
fprintf(stderr, "scriptc: island fetch glue failed to evaluate\n");
|
|
1085
|
+
abort();
|
|
1086
|
+
}
|
|
1087
|
+
JSValue host = JS_NewObject(ctx);
|
|
1088
|
+
JS_SetPropertyStr(ctx, host, "start", JS_NewCFunction(ctx, fx_host_start, "start", 2));
|
|
1089
|
+
JS_SetPropertyStr(ctx, host, "abort", JS_NewCFunction(ctx, fx_host_abort, "abort", 1));
|
|
1090
|
+
JSValue r = JS_Call(ctx, fn, JS_UNDEFINED, 1, (JSValueConst *)&host);
|
|
1091
|
+
JS_FreeValue(ctx, host);
|
|
1092
|
+
JS_FreeValue(ctx, fn);
|
|
1093
|
+
if (JS_IsException(r)) {
|
|
1094
|
+
fprintf(stderr, "scriptc: island fetch glue failed to run\n");
|
|
1095
|
+
abort();
|
|
1096
|
+
}
|
|
1097
|
+
JS_FreeValue(ctx, r);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/* Engine teardown with transfers still live (process.exit mid-request, or
|
|
1101
|
+
* an exit with an abandoned body stream): free their engine values FIRST
|
|
1102
|
+
* so the island's counting allocator returns to zero. The net/http exit
|
|
1103
|
+
* cleanups (registered later, so they run earlier — atexit LIFO) have
|
|
1104
|
+
* already dropped the listener closures; whatever the registry still
|
|
1105
|
+
* holds settles here. */
|
|
1106
|
+
static void fx_teardown(void) {
|
|
1107
|
+
while (fx_live) fx_settle(fx_live);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
/* The emitted main calls this (before any island entry) in builds whose
|
|
1111
|
+
* embedded graph references fetch. No pending/poll hooks: transfers live
|
|
1112
|
+
* on real sockets the loop's own poller sleeps on, and armed island
|
|
1113
|
+
* timers cap that sleep through the loop's island-deadline hook. */
|
|
1114
|
+
void scr_fetch_install(void) {
|
|
1115
|
+
static bool installed = false;
|
|
1116
|
+
if (installed) return;
|
|
1117
|
+
installed = true;
|
|
1118
|
+
/* The net unit's loop hooks (pending/dispatch/pollfd): the emitted main
|
|
1119
|
+
* registers them only for programs that USE node:net — a fetch-only
|
|
1120
|
+
* build must register them itself or its sockets would neither keep
|
|
1121
|
+
* the loop alive nor dispatch. */
|
|
1122
|
+
scr_net_install();
|
|
1123
|
+
/* The island's node:http/https client bridge rides the same units and
|
|
1124
|
+
* is always compiled beside the native fetch (cc.ts) — embedded graphs
|
|
1125
|
+
* that require node:http/https get working clients, not refusals. */
|
|
1126
|
+
scr_net_island_install();
|
|
1127
|
+
scr_island_set_fetch(fx_boot, NULL, NULL, fx_teardown);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
#endif /* SCR_DYNAMIC */
|