@scriptc/runtime 0.0.13 → 0.0.15
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/package.json +1 -1
- package/src/scr_http.c +49 -22
- package/src/scr_http2.c +6 -1
- package/src/scr_runtime.h +13 -0
- package/src/scr_tls.c +30 -1
package/package.json
CHANGED
package/src/scr_http.c
CHANGED
|
@@ -2911,8 +2911,23 @@ static ScrHttpClientReq *scr_http_request_impl(ScrStr *host /*borrowed*/, double
|
|
|
2911
2911
|
if (cb) scr_net_ls_add(&c->resp_ls, cb, (void *)fn, true);
|
|
2912
2912
|
|
|
2913
2913
|
/* dial — or take the caller's pre-made socket (createConnection); dial
|
|
2914
|
-
* failures are the async 'error' either way, the net story
|
|
2915
|
-
|
|
2914
|
+
* failures are the async 'error' either way, the net story.
|
|
2915
|
+
*
|
|
2916
|
+
* The hostname resolves HERE, at the client dial, the way the island's
|
|
2917
|
+
* client and the native fetch resolve at theirs: node:net's own connect
|
|
2918
|
+
* surface stays resolver-less on purpose (Node's async lookup semantics
|
|
2919
|
+
* are not this), so a client that dials by name has to ask. Only the
|
|
2920
|
+
* dial takes the address — c->host keeps the ORIGINAL name, which is
|
|
2921
|
+
* what the Host header carries and what the caller built the TLS
|
|
2922
|
+
* client's SNI from. An unresolvable name comes back unchanged and the
|
|
2923
|
+
* dial delivers Node's deferred ENOTFOUND. */
|
|
2924
|
+
if (presock != NULL) {
|
|
2925
|
+
c->sock = presock;
|
|
2926
|
+
} else {
|
|
2927
|
+
ScrStr *dial = scr_net_blocking_lookup(host);
|
|
2928
|
+
c->sock = scr_net_connect(port, dial, NULL);
|
|
2929
|
+
scr_str_release(dial);
|
|
2930
|
+
}
|
|
2916
2931
|
ScrHttpConn *conn = calloc(1, sizeof *conn);
|
|
2917
2932
|
if (!conn) scr_http_oom();
|
|
2918
2933
|
conn->sock = c->sock; /* borrowed */
|
|
@@ -4481,41 +4496,54 @@ void scr_http_client_end_dynv(ScrHttpClientReq *c, const ScrDyn *d) {
|
|
|
4481
4496
|
* result +1 or NULL with the exception pending. */
|
|
4482
4497
|
#include "scr_url_internal.h"
|
|
4483
4498
|
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
ScrHttpRespFn fn) {
|
|
4499
|
+
bool scr_http_url_parts(ScrStr *url /*borrowed*/, bool secure, ScrStr **host_out /*+1*/,
|
|
4500
|
+
double *port_out, ScrStr **path_out /*+1*/) {
|
|
4487
4501
|
ScrUrl *u = scr_url_new(url);
|
|
4488
|
-
if (!u)
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4502
|
+
if (!u) return false; /* Invalid URL pending */
|
|
4503
|
+
/* The scheme is checked against the MODULE the call came from, not read
|
|
4504
|
+
* off the URL: http.get('https://…') is Node's ERR_INVALID_PROTOCOL, not
|
|
4505
|
+
* a silent upgrade. Hence `secure` as a parameter. */
|
|
4506
|
+
const char *want = secure ? "https" : "http";
|
|
4507
|
+
const size_t wantlen = secure ? 5 : 4;
|
|
4508
|
+
if (!(u->scheme->len == wantlen && memcmp(u->scheme->data, want, wantlen) == 0)) {
|
|
4493
4509
|
char msg[128];
|
|
4494
|
-
int n = snprintf(msg, sizeof msg, "Protocol \"%.*s:\" not supported. Expected \"
|
|
4495
|
-
(int)(u->scheme->len < 32 ? u->scheme->len : 32), u->scheme->data);
|
|
4510
|
+
int n = snprintf(msg, sizeof msg, "Protocol \"%.*s:\" not supported. Expected \"%s:\"",
|
|
4511
|
+
(int)(u->scheme->len < 32 ? u->scheme->len : 32), u->scheme->data, want);
|
|
4496
4512
|
scr_throw_error_msg_code(SCR_ERR_TYPE, msg, (size_t)n, "ERR_INVALID_PROTOCOL");
|
|
4497
4513
|
scr_url_release(u);
|
|
4498
|
-
|
|
4499
|
-
return NULL;
|
|
4514
|
+
return false;
|
|
4500
4515
|
}
|
|
4501
|
-
double port = 80;
|
|
4516
|
+
double port = secure ? 443 : 80;
|
|
4502
4517
|
if (u->port->len > 0) {
|
|
4503
4518
|
port = 0;
|
|
4504
4519
|
for (size_t i = 0; i < u->port->len; i++) port = port * 10 + (u->port->data[i] - '0');
|
|
4505
4520
|
}
|
|
4506
4521
|
/* IPv6 authority arrives bracketed ("[::1]") — the dial wants the bare
|
|
4507
4522
|
* address, like Node's client strips them. */
|
|
4508
|
-
ScrStr *host;
|
|
4509
4523
|
if (u->host->len >= 2 && u->host->data[0] == '[' && u->host->data[u->host->len - 1] == ']') {
|
|
4510
|
-
|
|
4524
|
+
*host_out = scr_str_new(u->host->data + 1, u->host->len - 2);
|
|
4511
4525
|
} else {
|
|
4512
|
-
|
|
4526
|
+
*host_out = scr_str_retain(u->host);
|
|
4513
4527
|
}
|
|
4514
|
-
ScrStr *path;
|
|
4515
4528
|
if (u->query->len > 0) {
|
|
4516
|
-
|
|
4529
|
+
*path_out = scr_str_concat(u->path, u->query);
|
|
4517
4530
|
} else {
|
|
4518
|
-
|
|
4531
|
+
*path_out = u->path->len > 0 ? scr_str_retain(u->path) : scr_str_new("/", 1);
|
|
4532
|
+
}
|
|
4533
|
+
*port_out = port;
|
|
4534
|
+
scr_url_release(u);
|
|
4535
|
+
return true;
|
|
4536
|
+
}
|
|
4537
|
+
|
|
4538
|
+
ScrHttpClientReq *scr_http_request_url(ScrStr *url /*borrowed*/, ScrStr *method /*borrowed*/,
|
|
4539
|
+
bool auto_end, ScrClosure *cb /*moves, nullable*/,
|
|
4540
|
+
ScrHttpRespFn fn) {
|
|
4541
|
+
ScrStr *host;
|
|
4542
|
+
ScrStr *path;
|
|
4543
|
+
double port;
|
|
4544
|
+
if (!scr_http_url_parts(url, false, &host, &port, &path)) {
|
|
4545
|
+
if (cb) scr_closure_release(cb);
|
|
4546
|
+
return NULL; /* Invalid URL / ERR_INVALID_PROTOCOL pending */
|
|
4519
4547
|
}
|
|
4520
4548
|
ScrArr *pairs = scr_arr_new(SCR_ELEM_STR, 0); /* request_impl reads the pairs array */
|
|
4521
4549
|
ScrHttpClientReq *c = scr_http_request_ex(host, port, path, method, 0, pairs, auto_end,
|
|
@@ -4523,6 +4551,5 @@ ScrHttpClientReq *scr_http_request_url(ScrStr *url /*borrowed*/, ScrStr *method
|
|
|
4523
4551
|
scr_arr_release(pairs);
|
|
4524
4552
|
scr_str_release(host);
|
|
4525
4553
|
scr_str_release(path);
|
|
4526
|
-
scr_url_release(u);
|
|
4527
4554
|
return c;
|
|
4528
4555
|
}
|
package/src/scr_http2.c
CHANGED
|
@@ -2440,7 +2440,12 @@ ScrH2Session *scr_http2_connect(ScrStr *url /*borrowed*/, bool reject_unauthoriz
|
|
|
2440
2440
|
/* stash the authority in the session's hblock buf slot? No — its own
|
|
2441
2441
|
* field: reuse rbuf? Neither: a dedicated malloc. */
|
|
2442
2442
|
ScrStr *host_str = scr_str_new(host, hlen);
|
|
2443
|
-
|
|
2443
|
+
/* Resolve for the dial only (the http client's rule): the TLS wrap below
|
|
2444
|
+
* takes host_str, the NAME, because that is what SNI and verification
|
|
2445
|
+
* must see. */
|
|
2446
|
+
ScrStr *dial_addr = scr_net_blocking_lookup(host_str);
|
|
2447
|
+
ScrNetSocket *sock = scr_net_connect(port, dial_addr, NULL);
|
|
2448
|
+
scr_str_release(dial_addr);
|
|
2444
2449
|
if (secure) scr_tls_h2_client_wrap(sock, host_str, reject_unauthorized, ca, ca_len);
|
|
2445
2450
|
scr_str_release(host_str);
|
|
2446
2451
|
s->sock = sock; /* scr_net_connect returned +1 — the session takes it */
|
package/src/scr_runtime.h
CHANGED
|
@@ -5327,6 +5327,12 @@ ScrHttpClientReq *scr_http_request_ex(ScrStr *host /*borrowed*/, double port,
|
|
|
5327
5327
|
ScrHttpClientReq *scr_http_request_url(ScrStr *url /*borrowed*/, ScrStr *method /*borrowed*/,
|
|
5328
5328
|
bool auto_end, ScrClosure *cb /*moves, nullable*/,
|
|
5329
5329
|
ScrHttpRespFn fn); /* +1 */
|
|
5330
|
+
/* Its parse half, shared with scr_tls.c's https spelling: the scheme is
|
|
5331
|
+
* checked against `secure` (the calling module), so a mismatch is Node's
|
|
5332
|
+
* ERR_INVALID_PROTOCOL rather than a silent upgrade. false = the
|
|
5333
|
+
* exception is pending and no out-parameter was written. */
|
|
5334
|
+
bool scr_http_url_parts(ScrStr *url /*borrowed*/, bool secure, ScrStr **host_out /*+1*/,
|
|
5335
|
+
double *port_out, ScrStr **path_out /*+1*/);
|
|
5330
5336
|
/* ── the http Agent (new http.Agent(opts) — option surface, getName, and
|
|
5331
5337
|
* the maxSockets queue over one-dial-per-request connections; keep-alive
|
|
5332
5338
|
* POOLING is not modeled: keepAlive: true fences at construction).
|
|
@@ -5514,6 +5520,13 @@ ScrHttpClientReq *scr_https_request(ScrStr *host /*borrowed*/, double port,
|
|
|
5514
5520
|
bool auto_end, bool reject_unauthorized,
|
|
5515
5521
|
const char *ca /*borrowed, len 0 = none*/, size_t ca_len,
|
|
5516
5522
|
ScrClosure *cb /*moves, nullable*/, ScrHttpRespFn fn); /* +1 */
|
|
5523
|
+
/* The URL-string form (https.get('https://host/path')): scr_http.c's
|
|
5524
|
+
* shared parse, then the options form's dial with Node's no-options
|
|
5525
|
+
* defaults (verification on, the default trust anchors). Throws
|
|
5526
|
+
* catchably on an unparsable input or a non-https scheme. */
|
|
5527
|
+
ScrHttpClientReq *scr_https_request_url(ScrStr *url /*borrowed*/, ScrStr *method /*borrowed*/,
|
|
5528
|
+
bool auto_end, ScrClosure *cb /*moves, nullable*/,
|
|
5529
|
+
ScrHttpRespFn fn); /* +1 */
|
|
5517
5530
|
/* The agent-threaded twin (the scr_http_request_agent story over TLS). */
|
|
5518
5531
|
ScrHttpClientReq *scr_https_request_agent(ScrStr *host /*borrowed*/, double port,
|
|
5519
5532
|
ScrStr *path /*borrowed*/, ScrStr *method /*borrowed*/,
|
package/src/scr_tls.c
CHANGED
|
@@ -1006,6 +1006,30 @@ ScrHttpClientReq *scr_https_request(ScrStr *host /*borrowed*/, double port,
|
|
|
1006
1006
|
fn, 443, &scr_tls_cli_wrap, cli);
|
|
1007
1007
|
}
|
|
1008
1008
|
|
|
1009
|
+
/* https.get('https://host/path') — the URL-string spelling, sharing
|
|
1010
|
+
* scr_http.c's parse (which rejects a non-https scheme here with Node's
|
|
1011
|
+
* ERR_INVALID_PROTOCOL) and dialing through the same per-request client
|
|
1012
|
+
* config as the options form. No options means Node's defaults: the
|
|
1013
|
+
* certificate is verified against the default trust anchors. */
|
|
1014
|
+
ScrHttpClientReq *scr_https_request_url(ScrStr *url /*borrowed*/, ScrStr *method /*borrowed*/,
|
|
1015
|
+
bool auto_end, ScrClosure *cb /*moves, nullable*/,
|
|
1016
|
+
ScrHttpRespFn fn) {
|
|
1017
|
+
ScrStr *host;
|
|
1018
|
+
ScrStr *path;
|
|
1019
|
+
double port;
|
|
1020
|
+
if (!scr_http_url_parts(url, true, &host, &port, &path)) {
|
|
1021
|
+
if (cb) scr_closure_release(cb);
|
|
1022
|
+
return NULL; /* Invalid URL / ERR_INVALID_PROTOCOL pending */
|
|
1023
|
+
}
|
|
1024
|
+
ScrArr *pairs = scr_arr_new(SCR_ELEM_STR, 0);
|
|
1025
|
+
ScrHttpClientReq *c = scr_https_request(host, port, path, method, 0, pairs, auto_end,
|
|
1026
|
+
true /* rejectUnauthorized */, NULL, 0, cb, fn);
|
|
1027
|
+
scr_arr_release(pairs);
|
|
1028
|
+
scr_str_release(host);
|
|
1029
|
+
scr_str_release(path);
|
|
1030
|
+
return c;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1009
1033
|
ScrHttpClientReq *scr_https_request_agent(ScrStr *host /*borrowed*/, double port,
|
|
1010
1034
|
ScrStr *path /*borrowed*/, ScrStr *method /*borrowed*/,
|
|
1011
1035
|
double timeout_ms, ScrArr *header_pairs /*borrowed*/,
|
|
@@ -1516,7 +1540,12 @@ ScrNetSocket *scr_tls_connect_dyn(double port, ScrStr *host /*borrowed, nullable
|
|
|
1516
1540
|
localhost_fallback = scr_str_new("localhost", 9);
|
|
1517
1541
|
verify_host = localhost_fallback;
|
|
1518
1542
|
}
|
|
1519
|
-
|
|
1543
|
+
/* Resolve for the dial only (the http client's rule): verify_host above
|
|
1544
|
+
* already holds the NAME, which is what SNI and certificate verification
|
|
1545
|
+
* must see. A null dial_host stays null — scr_net_connect's own arm. */
|
|
1546
|
+
ScrStr *dial_addr = dial_host != NULL ? scr_net_blocking_lookup(dial_host) : NULL;
|
|
1547
|
+
ScrNetSocket *s = scr_net_connect(port, dial_addr, cb); /* cb fires post-handshake — secureConnect */
|
|
1548
|
+
if (dial_addr) scr_str_release(dial_addr);
|
|
1520
1549
|
ScrTlsCli *cli = scr_tls_cli_new2(verify_host, reject,
|
|
1521
1550
|
ca != NULL ? (const char *)ca->data : NULL,
|
|
1522
1551
|
ca != NULL ? ca->len : 0, !reject);
|