visaljs 0.0.9 → 0.0.11
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/README.md +12 -4
- package/THIRD_PARTY_LICENSES +31 -1
- package/cli.js +3745 -890
- package/node/include/js_node.h +12 -1
- package/node/prelude/_http_common.js +29 -0
- package/node/prelude/async_hooks.js +50 -11
- package/node/prelude/child_process.js +31 -4
- package/node/prelude/console.js +311 -143
- package/node/prelude/crypto.js +6 -4
- package/node/prelude/dgram.js +1169 -0
- package/node/prelude/diagnostics_channel.js +3 -1
- package/node/prelude/dns.js +250 -45
- package/node/prelude/dns_promises.js +8 -2
- package/node/prelude/fs_promises.js +9 -1
- package/node/prelude/http.js +405 -94
- package/node/prelude/https.js +13 -4
- package/node/prelude/internal/console_class.js +7 -0
- package/node/prelude/internal/console_global.js +25 -0
- package/node/prelude/internal/crypto/key_encryption.js +217 -0
- package/node/prelude/internal/crypto/keys.js +161 -26
- package/node/prelude/internal/crypto/random.js +24 -0
- package/node/prelude/internal/crypto/util.js +2 -1
- package/node/prelude/internal/crypto_x509.js +161 -0
- package/node/prelude/internal/dns_classes.js +6 -0
- package/node/prelude/internal/dns_resolver.js +371 -0
- package/node/prelude/internal/errors.js +9 -0
- package/node/prelude/internal/events_on.js +82 -37
- package/node/prelude/internal/features.js +8 -4
- package/node/prelude/internal/fs_filehandle.js +10 -4
- package/node/prelude/internal/http_chars.ts +22 -0
- package/node/prelude/internal/perf_histogram.js +1 -1
- package/node/prelude/internal/process_more.js +32 -17
- package/node/prelude/internal/process_signals.js +8 -2
- package/node/prelude/internal/punycode.ts +163 -0
- package/node/prelude/internal/readline.js +648 -274
- package/node/prelude/internal/readline_editor.js +1240 -0
- package/node/prelude/internal/string_width.js +43 -0
- package/node/prelude/internal/tls/common.js +145 -33
- package/node/prelude/internal/tls/wrap.js +182 -49
- package/node/prelude/internal/tls/x509.js +4 -1
- package/node/prelude/internal/udp.js +177 -0
- package/node/prelude/net.js +30 -14
- package/node/prelude/os.js +24 -6
- package/node/prelude/perf_hooks.js +37 -2
- package/node/prelude/punycode.js +2 -130
- package/node/prelude/readline.js +113 -4
- package/node/prelude/readline_promises.js +56 -32
- package/node/prelude/tls.js +21 -4
- package/node/prelude/util.js +3 -16
- package/node/src/host_dns.c +623 -0
- package/node/src/host_http.c +12 -0
- package/node/src/host_net.c +46 -0
- package/node/src/host_os.c +1 -6
- package/node/src/host_sys.c +79 -0
- package/node/src/host_udp.c +418 -0
- package/node/third_party/c-ares/LICENSE.md +24 -0
- package/node/third_party/c-ares/config/darwin/ares_config.h +573 -0
- package/node/third_party/c-ares/config/freebsd/ares_config.h +573 -0
- package/node/third_party/c-ares/config/linux/ares_config.h +573 -0
- package/node/third_party/c-ares/config/openbsd/ares_config.h +583 -0
- package/node/third_party/c-ares/include/ares.h +1237 -0
- package/node/third_party/c-ares/include/ares_build.h +202 -0
- package/node/third_party/c-ares/include/ares_dns.h +127 -0
- package/node/third_party/c-ares/include/ares_dns_record.h +1119 -0
- package/node/third_party/c-ares/include/ares_nameser.h +510 -0
- package/node/third_party/c-ares/include/ares_version.h +47 -0
- package/node/third_party/c-ares/src/lib/ares_addrinfo2hostent.c +305 -0
- package/node/third_party/c-ares/src/lib/ares_addrinfo_localhost.c +245 -0
- package/node/third_party/c-ares/src/lib/ares_android.c +496 -0
- package/node/third_party/c-ares/src/lib/ares_android.h +38 -0
- package/node/third_party/c-ares/src/lib/ares_cancel.c +87 -0
- package/node/third_party/c-ares/src/lib/ares_close_sockets.c +137 -0
- package/node/third_party/c-ares/src/lib/ares_conn.c +511 -0
- package/node/third_party/c-ares/src/lib/ares_conn.h +202 -0
- package/node/third_party/c-ares/src/lib/ares_cookie.c +461 -0
- package/node/third_party/c-ares/src/lib/ares_data.c +168 -0
- package/node/third_party/c-ares/src/lib/ares_data.h +92 -0
- package/node/third_party/c-ares/src/lib/ares_destroy.c +159 -0
- package/node/third_party/c-ares/src/lib/ares_free_hostent.c +54 -0
- package/node/third_party/c-ares/src/lib/ares_free_string.c +33 -0
- package/node/third_party/c-ares/src/lib/ares_freeaddrinfo.c +67 -0
- package/node/third_party/c-ares/src/lib/ares_getaddrinfo.c +806 -0
- package/node/third_party/c-ares/src/lib/ares_getenv.c +38 -0
- package/node/third_party/c-ares/src/lib/ares_getenv.h +34 -0
- package/node/third_party/c-ares/src/lib/ares_gethostbyaddr.c +229 -0
- package/node/third_party/c-ares/src/lib/ares_gethostbyname.c +341 -0
- package/node/third_party/c-ares/src/lib/ares_getnameinfo.c +437 -0
- package/node/third_party/c-ares/src/lib/ares_hosts_file.c +960 -0
- package/node/third_party/c-ares/src/lib/ares_inet_net_pton.h +31 -0
- package/node/third_party/c-ares/src/lib/ares_init.c +631 -0
- package/node/third_party/c-ares/src/lib/ares_ipv6.h +115 -0
- package/node/third_party/c-ares/src/lib/ares_library_init.c +190 -0
- package/node/third_party/c-ares/src/lib/ares_metrics.c +261 -0
- package/node/third_party/c-ares/src/lib/ares_options.c +492 -0
- package/node/third_party/c-ares/src/lib/ares_parse_into_addrinfo.c +179 -0
- package/node/third_party/c-ares/src/lib/ares_private.h +648 -0
- package/node/third_party/c-ares/src/lib/ares_process.c +1649 -0
- package/node/third_party/c-ares/src/lib/ares_qcache.c +442 -0
- package/node/third_party/c-ares/src/lib/ares_query.c +151 -0
- package/node/third_party/c-ares/src/lib/ares_search.c +623 -0
- package/node/third_party/c-ares/src/lib/ares_send.c +300 -0
- package/node/third_party/c-ares/src/lib/ares_set_socket_functions.c +590 -0
- package/node/third_party/c-ares/src/lib/ares_setup.h +224 -0
- package/node/third_party/c-ares/src/lib/ares_socket.c +427 -0
- package/node/third_party/c-ares/src/lib/ares_socket.h +163 -0
- package/node/third_party/c-ares/src/lib/ares_sortaddrinfo.c +447 -0
- package/node/third_party/c-ares/src/lib/ares_strerror.c +91 -0
- package/node/third_party/c-ares/src/lib/ares_sysconfig.c +642 -0
- package/node/third_party/c-ares/src/lib/ares_sysconfig_files.c +851 -0
- package/node/third_party/c-ares/src/lib/ares_sysconfig_mac.c +373 -0
- package/node/third_party/c-ares/src/lib/ares_sysconfig_win.c +673 -0
- package/node/third_party/c-ares/src/lib/ares_timeout.c +162 -0
- package/node/third_party/c-ares/src/lib/ares_update_servers.c +1376 -0
- package/node/third_party/c-ares/src/lib/ares_version.c +36 -0
- package/node/third_party/c-ares/src/lib/config-dos.h +114 -0
- package/node/third_party/c-ares/src/lib/config-win32.h +396 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_array.c +409 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable.c +451 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable.h +174 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_asvp.c +224 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_dict.c +230 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_strvp.c +210 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_szvp.c +188 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_vpstr.c +186 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_htable_vpvp.c +194 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_llist.c +385 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_slist.c +479 -0
- package/node/third_party/c-ares/src/lib/dsa/ares_slist.h +207 -0
- package/node/third_party/c-ares/src/lib/event/ares_event.h +191 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_configchg.c +746 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_epoll.c +192 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_kqueue.c +248 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_poll.c +140 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_select.c +159 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_thread.c +575 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_wake_pipe.c +172 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_win32.c +981 -0
- package/node/third_party/c-ares/src/lib/event/ares_event_win32.h +161 -0
- package/node/third_party/c-ares/src/lib/include/ares_array.h +276 -0
- package/node/third_party/c-ares/src/lib/include/ares_buf.h +732 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_asvp.h +130 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_dict.h +123 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_strvp.h +130 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_szvp.h +118 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_vpstr.h +111 -0
- package/node/third_party/c-ares/src/lib/include/ares_htable_vpvp.h +128 -0
- package/node/third_party/c-ares/src/lib/include/ares_llist.h +239 -0
- package/node/third_party/c-ares/src/lib/include/ares_mem.h +41 -0
- package/node/third_party/c-ares/src/lib/include/ares_str.h +261 -0
- package/node/third_party/c-ares/src/lib/inet_net_pton.c +451 -0
- package/node/third_party/c-ares/src/lib/inet_ntop.c +219 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_create_query.c +78 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_expand_name.c +99 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_expand_string.c +107 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_fds.c +80 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_getsock.c +85 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_a_reply.c +107 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_aaaa_reply.c +109 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_caa_reply.c +137 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_mx_reply.c +110 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_naptr_reply.c +132 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_ns_reply.c +154 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_ptr_reply.c +213 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_soa_reply.c +115 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_srv_reply.c +114 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_txt_reply.c +144 -0
- package/node/third_party/c-ares/src/lib/legacy/ares_parse_uri_reply.c +113 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_mapping.c +982 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_multistring.c +309 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_multistring.h +72 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_name.c +736 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_parse.c +1360 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_private.h +273 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_record.c +1701 -0
- package/node/third_party/c-ares/src/lib/record/ares_dns_write.c +1229 -0
- package/node/third_party/c-ares/src/lib/str/ares_buf.c +1510 -0
- package/node/third_party/c-ares/src/lib/str/ares_str.c +562 -0
- package/node/third_party/c-ares/src/lib/str/ares_strsplit.c +90 -0
- package/node/third_party/c-ares/src/lib/str/ares_strsplit.h +51 -0
- package/node/third_party/c-ares/src/lib/thirdparty/apple/dnsinfo.h +122 -0
- package/node/third_party/c-ares/src/lib/util/ares_iface_ips.c +640 -0
- package/node/third_party/c-ares/src/lib/util/ares_iface_ips.h +140 -0
- package/node/third_party/c-ares/src/lib/util/ares_math.c +167 -0
- package/node/third_party/c-ares/src/lib/util/ares_math.h +58 -0
- package/node/third_party/c-ares/src/lib/util/ares_rand.c +389 -0
- package/node/third_party/c-ares/src/lib/util/ares_rand.h +36 -0
- package/node/third_party/c-ares/src/lib/util/ares_threads.c +613 -0
- package/node/third_party/c-ares/src/lib/util/ares_threads.h +60 -0
- package/node/third_party/c-ares/src/lib/util/ares_time.h +49 -0
- package/node/third_party/c-ares/src/lib/util/ares_timeval.c +95 -0
- package/node/third_party/c-ares/src/lib/util/ares_uri.c +1627 -0
- package/node/third_party/c-ares/src/lib/util/ares_uri.h +252 -0
- package/node/third_party/c-ares/src/lib/windows_port.c +29 -0
- package/package.json +1 -1
- package/prebuilt/darwin-arm64/cares-a6286c65ca9374a3.a +0 -0
- package/prebuilt/darwin-x64/cares-a6286c65ca9374a3.a +0 -0
- package/prebuilt/linux-arm64/cares-4ba05ac8e948af8e.a +0 -0
- package/prebuilt/linux-arm64-musl/cares-4ba05ac8e948af8e.a +0 -0
- package/prebuilt/linux-x64/cares-4ba05ac8e948af8e.a +0 -0
- package/prebuilt/linux-x64-musl/cares-4ba05ac8e948af8e.a +0 -0
- package/prebuilt/win32-x64/boringssl-ce573858472b7fc9.a +0 -0
- package/prebuilt/win32-x64/brotli-20d86a61f30baeb3.a +0 -0
- package/prebuilt/win32-x64/cares-49c9ec95162b912d.a +0 -0
- package/prebuilt/win32-x64/uv-b11bae65d7fced82.a +0 -0
- package/prebuilt/win32-x64/zlib-4ce2317a4c3f5fb5.a +0 -0
- package/prebuilt/win32-x64/zstd-015315ac7c784c73.a +0 -0
- package/runtime/include/js_buffer.h +185 -0
- package/runtime/include/js_builtins.h +58 -0
- package/runtime/include/js_crypto.h +11 -0
- package/runtime/include/js_exception.h +3 -0
- package/runtime/include/js_function.h +1 -1
- package/runtime/include/js_gc.h +13 -10
- package/runtime/include/js_jobs.h +2 -0
- package/runtime/include/js_object.h +79 -3
- package/runtime/include/js_ops.h +27 -0
- package/runtime/include/js_runtime.h +1 -0
- package/runtime/include/js_web.h +0 -3
- package/runtime/include/jscontext.h +8 -0
- package/runtime/src/builtins.c +17 -4
- package/runtime/src/crypto_internal.h +1 -0
- package/runtime/src/crypto_subtle.c +66 -7
- package/runtime/src/crypto_tls.c +265 -19
- package/runtime/src/function.c +37 -10
- package/runtime/src/gc.c +76 -93
- package/runtime/src/inspect.c +18 -1
- package/runtime/src/iterator.c +5 -1
- package/runtime/src/jobs.c +37 -22
- package/runtime/src/object.c +91 -8
- package/runtime/src/os.c +16 -6
- package/runtime/src/os.h +2 -0
- package/runtime/src/process.c +97 -10
- package/runtime/src/typedarray.c +23 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
/* Host primitives for dns.Resolver: c-ares channels on libuv's loop, as Node's cares_wrap drives
|
|
2
|
+
* them (a poll handle for each socket c-ares opens, a timer while any is open). The prelude's
|
|
3
|
+
* internal/dns_resolver.js is Node's lib/internal/dns over them. A query's answer comes back as
|
|
4
|
+
* the bytes of the DNS message; dnsParse reads it with c-ares's parsers, as Node's do.
|
|
5
|
+
*
|
|
6
|
+
* dnsChannel(timeoutMs, tries, maxTimeoutMs) → channel (a c-ares channel, freed with it)
|
|
7
|
+
* dnsQuery(channel, name, type, cb) → 0 | ARES_*: cb(status, answer | null)
|
|
8
|
+
* dnsReverse(channel, ip, cb) → 0 | -EINVAL: cb(status, [name, …] | null)
|
|
9
|
+
* dnsParse(answer, kind) → [status, records, ttls | undefined, cname] (kind: a DNS type; 0x10000 + A: a CNAME
|
|
10
|
+
* or A; 0x10000 + SOA: ANY's SOA, none no error)
|
|
11
|
+
* dnsGetServers(channel) → [[ip, port], …]
|
|
12
|
+
* dnsSetServers(channel, [[family, ip, port], …]) → 0 | ARES_* | DNS_ESETSRVPENDING (queries pending)
|
|
13
|
+
* dnsSetLocalAddress(channel, ip4 | null, ip6 | null)
|
|
14
|
+
* dnsCancel(channel)
|
|
15
|
+
* dnsStrerror(status) → its message
|
|
16
|
+
*
|
|
17
|
+
* The callbacks are called from the loop, never inside a primitive (ares_cancel and ares_destroy
|
|
18
|
+
* finish queries at once): finished queries wait for a zero timer, as Node's wait for an immediate. */
|
|
19
|
+
#define _POSIX_C_SOURCE 200809L /* libuv's headers: pthread_rwlock_t, struct addrinfo */
|
|
20
|
+
#include <stdlib.h>
|
|
21
|
+
#include <string.h>
|
|
22
|
+
|
|
23
|
+
#include <ares.h>
|
|
24
|
+
|
|
25
|
+
#include "js_buffer.h"
|
|
26
|
+
#include "js_exception.h"
|
|
27
|
+
#include "js_gc.h"
|
|
28
|
+
#include "js_node.h"
|
|
29
|
+
#include "js_object.h"
|
|
30
|
+
#include "js_ops.h"
|
|
31
|
+
#include "js_uv.h"
|
|
32
|
+
#include "js_web.h"
|
|
33
|
+
#include "jscontext.h"
|
|
34
|
+
#include "jsstring.h"
|
|
35
|
+
|
|
36
|
+
#define HOST_FN(name) JSValue name(JSContext *ctx, JSValue callee, JSValue this_val, uint32_t argc, const JSValue *argv, JSValue new_target)
|
|
37
|
+
#define UNUSED (void)ctx, (void)callee, (void)this_val, (void)new_target
|
|
38
|
+
#define ARG(i) ((i) < argc ? argv[i] : JS_UNDEFINED)
|
|
39
|
+
|
|
40
|
+
/* Node's: setServers while queries are pending */
|
|
41
|
+
#define DNS_ESETSRVPENDING (-1000)
|
|
42
|
+
#define KIND_CNAME_OR_A 0x10000
|
|
43
|
+
#define KIND_SOA_IN_ANY 0x10006
|
|
44
|
+
|
|
45
|
+
typedef struct Channel Channel;
|
|
46
|
+
|
|
47
|
+
/* a socket c-ares opened, polled */
|
|
48
|
+
typedef struct Task {
|
|
49
|
+
uv_poll_t poll;
|
|
50
|
+
Channel *channel;
|
|
51
|
+
ares_socket_t sock;
|
|
52
|
+
struct Task *next;
|
|
53
|
+
} Task;
|
|
54
|
+
|
|
55
|
+
/* the loop and runtime are the channel's: c-ares opens sockets inside a primitive too, where
|
|
56
|
+
* js_uv_context() is null (it is set only while the loop runs callbacks) */
|
|
57
|
+
struct Channel {
|
|
58
|
+
uv_loop_t *loop;
|
|
59
|
+
JSRuntime *rt;
|
|
60
|
+
ares_channel_t *ares;
|
|
61
|
+
uv_timer_t *timer; /* while c-ares has sockets: its timeouts */
|
|
62
|
+
Task *tasks;
|
|
63
|
+
int timeout;
|
|
64
|
+
int active; /* queries pending: the channel's object is a root while there are */
|
|
65
|
+
JSValue self;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
typedef struct ChannelObject {
|
|
69
|
+
JSObject obj;
|
|
70
|
+
Channel *c;
|
|
71
|
+
} ChannelObject;
|
|
72
|
+
|
|
73
|
+
/* a query: its callback, and once finished its result, waiting to be delivered */
|
|
74
|
+
typedef struct Query {
|
|
75
|
+
Channel *channel;
|
|
76
|
+
JSValue cb; /* a root */
|
|
77
|
+
int status;
|
|
78
|
+
uint8_t *answer; /* malloc'd */
|
|
79
|
+
size_t answer_len;
|
|
80
|
+
char **names; /* a reverse lookup's: NULL-terminated, malloc'd */
|
|
81
|
+
struct Query *next;
|
|
82
|
+
} Query;
|
|
83
|
+
|
|
84
|
+
static Query *finished, **finished_tail = &finished;
|
|
85
|
+
static uv_timer_t deliver_timer;
|
|
86
|
+
static bool deliver_inited;
|
|
87
|
+
|
|
88
|
+
/* ---- the loop ------------------------------------------------------------------------------- */
|
|
89
|
+
|
|
90
|
+
static void on_ares_timeout(uv_timer_t *t) {
|
|
91
|
+
Channel *c = t->data;
|
|
92
|
+
ares_process_fd(c->ares, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static void on_poll(uv_poll_t *p, int status, int events) {
|
|
96
|
+
Task *task = (Task *)p;
|
|
97
|
+
Channel *c = task->channel;
|
|
98
|
+
if (c->timer) uv_timer_again(c->timer);
|
|
99
|
+
/* an error: as readable and writable, so c-ares finds it */
|
|
100
|
+
if (status < 0) ares_process_fd(c->ares, task->sock, task->sock);
|
|
101
|
+
else ares_process_fd(c->ares, events & UV_READABLE ? task->sock : ARES_SOCKET_BAD, events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static void free_handle(uv_handle_t *h) { free(h); }
|
|
105
|
+
|
|
106
|
+
static void start_timer(Channel *c) {
|
|
107
|
+
if (!c->timer) {
|
|
108
|
+
c->timer = malloc(sizeof *c->timer);
|
|
109
|
+
if (!c->timer) js_fatal("out of memory in dns");
|
|
110
|
+
uv_timer_init(c->loop, c->timer);
|
|
111
|
+
c->timer->data = c;
|
|
112
|
+
} else if (uv_is_active((uv_handle_t *)c->timer)) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
/* c-ares's timeouts are checked at least once a second (Node's) */
|
|
116
|
+
int timeout = c->timeout <= 0 || c->timeout > 1000 ? 1000 : c->timeout;
|
|
117
|
+
uv_timer_start(c->timer, on_ares_timeout, timeout, timeout);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static void close_timer(Channel *c) {
|
|
121
|
+
if (!c->timer) return;
|
|
122
|
+
uv_close((uv_handle_t *)c->timer, free_handle);
|
|
123
|
+
c->timer = NULL;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* c-ares opened, changed or closed a socket */
|
|
127
|
+
static void on_sock_state(void *data, ares_socket_t sock, int read, int write) {
|
|
128
|
+
Channel *c = data;
|
|
129
|
+
Task **at = &c->tasks;
|
|
130
|
+
while (*at && (*at)->sock != sock) at = &(*at)->next;
|
|
131
|
+
Task *task = *at;
|
|
132
|
+
if (read || write) {
|
|
133
|
+
if (!task) {
|
|
134
|
+
start_timer(c);
|
|
135
|
+
task = calloc(1, sizeof *task);
|
|
136
|
+
if (!task) js_fatal("out of memory in dns");
|
|
137
|
+
task->channel = c;
|
|
138
|
+
task->sock = sock;
|
|
139
|
+
/* if this fails, the query times out */
|
|
140
|
+
if (uv_poll_init_socket(c->loop, &task->poll, sock) < 0) {
|
|
141
|
+
free(task);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
task->next = c->tasks;
|
|
145
|
+
c->tasks = task;
|
|
146
|
+
}
|
|
147
|
+
uv_poll_start(&task->poll, (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0), on_poll);
|
|
148
|
+
} else if (task) {
|
|
149
|
+
*at = task->next;
|
|
150
|
+
uv_close((uv_handle_t *)&task->poll, free_handle);
|
|
151
|
+
if (!c->tasks) close_timer(c);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* ---- finished queries ----------------------------------------------------------------------- */
|
|
156
|
+
|
|
157
|
+
static void query_done(Channel *c) {
|
|
158
|
+
if (--c->active == 0) js_remove_root(c->rt, &c->self);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
static void on_deliver(uv_timer_t *t) {
|
|
162
|
+
(void)t;
|
|
163
|
+
JSContext *ctx = js_uv_context();
|
|
164
|
+
Query *q = finished;
|
|
165
|
+
finished = NULL;
|
|
166
|
+
finished_tail = &finished;
|
|
167
|
+
while (q) {
|
|
168
|
+
Query *next = q->next;
|
|
169
|
+
JSValue args[2] = { js_int32(q->status), JS_NULL };
|
|
170
|
+
if (q->answer) {
|
|
171
|
+
args[1] = js_new_buffer_from_bytes(ctx, q->answer, q->answer_len);
|
|
172
|
+
} else if (q->names) {
|
|
173
|
+
args[1] = js_new_array(ctx, 0);
|
|
174
|
+
for (char **n = q->names; *n; n++) {
|
|
175
|
+
if (js_array_append(ctx, args[1], js_new_string_cstr(ctx, *n)) < 0) js_fatal("out of memory in dns");
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
JSValue cb = q->cb;
|
|
179
|
+
js_remove_root(ctx->rt, &q->cb);
|
|
180
|
+
free(q->answer);
|
|
181
|
+
if (q->names) {
|
|
182
|
+
for (char **n = q->names; *n; n++) free(*n);
|
|
183
|
+
free(q->names);
|
|
184
|
+
}
|
|
185
|
+
free(q);
|
|
186
|
+
(void)js_uv_call(cb, 2, args, NULL);
|
|
187
|
+
q = next;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static void finish(Query *q, int status) {
|
|
192
|
+
q->status = status;
|
|
193
|
+
query_done(q->channel);
|
|
194
|
+
q->next = NULL;
|
|
195
|
+
*finished_tail = q;
|
|
196
|
+
finished_tail = &q->next;
|
|
197
|
+
if (!deliver_inited) {
|
|
198
|
+
uv_timer_init(q->channel->loop, &deliver_timer);
|
|
199
|
+
uv_unref((uv_handle_t *)&deliver_timer);
|
|
200
|
+
deliver_inited = true;
|
|
201
|
+
}
|
|
202
|
+
/* a zero timer: the next turn of the loop, which it keeps alive till then */
|
|
203
|
+
uv_ref((uv_handle_t *)&deliver_timer);
|
|
204
|
+
uv_timer_start(&deliver_timer, on_deliver, 0, 0);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static void on_answer(void *arg, ares_status_t status, size_t timeouts, const ares_dns_record_t *dnsrec) {
|
|
208
|
+
(void)timeouts;
|
|
209
|
+
Query *q = arg;
|
|
210
|
+
if (status == ARES_SUCCESS && ares_dns_write(dnsrec, &q->answer, &q->answer_len) != ARES_SUCCESS) status = ARES_ENOMEM;
|
|
211
|
+
finish(q, (int)status);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
static void on_host(void *arg, int status, int timeouts, struct hostent *host) {
|
|
215
|
+
(void)timeouts;
|
|
216
|
+
Query *q = arg;
|
|
217
|
+
if (status == ARES_SUCCESS && host) {
|
|
218
|
+
size_t n = 0;
|
|
219
|
+
while (host->h_aliases[n]) n++;
|
|
220
|
+
q->names = calloc(n + 1, sizeof *q->names);
|
|
221
|
+
if (!q->names) js_fatal("out of memory in dns");
|
|
222
|
+
for (size_t i = 0; i < n; i++) {
|
|
223
|
+
q->names[i] = strdup(host->h_aliases[i]);
|
|
224
|
+
if (!q->names[i]) js_fatal("out of memory in dns");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
finish(q, status);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/* ---- channels ------------------------------------------------------------------------------- */
|
|
231
|
+
|
|
232
|
+
static void channel_finalize(JSRuntime *rt, JSCell *cell) {
|
|
233
|
+
(void)rt;
|
|
234
|
+
Channel *c = ((ChannelObject *)cell)->c;
|
|
235
|
+
if (!c) return;
|
|
236
|
+
/* no query is pending (they keep the object): this closes the sockets, through on_sock_state */
|
|
237
|
+
ares_destroy(c->ares);
|
|
238
|
+
close_timer(c);
|
|
239
|
+
free(c);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
static const JSClass channel_class = { "ChannelWrap", sizeof(ChannelObject), NULL, NULL, NULL, NULL, NULL, channel_finalize, NULL };
|
|
243
|
+
|
|
244
|
+
static Channel *channel_arg(JSValue v) {
|
|
245
|
+
return js_is_object(v) && js_as_object(v)->shape->cls == &channel_class ? ((ChannelObject *)js_as_object(v))->c : NULL;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/* Node's ChannelWrap::Setup: responses not checked (NOCHECKRESP), nothing cached */
|
|
249
|
+
HOST_FN(js_host_dns_channel) {
|
|
250
|
+
UNUSED;
|
|
251
|
+
static bool library_inited;
|
|
252
|
+
if (!library_inited) {
|
|
253
|
+
int r = ares_library_init(ARES_LIB_INIT_ALL);
|
|
254
|
+
if (r != ARES_SUCCESS) return js_throw_type_error(ctx, ares_strerror(r));
|
|
255
|
+
library_inited = true;
|
|
256
|
+
}
|
|
257
|
+
Channel *c = calloc(1, sizeof *c);
|
|
258
|
+
if (!c) js_fatal("out of memory in dns");
|
|
259
|
+
c->loop = js_uv_loop(ctx);
|
|
260
|
+
c->rt = ctx->rt;
|
|
261
|
+
c->timeout = js_is_number(ARG(0)) ? (int)js_as_number(ARG(0)) : -1;
|
|
262
|
+
struct ares_options options = { 0 };
|
|
263
|
+
options.flags = ARES_FLAG_NOCHECKRESP;
|
|
264
|
+
options.sock_state_cb = on_sock_state;
|
|
265
|
+
options.sock_state_cb_data = c;
|
|
266
|
+
options.timeout = c->timeout;
|
|
267
|
+
options.tries = js_is_number(ARG(1)) ? (int)js_as_number(ARG(1)) : 4;
|
|
268
|
+
options.qcache_max_ttl = 0;
|
|
269
|
+
int optmask = ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | ARES_OPT_SOCK_STATE_CB | ARES_OPT_TRIES | ARES_OPT_QUERY_CACHE;
|
|
270
|
+
int max_timeout = js_is_number(ARG(2)) ? (int)js_as_number(ARG(2)) : 0;
|
|
271
|
+
if (max_timeout > 0) {
|
|
272
|
+
options.maxtimeout = max_timeout;
|
|
273
|
+
optmask |= ARES_OPT_MAXTIMEOUTMS;
|
|
274
|
+
}
|
|
275
|
+
int r = ares_init_options(&c->ares, &options, optmask);
|
|
276
|
+
if (r != ARES_SUCCESS) {
|
|
277
|
+
free(c);
|
|
278
|
+
return js_throw_type_error(ctx, ares_strerror(r));
|
|
279
|
+
}
|
|
280
|
+
ChannelObject *o = (ChannelObject *)js_alloc_object(ctx, JS_CELL_OBJECT, js_shape_root(ctx, &channel_class, JS_NULL, 0));
|
|
281
|
+
o->c = c;
|
|
282
|
+
c->self = js_object_value(&o->obj);
|
|
283
|
+
return c->self;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
static Query *new_query(JSContext *ctx, Channel *c, JSValue cb) {
|
|
287
|
+
Query *q = calloc(1, sizeof *q);
|
|
288
|
+
if (!q) js_fatal("out of memory in dns");
|
|
289
|
+
q->channel = c;
|
|
290
|
+
q->cb = cb;
|
|
291
|
+
js_add_root(ctx->rt, &q->cb);
|
|
292
|
+
if (c->active++ == 0) js_add_root(ctx->rt, &c->self);
|
|
293
|
+
return q;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
static char *string_dup(JSContext *ctx, JSValue v) {
|
|
297
|
+
if (!js_is_string(v)) return NULL;
|
|
298
|
+
JSStrView view = js_string_view(ctx, v);
|
|
299
|
+
size_t n = js_view_to_utf8(view, NULL, 0);
|
|
300
|
+
char *s = malloc(n + 1);
|
|
301
|
+
if (!s) js_fatal("out of memory in dns");
|
|
302
|
+
js_view_to_utf8(view, s, n);
|
|
303
|
+
s[n] = '\0';
|
|
304
|
+
return s;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* dnsQuery(channel, name, type, cb): the name as Node gives it, ASCII already (domainToASCII) */
|
|
308
|
+
HOST_FN(js_host_dns_query) {
|
|
309
|
+
UNUSED;
|
|
310
|
+
Channel *c = channel_arg(ARG(0));
|
|
311
|
+
char *name = string_dup(ctx, ARG(1));
|
|
312
|
+
if (!c || !name || !js_is_number(ARG(2))) {
|
|
313
|
+
free(name);
|
|
314
|
+
return js_throw_type_error(ctx, "dnsQuery: (channel, name, type, cb) expected");
|
|
315
|
+
}
|
|
316
|
+
Query *q = new_query(ctx, c, ARG(3));
|
|
317
|
+
ares_query_dnsrec(c->ares, name, ARES_CLASS_IN, (ares_dns_rec_type_t)js_as_number(ARG(2)), on_answer, q, NULL);
|
|
318
|
+
free(name);
|
|
319
|
+
return js_int32(0);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
HOST_FN(js_host_dns_reverse) {
|
|
323
|
+
UNUSED;
|
|
324
|
+
Channel *c = channel_arg(ARG(0));
|
|
325
|
+
char ip[64];
|
|
326
|
+
size_t n = js_is_string(ARG(1)) ? js_view_to_utf8(js_string_view(ctx, ARG(1)), ip, sizeof ip - 1) : 0;
|
|
327
|
+
ip[n] = '\0';
|
|
328
|
+
if (!c) return js_throw_type_error(ctx, "dnsReverse: (channel, ip, cb) expected");
|
|
329
|
+
unsigned char addr[16];
|
|
330
|
+
int family, length;
|
|
331
|
+
if (uv_inet_pton(AF_INET, ip, addr) == 0) family = AF_INET, length = 4;
|
|
332
|
+
else if (uv_inet_pton(AF_INET6, ip, addr) == 0) family = AF_INET6, length = 16;
|
|
333
|
+
else return js_int32(UV_EINVAL);
|
|
334
|
+
Query *q = new_query(ctx, c, ARG(2));
|
|
335
|
+
ares_gethostbyaddr(c->ares, addr, length, family, on_host, q);
|
|
336
|
+
return js_int32(0);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
HOST_FN(js_host_dns_cancel) {
|
|
340
|
+
UNUSED;
|
|
341
|
+
Channel *c = channel_arg(ARG(0));
|
|
342
|
+
if (c) ares_cancel(c->ares);
|
|
343
|
+
return JS_UNDEFINED;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
HOST_FN(js_host_dns_get_servers) {
|
|
347
|
+
UNUSED;
|
|
348
|
+
Channel *c = channel_arg(ARG(0));
|
|
349
|
+
if (!c) return js_throw_type_error(ctx, "dnsGetServers: a channel expected");
|
|
350
|
+
struct ares_addr_port_node *servers = NULL;
|
|
351
|
+
ares_get_servers_ports(c->ares, &servers);
|
|
352
|
+
JSValue out = js_new_array(ctx, 0);
|
|
353
|
+
for (struct ares_addr_port_node *s = servers; s; s = s->next) {
|
|
354
|
+
char ip[64] = "";
|
|
355
|
+
uv_inet_ntop(s->family, &s->addr, ip, sizeof ip);
|
|
356
|
+
JSValue items[2] = { js_new_string_cstr(ctx, ip), js_int32(s->udp_port) };
|
|
357
|
+
if (js_array_append(ctx, out, js_new_array_from(ctx, items, 2)) < 0) js_fatal("out of memory in dns");
|
|
358
|
+
}
|
|
359
|
+
ares_free_data(servers);
|
|
360
|
+
return out;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
HOST_FN(js_host_dns_set_servers) {
|
|
364
|
+
UNUSED;
|
|
365
|
+
Channel *c = channel_arg(ARG(0));
|
|
366
|
+
if (!c || !js_is_array(ARG(1))) return js_throw_type_error(ctx, "dnsSetServers: (channel, servers) expected");
|
|
367
|
+
if (c->active) return js_int32(DNS_ESETSRVPENDING);
|
|
368
|
+
uint32_t n = js_array_length(js_as_object(ARG(1)));
|
|
369
|
+
if (n == 0) return js_int32(ares_set_servers(c->ares, NULL));
|
|
370
|
+
struct ares_addr_port_node *servers = calloc(n, sizeof *servers);
|
|
371
|
+
if (!servers) js_fatal("out of memory in dns");
|
|
372
|
+
int err = 0;
|
|
373
|
+
for (uint32_t i = 0; i < n && err == 0; i++) {
|
|
374
|
+
JSValue e = js_get_value(ctx, ARG(1), js_index_key(i));
|
|
375
|
+
JSValue family = js_get_value(ctx, e, js_index_key(0)), ipv = js_get_value(ctx, e, js_index_key(1)), port = js_get_value(ctx, e, js_index_key(2));
|
|
376
|
+
char ip[64];
|
|
377
|
+
size_t len = js_is_string(ipv) ? js_view_to_utf8(js_string_view(ctx, ipv), ip, sizeof ip - 1) : 0;
|
|
378
|
+
ip[len] = '\0';
|
|
379
|
+
struct ares_addr_port_node *s = &servers[i];
|
|
380
|
+
s->udp_port = s->tcp_port = js_is_number(port) ? (int)js_as_number(port) : 53;
|
|
381
|
+
s->family = js_is_number(family) && js_as_number(family) == 6 ? AF_INET6 : AF_INET;
|
|
382
|
+
err = uv_inet_pton(s->family, ip, &s->addr);
|
|
383
|
+
if (i > 0) servers[i - 1].next = s;
|
|
384
|
+
}
|
|
385
|
+
int r = err ? ARES_EBADSTR : ares_set_servers_ports(c->ares, servers);
|
|
386
|
+
free(servers);
|
|
387
|
+
return js_int32(r);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/* dnsSetLocalAddress(channel, ip4 | null, ip6 | null): the addresses queries are sent from (null: any) */
|
|
391
|
+
HOST_FN(js_host_dns_set_local_address) {
|
|
392
|
+
UNUSED;
|
|
393
|
+
Channel *c = channel_arg(ARG(0));
|
|
394
|
+
if (!c) return js_throw_type_error(ctx, "dnsSetLocalAddress: a channel expected");
|
|
395
|
+
char ip[64];
|
|
396
|
+
unsigned char addr[16] = { 0 };
|
|
397
|
+
size_t n = js_is_string(ARG(1)) ? js_view_to_utf8(js_string_view(ctx, ARG(1)), ip, sizeof ip - 1) : 0;
|
|
398
|
+
ip[n] = '\0';
|
|
399
|
+
ares_set_local_ip4(c->ares, n && uv_inet_pton(AF_INET, ip, addr) == 0 ? ((unsigned)addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3]) : 0);
|
|
400
|
+
memset(addr, 0, sizeof addr);
|
|
401
|
+
n = js_is_string(ARG(2)) ? js_view_to_utf8(js_string_view(ctx, ARG(2)), ip, sizeof ip - 1) : 0;
|
|
402
|
+
ip[n] = '\0';
|
|
403
|
+
if (n) uv_inet_pton(AF_INET6, ip, addr);
|
|
404
|
+
ares_set_local_ip6(c->ares, addr);
|
|
405
|
+
return JS_UNDEFINED;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
HOST_FN(js_host_dns_strerror) {
|
|
409
|
+
UNUSED;
|
|
410
|
+
int code = js_is_number(ARG(0)) ? (int)js_as_number(ARG(0)) : 0;
|
|
411
|
+
return js_new_string_cstr(ctx, code == DNS_ESETSRVPENDING ? "There are pending queries." : ares_strerror(code));
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/* ---- answers, as Node's parsers read them ---------------------------------------------------- */
|
|
415
|
+
|
|
416
|
+
static void append(JSContext *ctx, JSValue list, JSValue v) {
|
|
417
|
+
if (js_array_append(ctx, list, v) < 0) js_fatal("out of memory in dns");
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
static JSValue array_of(JSContext *ctx, JSValue *items, uint32_t n) {
|
|
421
|
+
return js_new_array_from(ctx, items, n);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
static JSValue str(JSContext *ctx, const void *s) {
|
|
425
|
+
return js_new_string_cstr(ctx, s ? (const char *)s : "");
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* the answers' count (Node's GetAnswerCountForTTLBuffer): the TTL buffer's size */
|
|
429
|
+
static int answer_count(const uint8_t *buf, size_t len) {
|
|
430
|
+
if (len <= 7) return 256;
|
|
431
|
+
int n = buf[6] << 8 | buf[7];
|
|
432
|
+
return n == 0 ? 1 : n;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/* A, AAAA, CNAME, NS, PTR (Node's ParseGeneralReply), into records and ttls */
|
|
436
|
+
static int general(JSContext *ctx, const uint8_t *buf, int len, int kind, JSValue records, JSValue ttls, bool *cname) {
|
|
437
|
+
struct hostent *host = NULL;
|
|
438
|
+
int n = answer_count(buf, (size_t)len), status;
|
|
439
|
+
int type = kind == KIND_CNAME_OR_A ? ARES_REC_TYPE_A : kind;
|
|
440
|
+
void *addrttls = NULL;
|
|
441
|
+
if (type == ARES_REC_TYPE_A || type == ARES_REC_TYPE_AAAA) {
|
|
442
|
+
addrttls = calloc((size_t)n, type == ARES_REC_TYPE_A ? sizeof(struct ares_addrttl) : sizeof(struct ares_addr6ttl));
|
|
443
|
+
if (!addrttls) js_fatal("out of memory in dns");
|
|
444
|
+
}
|
|
445
|
+
switch (type) {
|
|
446
|
+
case ARES_REC_TYPE_A:
|
|
447
|
+
case ARES_REC_TYPE_CNAME: status = ares_parse_a_reply(buf, len, &host, type == ARES_REC_TYPE_A ? addrttls : NULL, type == ARES_REC_TYPE_A ? &n : NULL); break;
|
|
448
|
+
case ARES_REC_TYPE_AAAA: status = ares_parse_aaaa_reply(buf, len, &host, addrttls, &n); break;
|
|
449
|
+
case ARES_REC_TYPE_NS: status = ares_parse_ns_reply(buf, len, &host); break;
|
|
450
|
+
default: status = ares_parse_ptr_reply(buf, len, NULL, 0, AF_INET, &host); break;
|
|
451
|
+
}
|
|
452
|
+
if (status == ARES_SUCCESS) {
|
|
453
|
+
/* a CNAME, or for CNAME-or-A one that has a name and an alias: the name */
|
|
454
|
+
if (type == ARES_REC_TYPE_CNAME || (kind == KIND_CNAME_OR_A && host->h_name && host->h_aliases[0])) {
|
|
455
|
+
*cname = true;
|
|
456
|
+
append(ctx, records, str(ctx, host->h_name));
|
|
457
|
+
} else if (type == ARES_REC_TYPE_NS || type == ARES_REC_TYPE_PTR) {
|
|
458
|
+
for (char **a = host->h_aliases; *a; a++) append(ctx, records, str(ctx, *a));
|
|
459
|
+
} else {
|
|
460
|
+
char ip[64];
|
|
461
|
+
for (char **a = host->h_addr_list; *a; a++) {
|
|
462
|
+
uv_inet_ntop(host->h_addrtype, *a, ip, sizeof ip);
|
|
463
|
+
append(ctx, records, str(ctx, ip));
|
|
464
|
+
}
|
|
465
|
+
for (int i = 0; i < n; i++) {
|
|
466
|
+
int ttl = type == ARES_REC_TYPE_A ? ((struct ares_addrttl *)addrttls)[i].ttl : ((struct ares_addr6ttl *)addrttls)[i].ttl;
|
|
467
|
+
append(ctx, ttls, js_number((double)(unsigned)ttl));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
ares_free_hostent(host);
|
|
471
|
+
}
|
|
472
|
+
free(addrttls);
|
|
473
|
+
return status;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
static int mx(JSContext *ctx, const uint8_t *buf, int len, JSValue records) {
|
|
477
|
+
struct ares_mx_reply *start;
|
|
478
|
+
int status = ares_parse_mx_reply(buf, len, &start);
|
|
479
|
+
if (status != ARES_SUCCESS) return status;
|
|
480
|
+
for (struct ares_mx_reply *r = start; r; r = r->next) {
|
|
481
|
+
JSValue items[2] = { js_int32(r->priority), str(ctx, r->host) };
|
|
482
|
+
append(ctx, records, array_of(ctx, items, 2));
|
|
483
|
+
}
|
|
484
|
+
ares_free_data(start);
|
|
485
|
+
return status;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/* each record's strings (a record may be several) */
|
|
489
|
+
static int txt(JSContext *ctx, const uint8_t *buf, int len, JSValue records) {
|
|
490
|
+
struct ares_txt_ext *start;
|
|
491
|
+
int status = ares_parse_txt_reply_ext(buf, len, &start);
|
|
492
|
+
if (status != ARES_SUCCESS) return status;
|
|
493
|
+
JSValue chunks = JS_UNDEFINED;
|
|
494
|
+
for (struct ares_txt_ext *r = start; r; r = r->next) {
|
|
495
|
+
if (r->record_start || js_is_undefined(chunks)) {
|
|
496
|
+
chunks = js_new_array(ctx, 0);
|
|
497
|
+
append(ctx, records, chunks);
|
|
498
|
+
}
|
|
499
|
+
append(ctx, chunks, js_new_string_latin1(ctx, (const uint8_t *)r->txt, r->length));
|
|
500
|
+
}
|
|
501
|
+
ares_free_data(start);
|
|
502
|
+
return status;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
static int srv(JSContext *ctx, const uint8_t *buf, int len, JSValue records) {
|
|
506
|
+
struct ares_srv_reply *start;
|
|
507
|
+
int status = ares_parse_srv_reply(buf, len, &start);
|
|
508
|
+
if (status != ARES_SUCCESS) return status;
|
|
509
|
+
for (struct ares_srv_reply *r = start; r; r = r->next) {
|
|
510
|
+
JSValue items[4] = { str(ctx, r->host), js_int32(r->port), js_int32(r->priority), js_int32(r->weight) };
|
|
511
|
+
append(ctx, records, array_of(ctx, items, 4));
|
|
512
|
+
}
|
|
513
|
+
ares_free_data(start);
|
|
514
|
+
return status;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
static int naptr(JSContext *ctx, const uint8_t *buf, int len, JSValue records) {
|
|
518
|
+
struct ares_naptr_reply *start;
|
|
519
|
+
int status = ares_parse_naptr_reply(buf, len, &start);
|
|
520
|
+
if (status != ARES_SUCCESS) return status;
|
|
521
|
+
for (struct ares_naptr_reply *r = start; r; r = r->next) {
|
|
522
|
+
JSValue items[6] = { str(ctx, r->flags), str(ctx, r->service), str(ctx, r->regexp), str(ctx, r->replacement), js_int32(r->order),
|
|
523
|
+
js_int32(r->preference) };
|
|
524
|
+
append(ctx, records, array_of(ctx, items, 6));
|
|
525
|
+
}
|
|
526
|
+
ares_free_data(start);
|
|
527
|
+
return status;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
static int soa(JSContext *ctx, const uint8_t *buf, int len, JSValue records) {
|
|
531
|
+
struct ares_soa_reply *r;
|
|
532
|
+
int status = ares_parse_soa_reply(buf, len, &r);
|
|
533
|
+
if (status != ARES_SUCCESS) return status;
|
|
534
|
+
JSValue items[7] = { str(ctx, r->nsname), str(ctx, r->hostmaster), js_number(r->serial), js_number(r->refresh), js_number(r->retry),
|
|
535
|
+
js_number(r->expire), js_number(r->minttl) };
|
|
536
|
+
append(ctx, records, array_of(ctx, items, 7));
|
|
537
|
+
ares_free_data(r);
|
|
538
|
+
return status;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/* ANY's SOA (Node's ParseSoaReply): the answer's last SOA, none being no error */
|
|
542
|
+
static int soa_any(JSContext *ctx, const uint8_t *buf, int len, JSValue records) {
|
|
543
|
+
ares_dns_record_t *rec = NULL;
|
|
544
|
+
if (ares_dns_parse(buf, (size_t)len, 0, &rec) != ARES_SUCCESS) {
|
|
545
|
+
ares_dns_record_destroy(rec);
|
|
546
|
+
return ARES_EBADRESP;
|
|
547
|
+
}
|
|
548
|
+
const ares_dns_rr_t *found = NULL;
|
|
549
|
+
size_t n = ares_dns_record_rr_cnt(rec, ARES_SECTION_ANSWER);
|
|
550
|
+
for (size_t i = 0; i < n; i++) {
|
|
551
|
+
const ares_dns_rr_t *rr = ares_dns_record_rr_get(rec, ARES_SECTION_ANSWER, i);
|
|
552
|
+
if (ares_dns_rr_get_type(rr) == ARES_REC_TYPE_SOA) found = rr;
|
|
553
|
+
}
|
|
554
|
+
if (found) {
|
|
555
|
+
JSValue items[7] = { str(ctx, ares_dns_rr_get_str(found, ARES_RR_SOA_MNAME)), str(ctx, ares_dns_rr_get_str(found, ARES_RR_SOA_RNAME)),
|
|
556
|
+
js_number(ares_dns_rr_get_u32(found, ARES_RR_SOA_SERIAL)), js_number(ares_dns_rr_get_u32(found, ARES_RR_SOA_REFRESH)),
|
|
557
|
+
js_number(ares_dns_rr_get_u32(found, ARES_RR_SOA_RETRY)), js_number(ares_dns_rr_get_u32(found, ARES_RR_SOA_EXPIRE)),
|
|
558
|
+
js_number(ares_dns_rr_get_u32(found, ARES_RR_SOA_MINIMUM)) };
|
|
559
|
+
append(ctx, records, array_of(ctx, items, 7));
|
|
560
|
+
}
|
|
561
|
+
ares_dns_record_destroy(rec);
|
|
562
|
+
return ARES_SUCCESS;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
static int caa(JSContext *ctx, const uint8_t *buf, int len, JSValue records) {
|
|
566
|
+
struct ares_caa_reply *start;
|
|
567
|
+
int status = ares_parse_caa_reply(buf, len, &start);
|
|
568
|
+
if (status != ARES_SUCCESS) return status;
|
|
569
|
+
for (struct ares_caa_reply *r = start; r; r = r->next) {
|
|
570
|
+
JSValue items[3] = { js_int32(r->critical), js_new_string_latin1(ctx, (const uint8_t *)r->property, r->plength),
|
|
571
|
+
js_new_string_latin1(ctx, (const uint8_t *)r->value, r->length) };
|
|
572
|
+
append(ctx, records, array_of(ctx, items, 3));
|
|
573
|
+
}
|
|
574
|
+
ares_free_data(start);
|
|
575
|
+
return status;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/* TLSA, from the parsed message (c-ares has no legacy parser for it), as Node's */
|
|
579
|
+
static int tlsa(JSContext *ctx, const uint8_t *buf, int len, JSValue records) {
|
|
580
|
+
ares_dns_record_t *rec = NULL;
|
|
581
|
+
int status = ares_dns_parse(buf, (size_t)len, 0, &rec);
|
|
582
|
+
if (status != ARES_SUCCESS) {
|
|
583
|
+
ares_dns_record_destroy(rec);
|
|
584
|
+
return status;
|
|
585
|
+
}
|
|
586
|
+
size_t n = ares_dns_record_rr_cnt(rec, ARES_SECTION_ANSWER);
|
|
587
|
+
for (size_t i = 0; i < n; i++) {
|
|
588
|
+
const ares_dns_rr_t *rr = ares_dns_record_rr_get(rec, ARES_SECTION_ANSWER, i);
|
|
589
|
+
if (ares_dns_rr_get_type(rr) != ARES_REC_TYPE_TLSA) continue;
|
|
590
|
+
size_t data_len;
|
|
591
|
+
const unsigned char *data = ares_dns_rr_get_bin(rr, ARES_RR_TLSA_DATA, &data_len);
|
|
592
|
+
if (!data || data_len == 0) continue;
|
|
593
|
+
JSValue items[4] = { js_int32(ares_dns_rr_get_u8(rr, ARES_RR_TLSA_CERT_USAGE)), js_int32(ares_dns_rr_get_u8(rr, ARES_RR_TLSA_SELECTOR)),
|
|
594
|
+
js_int32(ares_dns_rr_get_u8(rr, ARES_RR_TLSA_MATCH)), js_new_buffer_from_bytes(ctx, data, data_len) };
|
|
595
|
+
append(ctx, records, array_of(ctx, items, 4));
|
|
596
|
+
}
|
|
597
|
+
ares_dns_record_destroy(rec);
|
|
598
|
+
return ARES_SUCCESS;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
HOST_FN(js_host_dns_parse) {
|
|
602
|
+
UNUSED;
|
|
603
|
+
uint8_t *buf;
|
|
604
|
+
size_t len;
|
|
605
|
+
if (!js_buffer_source_bytes(ARG(0), &buf, &len) || !js_is_number(ARG(1))) return js_throw_type_error(ctx, "dnsParse: (answer, kind) expected");
|
|
606
|
+
int kind = (int)js_as_number(ARG(1));
|
|
607
|
+
JSValue records = js_new_array(ctx, 0), ttls = js_new_array(ctx, 0);
|
|
608
|
+
bool cname = false;
|
|
609
|
+
int status;
|
|
610
|
+
switch (kind) {
|
|
611
|
+
case ARES_REC_TYPE_MX: status = mx(ctx, buf, (int)len, records); break;
|
|
612
|
+
case ARES_REC_TYPE_TXT: status = txt(ctx, buf, (int)len, records); break;
|
|
613
|
+
case ARES_REC_TYPE_SRV: status = srv(ctx, buf, (int)len, records); break;
|
|
614
|
+
case ARES_REC_TYPE_NAPTR: status = naptr(ctx, buf, (int)len, records); break;
|
|
615
|
+
case ARES_REC_TYPE_SOA: status = soa(ctx, buf, (int)len, records); break;
|
|
616
|
+
case KIND_SOA_IN_ANY: status = soa_any(ctx, buf, (int)len, records); break;
|
|
617
|
+
case ARES_REC_TYPE_CAA: status = caa(ctx, buf, (int)len, records); break;
|
|
618
|
+
case ARES_REC_TYPE_TLSA: status = tlsa(ctx, buf, (int)len, records); break;
|
|
619
|
+
default: status = general(ctx, buf, (int)len, kind, records, ttls, &cname); break;
|
|
620
|
+
}
|
|
621
|
+
JSValue items[4] = { js_int32(status), records, ttls, js_bool(cname) };
|
|
622
|
+
return js_new_array_from(ctx, items, 4);
|
|
623
|
+
}
|
package/node/src/host_http.c
CHANGED
|
@@ -85,6 +85,7 @@ struct Conn {
|
|
|
85
85
|
JSValue headers; /* the head's or the trailers' [k, v, …] being parsed (a root) */
|
|
86
86
|
bool in_value;
|
|
87
87
|
bool queued; /* in `pending`: `out` goes out at the next flush */
|
|
88
|
+
double written; /* the bytes JS has written to it, for the socket's bytesWritten */
|
|
88
89
|
Buf out; /* written but not sent: corked, as Node corks a response */
|
|
89
90
|
};
|
|
90
91
|
|
|
@@ -141,6 +142,8 @@ static JSValue bytes_value(JSContext *ctx, const char *at, size_t n) {
|
|
|
141
142
|
static void push_header(Conn *c) {
|
|
142
143
|
JSContext *ctx = ctx_();
|
|
143
144
|
if (js_is_undefined(c->headers)) c->headers = js_new_array(ctx, 0); /* the first trailer */
|
|
145
|
+
/* as Node's parser: trailing whitespace off the value (llhttp leaves it when a read splits it) */
|
|
146
|
+
while (c->value.n > 0 && (c->value.v[c->value.n - 1] == ' ' || c->value.v[c->value.n - 1] == '\t')) c->value.n--;
|
|
144
147
|
JSValue k = latin1(ctx, &c->field), v = latin1(ctx, &c->value);
|
|
145
148
|
if (js_array_push(ctx, js_as_object(c->headers), k) < 0 || js_array_push(ctx, js_as_object(c->headers), v) < 0) js_fatal("out of memory in http");
|
|
146
149
|
c->field.n = c->value.n = 0;
|
|
@@ -500,6 +503,13 @@ JSValue js_host_http_pending(JSContext *ctx, JSValue callee, JSValue this_val, u
|
|
|
500
503
|
return js_number(c ? (double)pending_bytes(c) : 0);
|
|
501
504
|
}
|
|
502
505
|
|
|
506
|
+
/* httpWritten(conn) → the bytes written to it, sent or not */
|
|
507
|
+
JSValue js_host_http_written(JSContext *ctx, JSValue callee, JSValue this_val, uint32_t argc, const JSValue *argv, JSValue new_target) {
|
|
508
|
+
(void)ctx, (void)callee, (void)this_val, (void)new_target;
|
|
509
|
+
Conn *c = argc > 0 && js_is_int32(argv[0]) ? conn_of(js_as_int32(argv[0])) : NULL;
|
|
510
|
+
return js_number(c ? c->written : 0);
|
|
511
|
+
}
|
|
512
|
+
|
|
503
513
|
/* httpWatchDrain(conn) → true when nothing is pending (drained already), else the parsers' onDrain
|
|
504
514
|
* is called once it all has gone out */
|
|
505
515
|
JSValue js_host_http_watch_drain(JSContext *ctx, JSValue callee, JSValue this_val, uint32_t argc, const JSValue *argv, JSValue new_target) {
|
|
@@ -615,6 +625,7 @@ JSValue js_host_http_write(JSContext *ctx, JSValue callee, JSValue this_val, uin
|
|
|
615
625
|
(void)callee, (void)this_val, (void)new_target;
|
|
616
626
|
Conn *c = argc > 0 && js_is_int32(argv[0]) ? conn_of(js_as_int32(argv[0])) : NULL;
|
|
617
627
|
if (!c || argc < 2 || (c->id >= 0 && !js_net_stream(c->id))) return JS_FALSE;
|
|
628
|
+
size_t before = c->out.n;
|
|
618
629
|
if (js_is_string(argv[1]) && argc > 2 && js_truthy(argv[2])) {
|
|
619
630
|
JSStrView v = js_string_view(ctx, argv[1]);
|
|
620
631
|
if (v.length == 0) return JS_TRUE;
|
|
@@ -636,6 +647,7 @@ JSValue js_host_http_write(JSContext *ctx, JSValue callee, JSValue this_val, uin
|
|
|
636
647
|
if (n == 0) return JS_TRUE;
|
|
637
648
|
buf_append(&c->out, (const char *)bytes, n);
|
|
638
649
|
}
|
|
650
|
+
c->written += (double)(c->out.n - before);
|
|
639
651
|
if (!c->queued) {
|
|
640
652
|
if (npending == pending_cap) {
|
|
641
653
|
pending_cap = pending_cap ? pending_cap * 2 : 64;
|