@scriptc/cli-darwin-arm64 0.2.2 → 0.2.4
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/dist/THIRD_PARTY_NOTICES +1 -1
- package/dist/bin/scriptc +0 -0
- package/dist/bin/scriptc.json +1 -1
- package/dist/lib/declarations/scriptc-node-fallback.d.ts +99 -27
- package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
- package/dist/lib/llvm/package.json +1 -1
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/default/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_island.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/dev/runtime/dynamic/scr_web.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/library-thread-release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/default/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_island.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-arm64/artifacts/release/runtime/dynamic/scr_web.o +0 -0
- package/dist/lib/runtime-darwin-arm64/package.json +1 -1
- package/dist/lib/runtime-darwin-arm64/runtime-pack.json +399 -273
- package/dist/lib/runtime-sources/package.json +1 -1
- package/dist/lib/runtime-sources/src/scr_array.c +55 -34
- package/dist/lib/runtime-sources/src/scr_assert.c +26 -0
- package/dist/lib/runtime-sources/src/scr_async.c +44 -0
- package/dist/lib/runtime-sources/src/scr_bigint.c +15 -0
- package/dist/lib/runtime-sources/src/scr_bytes_io.c +305 -48
- package/dist/lib/runtime-sources/src/scr_cycle.c +84 -60
- package/dist/lib/runtime-sources/src/scr_events.c +9 -0
- package/dist/lib/runtime-sources/src/scr_exception.c +1 -0
- package/dist/lib/runtime-sources/src/scr_file_handle.c +11 -0
- package/dist/lib/runtime-sources/src/scr_island.c +1001 -417
- package/dist/lib/runtime-sources/src/scr_island_manifest.h +11 -7
- package/dist/lib/runtime-sources/src/scr_json.c +150 -13
- package/dist/lib/runtime-sources/src/scr_lib.c +424 -28
- package/dist/lib/runtime-sources/src/scr_map.c +236 -40
- package/dist/lib/runtime-sources/src/scr_node_builtin.c +78 -0
- package/dist/lib/runtime-sources/src/scr_regex.c +112 -8
- package/dist/lib/runtime-sources/src/scr_runtime.h +108 -14
- package/dist/lib/runtime-sources/src/scr_string.c +29 -0
- package/dist/lib/runtime-sources/src/scr_symbol.c +5 -0
- package/dist/lib/runtime-sources/src/scr_system_errors.h +573 -0
- package/dist/lib/runtime-sources/src/scr_url.c +515 -59
- package/dist/lib/runtime-sources/src/scr_url_internal.h +6 -0
- package/dist/lib/runtime-sources/src/scr_url_params.c +10 -0
- package/dist/lib/runtime-sources/src/scr_util_compare.c +222 -0
- package/dist/lib/runtime-sources/src/scr_util_style.c +337 -0
- package/dist/lib/runtime-sources/src/scr_web.c +720 -238
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* The WHATWG URL slice (scr_runtime.h has the API contract):
|
|
1
|
+
/* The WHATWG URL slice (scr_runtime.h has the API contract): a mutable,
|
|
2
2
|
* refcounted URL value parsed once at construction, plus the file-URL
|
|
3
3
|
* bridge pair (fileURLToPath / pathToFileURL).
|
|
4
4
|
*
|
|
@@ -197,7 +197,7 @@ static void ub_push_encoded(UrlBuf *b, unsigned char c, bool (*needs)(unsigned c
|
|
|
197
197
|
/* ── parsing ─────────────────────────────────────────────────────────── */
|
|
198
198
|
|
|
199
199
|
static void scr_url_throw_invalid(void) {
|
|
200
|
-
|
|
200
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE, "Invalid URL", 11, "ERR_INVALID_URL");
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
static bool is_special_scheme(const char *s, size_t len) {
|
|
@@ -322,6 +322,47 @@ static ScrStr *parse_rooted_path(const char *raw, size_t len, bool special) {
|
|
|
322
322
|
return parse_rooted_path_mode(raw, len, special, false);
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
/* Shared constructor/setter host parsing keeps the existing ASCII-host
|
|
326
|
+
* boundary and canonical IPv6 serialization in both execution tiers. */
|
|
327
|
+
static bool parse_host(const char *hp, size_t host_len, bool special, bool is_file,
|
|
328
|
+
ScrStr **host) {
|
|
329
|
+
bool ipv6 = host_len > 0 && hp[0] == '[';
|
|
330
|
+
size_t ipv6_end = host_len ? host_len - 1 : 0;
|
|
331
|
+
if (ipv6 && (host_len < 3 || hp[ipv6_end] != ']')) return false;
|
|
332
|
+
/* Validate + lowercase (special) the host. Divergence: non-ASCII and
|
|
333
|
+
* %-escapes (IDNA territory) are rejected outright. */
|
|
334
|
+
UrlBuf hb;
|
|
335
|
+
ub_init(&hb);
|
|
336
|
+
if (ipv6) {
|
|
337
|
+
if (!ub_append_ipv6(&hb, hp + 1, ipv6_end - 1)) {
|
|
338
|
+
free(hb.data);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
} else {
|
|
342
|
+
for (size_t i = 0; i < host_len; i++) {
|
|
343
|
+
unsigned char c = (unsigned char)hp[i];
|
|
344
|
+
if (c >= 0x80 || c == '%' || c == ':' || c == '[' || c == ']' ||
|
|
345
|
+
c <= 0x20 || c == '#' || c == '/' || c == '<' || c == '>' ||
|
|
346
|
+
c == '?' || c == '@' || c == '\\' || c == '^' || c == '|') {
|
|
347
|
+
free(hb.data);
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
if (special && c >= 'A' && c <= 'Z') {
|
|
351
|
+
c = (unsigned char)(c - 'A' + 'a');
|
|
352
|
+
}
|
|
353
|
+
ub_push(&hb, (char)c);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
/* file: "localhost" normalizes to "" at parse time (Node). */
|
|
357
|
+
if (is_file && hb.len == 9 && memcmp(hb.data, "localhost", 9) == 0) hb.len = 0;
|
|
358
|
+
if (hb.len == 0 && special && !is_file) {
|
|
359
|
+
free(hb.data);
|
|
360
|
+
return false; /* http:// — special non-file needs a host */
|
|
361
|
+
}
|
|
362
|
+
*host = ub_take(&hb);
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
|
|
325
366
|
/* Parses `authority` (between the slashes and the path/query/fragment):
|
|
326
367
|
* [userinfo@]host[:port]. Returns false (throws) on invalid input. */
|
|
327
368
|
static bool parse_authority(const char *raw, size_t len, bool special, bool is_file,
|
|
@@ -376,37 +417,7 @@ static bool parse_authority(const char *raw, size_t len, bool special, bool is_f
|
|
|
376
417
|
}
|
|
377
418
|
host_len = colon >= 0 ? (size_t)colon : hp_len;
|
|
378
419
|
}
|
|
379
|
-
|
|
380
|
-
* %-escapes (IDNA territory) are rejected outright. */
|
|
381
|
-
UrlBuf hb;
|
|
382
|
-
ub_init(&hb);
|
|
383
|
-
if (ipv6) {
|
|
384
|
-
if (!ub_append_ipv6(&hb, hp + 1, ipv6_end - 1)) {
|
|
385
|
-
free(hb.data);
|
|
386
|
-
return false;
|
|
387
|
-
}
|
|
388
|
-
} else {
|
|
389
|
-
for (size_t i = 0; i < host_len; i++) {
|
|
390
|
-
unsigned char c = (unsigned char)hp[i];
|
|
391
|
-
if (c >= 0x80 || c == '%' || c == ':' || c == '[' || c == ']' ||
|
|
392
|
-
c <= 0x20 || c == '#' || c == '/' || c == '<' || c == '>' ||
|
|
393
|
-
c == '?' || c == '@' || c == '\\' || c == '^' || c == '|') {
|
|
394
|
-
free(hb.data);
|
|
395
|
-
return false;
|
|
396
|
-
}
|
|
397
|
-
if (special && c >= 'A' && c <= 'Z') {
|
|
398
|
-
c = (unsigned char)(c - 'A' + 'a');
|
|
399
|
-
}
|
|
400
|
-
ub_push(&hb, (char)c);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
/* file: "localhost" normalizes to "" at parse time (Node). */
|
|
404
|
-
if (is_file && hb.len == 9 && memcmp(hb.data, "localhost", 9) == 0) hb.len = 0;
|
|
405
|
-
if (hb.len == 0 && special && !is_file) {
|
|
406
|
-
free(hb.data);
|
|
407
|
-
return false; /* http:// — special non-file needs a host */
|
|
408
|
-
}
|
|
409
|
-
*host = ub_take(&hb);
|
|
420
|
+
if (!parse_host(hp, host_len, special, is_file, host)) return false;
|
|
410
421
|
/* Port: digits only, leading zeros stripped, defaults dropped. */
|
|
411
422
|
UrlBuf pb;
|
|
412
423
|
ub_init(&pb);
|
|
@@ -645,7 +656,9 @@ ScrUrl *scr_url_new(ScrStr *input) {
|
|
|
645
656
|
u->query = query;
|
|
646
657
|
u->fragment = fragment;
|
|
647
658
|
u->has_authority = has_authority;
|
|
659
|
+
u->host_path_escape = false;
|
|
648
660
|
u->sp_cache = NULL;
|
|
661
|
+
u->sp_reload = NULL;
|
|
649
662
|
return u;
|
|
650
663
|
}
|
|
651
664
|
|
|
@@ -797,12 +810,15 @@ ScrStr *scr_url_pathname(ScrUrl *u) { return scr_str_retain(u->path); }
|
|
|
797
810
|
* normalized form findRoute-style authority compares want (lowercased
|
|
798
811
|
* host, no default :443/:80). */
|
|
799
812
|
ScrStr *scr_url_host(ScrUrl *u) {
|
|
800
|
-
if (u->port->len == 0) return scr_str_retain(u->host);
|
|
813
|
+
if (u->port->len == 0 && !u->host_path_escape) return scr_str_retain(u->host);
|
|
801
814
|
UrlBuf b;
|
|
802
815
|
ub_init(&b);
|
|
803
816
|
ub_append(&b, u->host->data, u->host->len);
|
|
804
|
-
|
|
805
|
-
|
|
817
|
+
if (u->port->len) {
|
|
818
|
+
ub_push(&b, ':');
|
|
819
|
+
ub_append(&b, u->port->data, u->port->len);
|
|
820
|
+
}
|
|
821
|
+
if (u->host_path_escape) ub_append(&b, "/.", 2);
|
|
806
822
|
return ub_take(&b);
|
|
807
823
|
}
|
|
808
824
|
|
|
@@ -878,12 +894,289 @@ ScrStr *scr_url_href(ScrUrl *u) {
|
|
|
878
894
|
ub_append(&b, u->port->data, u->port->len);
|
|
879
895
|
}
|
|
880
896
|
}
|
|
897
|
+
/* A host-less hierarchical path starting with // must not serialize
|
|
898
|
+
* as an authority (the URL Standard's /. escape). */
|
|
899
|
+
if (u->host_path_escape || (!u->has_authority && u->path->len >= 2 && !memcmp(u->path->data, "//", 2))) ub_append(&b, "/.", 2);
|
|
881
900
|
ub_append(&b, u->path->data, u->path->len);
|
|
882
901
|
ub_append(&b, u->query->data, u->query->len);
|
|
883
902
|
ub_append(&b, u->fragment->data, u->fragment->len);
|
|
884
903
|
return ub_take(&b);
|
|
885
904
|
}
|
|
886
905
|
|
|
906
|
+
static bool url_opaque(ScrUrl *u) {
|
|
907
|
+
return !u->has_authority && (u->path->len == 0 || u->path->data[0] != '/');
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
static void url_strip_opaque_spaces(ScrUrl *u) {
|
|
911
|
+
if (!url_opaque(u) || u->query->len || u->fragment->len) return;
|
|
912
|
+
size_t end = u->path->len;
|
|
913
|
+
while (end && u->path->data[end - 1] == ' ') end--;
|
|
914
|
+
if (end != u->path->len) {
|
|
915
|
+
ScrStr *path = scr_str_new(u->path->data, end);
|
|
916
|
+
scr_str_release(u->path);
|
|
917
|
+
u->path = path;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/* Setter state overrides preserve the other components. Unlike the full
|
|
922
|
+
* parser they strip TAB/LF/CR without trimming surrounding spaces. */
|
|
923
|
+
static void url_copy_fields(ScrUrl *u, ScrUrl *next) {
|
|
924
|
+
scr_str_release(u->scheme); u->scheme = scr_str_retain(next->scheme);
|
|
925
|
+
scr_str_release(u->userinfo); u->userinfo = scr_str_retain(next->userinfo);
|
|
926
|
+
scr_str_release(u->host); u->host = scr_str_retain(next->host);
|
|
927
|
+
scr_str_release(u->port); u->port = scr_str_retain(next->port);
|
|
928
|
+
scr_str_release(u->path); u->path = scr_str_retain(next->path);
|
|
929
|
+
scr_str_release(u->query); u->query = scr_str_retain(next->query);
|
|
930
|
+
scr_str_release(u->fragment); u->fragment = scr_str_retain(next->fragment);
|
|
931
|
+
u->has_authority = next->has_authority;
|
|
932
|
+
u->host_path_escape = next->host_path_escape;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
static bool url_file(ScrUrl *u) {
|
|
936
|
+
return u->scheme->len == 4 && !memcmp(u->scheme->data, "file", 4);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
static bool url_cannot_have_credentials_or_port(ScrUrl *u) {
|
|
940
|
+
return !u->host->len || url_file(u) || url_opaque(u);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
static bool url_set_port(ScrUrl *u, const char *raw, size_t len, bool empty_input) {
|
|
944
|
+
if (url_cannot_have_credentials_or_port(u)) return false;
|
|
945
|
+
if (empty_input) {
|
|
946
|
+
scr_str_release(u->port);
|
|
947
|
+
u->port = scr_str_new("", 0);
|
|
948
|
+
return true;
|
|
949
|
+
}
|
|
950
|
+
if (!len) return true; /* TAB/LF/CR-only input leaves the port unchanged. */
|
|
951
|
+
if (raw[0] < '0' || raw[0] > '9') return false;
|
|
952
|
+
unsigned int number = 0;
|
|
953
|
+
for (size_t i = 0; i < len && raw[i] >= '0' && raw[i] <= '9'; i++) {
|
|
954
|
+
number = number * 10 + (unsigned int)(raw[i] - '0');
|
|
955
|
+
if (number > 65535) return false;
|
|
956
|
+
}
|
|
957
|
+
char digits[6];
|
|
958
|
+
size_t size = (size_t)snprintf(digits, sizeof digits, "%u", number);
|
|
959
|
+
const char *dflt = default_port(u->scheme->data, u->scheme->len);
|
|
960
|
+
scr_str_release(u->port);
|
|
961
|
+
u->port = scr_str_new(digits, dflt && strlen(dflt) == size && !memcmp(dflt, digits, size) ? 0 : size);
|
|
962
|
+
return true;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
static bool url_set_protocol(ScrUrl *u, const char *raw, size_t len) {
|
|
966
|
+
if (!len) return true;
|
|
967
|
+
if (!((raw[0] >= 'a' && raw[0] <= 'z') || (raw[0] >= 'A' && raw[0] <= 'Z'))) return false;
|
|
968
|
+
size_t end = 1;
|
|
969
|
+
while (end < len && ((raw[end] >= 'a' && raw[end] <= 'z') ||
|
|
970
|
+
(raw[end] >= 'A' && raw[end] <= 'Z') || (raw[end] >= '0' && raw[end] <= '9') ||
|
|
971
|
+
raw[end] == '+' || raw[end] == '-' || raw[end] == '.')) end++;
|
|
972
|
+
if (end < len && raw[end] != ':') return false;
|
|
973
|
+
UrlBuf normalized;
|
|
974
|
+
ub_init(&normalized);
|
|
975
|
+
for (size_t i = 0; i < end; i++) {
|
|
976
|
+
char c = raw[i];
|
|
977
|
+
ub_push(&normalized, c >= 'A' && c <= 'Z' ? (char)(c + 'a' - 'A') : c);
|
|
978
|
+
}
|
|
979
|
+
ScrStr *scheme = ub_take(&normalized);
|
|
980
|
+
bool special = is_special_scheme(scheme->data, scheme->len);
|
|
981
|
+
bool file = scheme->len == 4 && !memcmp(scheme->data, "file", 4);
|
|
982
|
+
if (is_special_scheme(u->scheme->data, u->scheme->len) != special ||
|
|
983
|
+
(file && (u->userinfo->len || u->port->len)) || (url_file(u) && !u->host->len)) {
|
|
984
|
+
scr_str_release(scheme);
|
|
985
|
+
/* Ada reports a successful unchanged URL for non-special targets,
|
|
986
|
+
* so these writes still replace the pre-conversion snapshot in Node. */
|
|
987
|
+
return !special;
|
|
988
|
+
}
|
|
989
|
+
scr_str_release(u->scheme);
|
|
990
|
+
u->scheme = scheme;
|
|
991
|
+
const char *dflt = default_port(scheme->data, scheme->len);
|
|
992
|
+
if (dflt && u->port->len == strlen(dflt) && !memcmp(u->port->data, dflt, u->port->len)) {
|
|
993
|
+
scr_str_release(u->port);
|
|
994
|
+
u->port = scr_str_new("", 0);
|
|
995
|
+
}
|
|
996
|
+
return true;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
static bool url_set_credentials(ScrUrl *u, ScrStr *value, bool username) {
|
|
1000
|
+
if (url_cannot_have_credentials_or_port(u)) return false;
|
|
1001
|
+
ScrStr *other = username ? scr_url_password(u) : scr_url_username(u);
|
|
1002
|
+
UrlBuf encoded;
|
|
1003
|
+
ub_init(&encoded);
|
|
1004
|
+
for (size_t i = 0; i < value->len; i++) ub_push_encoded(&encoded, (unsigned char)value->data[i], enc_userinfo);
|
|
1005
|
+
ScrStr *part = ub_take(&encoded);
|
|
1006
|
+
ScrStr *user = username ? part : other;
|
|
1007
|
+
ScrStr *pass = username ? other : part;
|
|
1008
|
+
UrlBuf combined;
|
|
1009
|
+
ub_init(&combined);
|
|
1010
|
+
ub_append(&combined, user->data, user->len);
|
|
1011
|
+
if (pass->len) {
|
|
1012
|
+
ub_push(&combined, ':');
|
|
1013
|
+
ub_append(&combined, pass->data, pass->len);
|
|
1014
|
+
}
|
|
1015
|
+
scr_str_release(u->userinfo);
|
|
1016
|
+
u->userinfo = ub_take(&combined);
|
|
1017
|
+
scr_str_release(other);
|
|
1018
|
+
scr_str_release(part);
|
|
1019
|
+
return true;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
static bool url_set_host(ScrUrl *u, const char *raw, size_t len, bool hostname) {
|
|
1023
|
+
if (url_opaque(u)) return false;
|
|
1024
|
+
bool file = url_file(u);
|
|
1025
|
+
bool special = is_special_scheme(u->scheme->data, u->scheme->len);
|
|
1026
|
+
size_t end = 0;
|
|
1027
|
+
bool bracket = false, colon = false;
|
|
1028
|
+
for (; end < len; end++) {
|
|
1029
|
+
char c = raw[end];
|
|
1030
|
+
if (c == '/' || c == '?' || c == '#' || (special && c == '\\')) break;
|
|
1031
|
+
if (!file && c == ':' && !bracket) { colon = true; break; }
|
|
1032
|
+
if (c == '[') bracket = true;
|
|
1033
|
+
if (c == ']') bracket = false;
|
|
1034
|
+
}
|
|
1035
|
+
if (colon && (hostname || !end)) return false;
|
|
1036
|
+
if (!end && !file && (special || u->userinfo->len || u->port->len)) return false;
|
|
1037
|
+
ScrStr *host = NULL;
|
|
1038
|
+
if (!parse_host(raw, end, special, file, &host)) return false;
|
|
1039
|
+
bool escaped_path = !u->has_authority && u->path->len >= 2 && !memcmp(u->path->data, "//", 2);
|
|
1040
|
+
scr_str_release(u->host);
|
|
1041
|
+
u->host = host;
|
|
1042
|
+
if (host->len || escaped_path) u->has_authority = true;
|
|
1043
|
+
if (colon) {
|
|
1044
|
+
u->host_path_escape = escaped_path;
|
|
1045
|
+
if (end + 1 < len) url_set_port(u, raw + end + 1, len - end - 1, false);
|
|
1046
|
+
}
|
|
1047
|
+
return true;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/* The result distinguishes successful state overrides from ignored writes:
|
|
1051
|
+
* only successful writes replace Node's pre-conversion URL snapshot. */
|
|
1052
|
+
static bool url_apply_component(ScrUrl *u, ScrStr *field, ScrStr *value) {
|
|
1053
|
+
if (field->len == 4 && !memcmp(field->data, "href", 4)) {
|
|
1054
|
+
ScrUrl *next = scr_url_new(value);
|
|
1055
|
+
if (!next) return false;
|
|
1056
|
+
url_copy_fields(u, next);
|
|
1057
|
+
scr_url_release(next);
|
|
1058
|
+
if (u->sp_cache) u->sp_reload(u->sp_cache, u->query);
|
|
1059
|
+
return true;
|
|
1060
|
+
}
|
|
1061
|
+
bool pathname = field->len == 8 && !memcmp(field->data, "pathname", 8);
|
|
1062
|
+
bool search = field->len == 6 && !memcmp(field->data, "search", 6);
|
|
1063
|
+
bool hash = field->len == 4 && !memcmp(field->data, "hash", 4);
|
|
1064
|
+
bool protocol = field->len == 8 && !memcmp(field->data, "protocol", 8);
|
|
1065
|
+
bool username = field->len == 8 && !memcmp(field->data, "username", 8);
|
|
1066
|
+
bool password = field->len == 8 && !memcmp(field->data, "password", 8);
|
|
1067
|
+
bool host = field->len == 4 && !memcmp(field->data, "host", 4);
|
|
1068
|
+
bool hostname = field->len == 8 && !memcmp(field->data, "hostname", 8);
|
|
1069
|
+
bool port = field->len == 4 && !memcmp(field->data, "port", 4);
|
|
1070
|
+
if (!pathname && !search && !hash && !protocol && !username && !password && !host && !hostname && !port) {
|
|
1071
|
+
static const char message[] = "Native URL setter has no lowering";
|
|
1072
|
+
scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020");
|
|
1073
|
+
return false;
|
|
1074
|
+
}
|
|
1075
|
+
if (username || password) return url_set_credentials(u, value, username);
|
|
1076
|
+
if (pathname && url_opaque(u)) return false;
|
|
1077
|
+
UrlBuf raw;
|
|
1078
|
+
ub_init(&raw);
|
|
1079
|
+
size_t start = (search || hash) && value->len && value->data[0] == (search ? '?' : '#') ? 1 : 0;
|
|
1080
|
+
for (size_t i = start; i < value->len; i++) {
|
|
1081
|
+
char c = value->data[i];
|
|
1082
|
+
if ((host || hostname) && c == '#') break;
|
|
1083
|
+
if (c != '\t' && c != '\n' && c != '\r') ub_push(&raw, c);
|
|
1084
|
+
}
|
|
1085
|
+
bool special = is_special_scheme(u->scheme->data, u->scheme->len);
|
|
1086
|
+
bool applied = true;
|
|
1087
|
+
if (protocol) applied = url_set_protocol(u, raw.data, raw.len);
|
|
1088
|
+
else if (port) applied = url_set_port(u, raw.data, raw.len, !value->len);
|
|
1089
|
+
else if (host || hostname) applied = url_set_host(u, raw.data, raw.len, hostname);
|
|
1090
|
+
else if (pathname) {
|
|
1091
|
+
bool file = u->scheme->len == 4 && !memcmp(u->scheme->data, "file", 4);
|
|
1092
|
+
ScrStr *path = parse_rooted_path_mode(raw.data, raw.len, special, file);
|
|
1093
|
+
if (!path->len && (special || !u->has_authority)) {
|
|
1094
|
+
scr_str_release(path);
|
|
1095
|
+
path = scr_str_new("/", 1);
|
|
1096
|
+
}
|
|
1097
|
+
scr_str_release(u->path);
|
|
1098
|
+
u->path = path;
|
|
1099
|
+
} else {
|
|
1100
|
+
UrlBuf encoded;
|
|
1101
|
+
ub_init(&encoded);
|
|
1102
|
+
if (value->len) {
|
|
1103
|
+
char prefix = search ? '?' : '#';
|
|
1104
|
+
ub_push(&encoded, prefix);
|
|
1105
|
+
for (size_t i = 0; i < raw.len; i++) {
|
|
1106
|
+
unsigned char c = (unsigned char)raw.data[i];
|
|
1107
|
+
bool needs = search ? enc_query(c, special) : enc_fragment(c);
|
|
1108
|
+
if (needs) {
|
|
1109
|
+
char hex[4];
|
|
1110
|
+
snprintf(hex, sizeof hex, "%%%02X", c);
|
|
1111
|
+
ub_append(&encoded, hex, 3);
|
|
1112
|
+
} else ub_push(&encoded, (char)c);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
ScrStr **slot = search ? &u->query : &u->fragment;
|
|
1116
|
+
scr_str_release(*slot);
|
|
1117
|
+
*slot = ub_take(&encoded);
|
|
1118
|
+
url_strip_opaque_spaces(u);
|
|
1119
|
+
if (search && u->sp_cache) u->sp_reload(u->sp_cache, u->query);
|
|
1120
|
+
}
|
|
1121
|
+
free(raw.data);
|
|
1122
|
+
return applied;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
bool scr_url_set_component(ScrUrl *u, ScrStr *field, ScrStr *value) {
|
|
1126
|
+
if (field->len == 4 && !memcmp(field->data, "href", 4)) return url_apply_component(u, field, value);
|
|
1127
|
+
/* Node's binding reparses the captured href before applying an override.
|
|
1128
|
+
* This matters after protocol writes to file://localhost and for the
|
|
1129
|
+
* host-to-port serialization escape. Ignored overrides retain the live URL. */
|
|
1130
|
+
ScrStr *href = scr_url_href(u);
|
|
1131
|
+
ScrUrl *next = scr_url_new(href);
|
|
1132
|
+
scr_str_release(href);
|
|
1133
|
+
if (!next) return false;
|
|
1134
|
+
bool applied = url_apply_component(next, field, value);
|
|
1135
|
+
if (applied) {
|
|
1136
|
+
url_copy_fields(u, next);
|
|
1137
|
+
if (field->len == 6 && !memcmp(field->data, "search", 6) && u->sp_cache) u->sp_reload(u->sp_cache, u->query);
|
|
1138
|
+
}
|
|
1139
|
+
scr_url_release(next);
|
|
1140
|
+
return applied;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
void scr_url_set(ScrUrl *u, ScrStr *field, ScrStr *value) {
|
|
1144
|
+
scr_url_set_component(u, field, value);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/* Node snapshots a component setter's URL before invoking user string
|
|
1148
|
+
* conversion. href converts first, and opaque pathname writes are ignored. */
|
|
1149
|
+
void scr_url_set_checked(ScrUrl *u, ScrStr *field, const ScrDyn *value) {
|
|
1150
|
+
bool href = field->len == 4 && !memcmp(field->data, "href", 4);
|
|
1151
|
+
bool ignored = field->len == 8 && !memcmp(field->data, "pathname", 8) && url_opaque(u);
|
|
1152
|
+
ScrUrl *saved = NULL;
|
|
1153
|
+
if (!href && !ignored) {
|
|
1154
|
+
saved = malloc(sizeof *saved);
|
|
1155
|
+
if (!saved) abort();
|
|
1156
|
+
*saved = *u;
|
|
1157
|
+
saved->rc = 1;
|
|
1158
|
+
saved->sp_cache = NULL;
|
|
1159
|
+
saved->sp_reload = NULL;
|
|
1160
|
+
saved->scheme = scr_str_retain(u->scheme);
|
|
1161
|
+
saved->userinfo = scr_str_retain(u->userinfo);
|
|
1162
|
+
saved->host = scr_str_retain(u->host);
|
|
1163
|
+
saved->port = scr_str_retain(u->port);
|
|
1164
|
+
saved->path = scr_str_retain(u->path);
|
|
1165
|
+
saved->query = scr_str_retain(u->query);
|
|
1166
|
+
saved->fragment = scr_str_retain(u->fragment);
|
|
1167
|
+
}
|
|
1168
|
+
ScrStr *text = scr_dyn_string_coerce_js(value);
|
|
1169
|
+
if (text && !ignored) {
|
|
1170
|
+
bool applied = scr_url_set_component(saved ? saved : u, field, text);
|
|
1171
|
+
if (saved && applied && !scr_exc_pending()) {
|
|
1172
|
+
url_copy_fields(u, saved);
|
|
1173
|
+
if (field->len == 6 && !memcmp(field->data, "search", 6) && u->sp_cache) u->sp_reload(u->sp_cache, u->query);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
scr_str_release(text);
|
|
1177
|
+
scr_url_release(saved);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
887
1180
|
/* ── the file-URL bridge ─────────────────────────────────────────────── */
|
|
888
1181
|
|
|
889
1182
|
static int hex_val(char c) {
|
|
@@ -893,15 +1186,36 @@ static int hex_val(char c) {
|
|
|
893
1186
|
return -1;
|
|
894
1187
|
}
|
|
895
1188
|
|
|
1189
|
+
static bool url_file_scheme(ScrUrl *u) {
|
|
1190
|
+
if (u->scheme->len == 4 && memcmp(u->scheme->data, "file", 4) == 0) return true;
|
|
1191
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE, "The URL must be of scheme file", 30, "ERR_INVALID_URL_SCHEME");
|
|
1192
|
+
return false;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
static bool url_file_posix_host(ScrUrl *u) {
|
|
1196
|
+
if (u->host->len == 0) return true;
|
|
1197
|
+
const char *platform =
|
|
1198
|
+
#if defined(__APPLE__)
|
|
1199
|
+
"darwin";
|
|
1200
|
+
#elif defined(__linux__)
|
|
1201
|
+
"linux";
|
|
1202
|
+
#elif defined(_WIN32)
|
|
1203
|
+
"win32";
|
|
1204
|
+
#else
|
|
1205
|
+
"posix";
|
|
1206
|
+
#endif
|
|
1207
|
+
char message[96];
|
|
1208
|
+
int length = snprintf(message, sizeof message, "File URL host must be \"localhost\" or empty on %s", platform);
|
|
1209
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE, message, (size_t)length, "ERR_INVALID_FILE_URL_HOST");
|
|
1210
|
+
return false;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
896
1213
|
/* fileURLToPath over a parsed URL: Node's checks, Node's messages. The
|
|
897
1214
|
* posix arm rejects hosts and keeps forward slashes; the win32 arm maps
|
|
898
1215
|
* hosts to UNC \\host prefixes, flips separators, and demands a drive
|
|
899
1216
|
* letter otherwise. The public wrappers below select by TARGET. */
|
|
900
1217
|
static ScrStr *scr_url_to_path_impl(ScrUrl *u, bool win32) {
|
|
901
|
-
if (!(u
|
|
902
|
-
scr_throw_error_msg_code(SCR_ERR_TYPE, "The URL must be of scheme file", 30, "ERR_INVALID_URL_SCHEME");
|
|
903
|
-
return NULL;
|
|
904
|
-
}
|
|
1218
|
+
if (!url_file_scheme(u)) return NULL;
|
|
905
1219
|
const char *p = u->path->data;
|
|
906
1220
|
size_t len = u->path->len;
|
|
907
1221
|
if (win32) {
|
|
@@ -951,23 +1265,7 @@ static ScrStr *scr_url_to_path_impl(ScrUrl *u, bool win32) {
|
|
|
951
1265
|
free(out.data);
|
|
952
1266
|
return s;
|
|
953
1267
|
}
|
|
954
|
-
if (u
|
|
955
|
-
/* Parse-time normalization already emptied "localhost". */
|
|
956
|
-
const char *plat =
|
|
957
|
-
#if defined(__APPLE__)
|
|
958
|
-
"darwin";
|
|
959
|
-
#elif defined(__linux__)
|
|
960
|
-
"linux";
|
|
961
|
-
#elif defined(_WIN32)
|
|
962
|
-
"win32";
|
|
963
|
-
#else
|
|
964
|
-
"posix";
|
|
965
|
-
#endif
|
|
966
|
-
char msg[96];
|
|
967
|
-
int mlen = snprintf(msg, sizeof msg, "File URL host must be \"localhost\" or empty on %s", plat);
|
|
968
|
-
scr_throw_error_msg_code(SCR_ERR_TYPE, msg, (size_t)mlen, "ERR_INVALID_FILE_URL_HOST");
|
|
969
|
-
return NULL;
|
|
970
|
-
}
|
|
1268
|
+
if (!url_file_posix_host(u)) return NULL;
|
|
971
1269
|
for (size_t i = 0; i < len; i++) {
|
|
972
1270
|
if (p[i] == '%' && i + 2 < len) {
|
|
973
1271
|
int hi = hex_val(p[i + 1]);
|
|
@@ -1021,7 +1319,9 @@ static ScrUrl *scr_url_new_file(ScrStr *host, ScrStr *encoded_path) {
|
|
|
1021
1319
|
u->query = scr_str_new("", 0);
|
|
1022
1320
|
u->fragment = scr_str_new("", 0);
|
|
1023
1321
|
u->has_authority = true;
|
|
1322
|
+
u->host_path_escape = false;
|
|
1024
1323
|
u->sp_cache = NULL;
|
|
1324
|
+
u->sp_reload = NULL;
|
|
1025
1325
|
return u;
|
|
1026
1326
|
}
|
|
1027
1327
|
|
|
@@ -1044,7 +1344,7 @@ static void scr_url_throw_arg_value(const char *reason, ScrStr *value) {
|
|
|
1044
1344
|
ub_append(&msg, reason, strlen(reason));
|
|
1045
1345
|
ub_append(&msg, ". Received ", 11);
|
|
1046
1346
|
ub_push_inspected(&msg, value->data, value->len);
|
|
1047
|
-
|
|
1347
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE, msg.data, msg.len, "ERR_INVALID_ARG_VALUE");
|
|
1048
1348
|
free(msg.data);
|
|
1049
1349
|
}
|
|
1050
1350
|
|
|
@@ -1233,10 +1533,21 @@ static ScrDyn *scr_native_url_invoke(void *ptr, ScrDyn *self, const char *method
|
|
|
1233
1533
|
return NULL;
|
|
1234
1534
|
}
|
|
1235
1535
|
|
|
1536
|
+
static bool scr_native_url_set(void *ptr, const char *key, size_t len, const ScrDyn *value) {
|
|
1537
|
+
bool modeled = (len == 4 && (!memcmp(key, "href", 4) || !memcmp(key, "hash", 4) || !memcmp(key, "host", 4) || !memcmp(key, "port", 4))) ||
|
|
1538
|
+
(len == 8 && (!memcmp(key, "pathname", 8) || !memcmp(key, "protocol", 8) || !memcmp(key, "username", 8) || !memcmp(key, "password", 8) || !memcmp(key, "hostname", 8))) ||
|
|
1539
|
+
(len == 6 && !memcmp(key, "search", 6));
|
|
1540
|
+
if (!modeled) return false;
|
|
1541
|
+
ScrStr *field = scr_str_new(key, len);
|
|
1542
|
+
scr_url_set_checked(ptr, field, value);
|
|
1543
|
+
scr_str_release(field);
|
|
1544
|
+
return true;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1236
1547
|
ScrDyn *scr_dyn_native_url(ScrUrl *value) {
|
|
1237
1548
|
static const ScrDynHandleOps ops = {
|
|
1238
1549
|
"URL", &scr_url_retain_v, &scr_url_release_v, &scr_native_url_invoke,
|
|
1239
|
-
&scr_native_url_get,
|
|
1550
|
+
&scr_native_url_get, &scr_native_url_set, NULL, NULL,
|
|
1240
1551
|
};
|
|
1241
1552
|
scr_dyn_handle_install(SCR_DYNH_URL, &ops);
|
|
1242
1553
|
return scr_dyn_new_handle(value, SCR_DYNH_URL);
|
|
@@ -1425,3 +1736,148 @@ ScrStr *scr_url_checked_to_path(const ScrDyn *value) {
|
|
|
1425
1736
|
scr_dyn_arg_type_fail("path", "of type string or an instance of URL", value);
|
|
1426
1737
|
return NULL;
|
|
1427
1738
|
}
|
|
1739
|
+
|
|
1740
|
+
/* Property reads keep option accessors/proxies live, including typed
|
|
1741
|
+
* record getter closures and objects held by the dynamic engine. */
|
|
1742
|
+
static ScrDyn *url_property_read(const ScrDyn *object, const char *name) {
|
|
1743
|
+
if (object->kind == SCR_DYN_TYPED_REF) {
|
|
1744
|
+
ScrDyn *view = scr_dyn_typed_ref_materialize(object);
|
|
1745
|
+
if (!view) return NULL;
|
|
1746
|
+
char getter_name[64];
|
|
1747
|
+
snprintf(getter_name, sizeof getter_name, "%%get:%s", name);
|
|
1748
|
+
const ScrDyn *getter = scr_dyn_obj_get(view, getter_name, strlen(getter_name));
|
|
1749
|
+
ScrDyn *value = getter ? scr_dyn_call(getter, NULL, 0, "getter") : url_property_read(view, name);
|
|
1750
|
+
scr_dyn_release(view);
|
|
1751
|
+
return value;
|
|
1752
|
+
}
|
|
1753
|
+
if (object->kind == SCR_DYN_JSVAL || object->kind == SCR_DYN_HANDLE) {
|
|
1754
|
+
ScrStr *key = scr_str_new(name, strlen(name));
|
|
1755
|
+
ScrDyn *value = object->kind == SCR_DYN_JSVAL ? scr_dyn_isl_key_get(object, key) : scr_dyn_handle_key_get(object, key);
|
|
1756
|
+
scr_str_release(key);
|
|
1757
|
+
return value;
|
|
1758
|
+
}
|
|
1759
|
+
return scr_dyn_obj_read(object, name, strlen(name));
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
/* options?.windows is a nullish default followed by JS truthiness. */
|
|
1763
|
+
static bool url_options_windows(const ScrDyn *options, bool *windows) {
|
|
1764
|
+
#ifdef _WIN32
|
|
1765
|
+
*windows = true;
|
|
1766
|
+
#else
|
|
1767
|
+
*windows = false;
|
|
1768
|
+
#endif
|
|
1769
|
+
if (scr_dyn_is_nullish(options)) return true;
|
|
1770
|
+
ScrDyn *value = url_property_read(options, "windows");
|
|
1771
|
+
if (!value || scr_exc_pending()) { scr_dyn_release(value); return false; }
|
|
1772
|
+
if (!scr_dyn_is_nullish(value)) *windows = scr_dyn_truthy(value);
|
|
1773
|
+
scr_dyn_release(value);
|
|
1774
|
+
return true;
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
static ScrUrl *url_checked_file_input(const ScrDyn *value) {
|
|
1778
|
+
if (scr_dyn_native_url_is(value)) return scr_url_retain(value->v.handle.ptr);
|
|
1779
|
+
if (value->kind == SCR_DYN_STR) return scr_url_new(value->v.str);
|
|
1780
|
+
/* Node's isURL checks href/protocol/auth/path structurally. Keep the
|
|
1781
|
+
* short circuit order and getter exceptions before its scheme check. */
|
|
1782
|
+
bool is_url = !scr_dyn_is_nullish(value);
|
|
1783
|
+
const char *keys[] = {"href", "protocol", "auth", "path"};
|
|
1784
|
+
for (size_t i = 0; is_url && i < 4; i++) {
|
|
1785
|
+
ScrDyn *property = url_property_read(value, keys[i]);
|
|
1786
|
+
if (!property || scr_exc_pending()) { scr_dyn_release(property); return NULL; }
|
|
1787
|
+
is_url = i < 2 ? scr_dyn_truthy(property) : property->kind == SCR_DYN_UNDEF;
|
|
1788
|
+
scr_dyn_release(property);
|
|
1789
|
+
}
|
|
1790
|
+
if (!is_url) {
|
|
1791
|
+
scr_dyn_arg_type_fail("path", "of type string or an instance of URL", value);
|
|
1792
|
+
return NULL;
|
|
1793
|
+
}
|
|
1794
|
+
ScrDyn *protocol = url_property_read(value, "protocol");
|
|
1795
|
+
if (!protocol || scr_exc_pending()) { scr_dyn_release(protocol); return NULL; }
|
|
1796
|
+
bool file = protocol->kind == SCR_DYN_STR && protocol->v.str->len == 5 && memcmp(protocol->v.str->data, "file:", 5) == 0;
|
|
1797
|
+
scr_dyn_release(protocol);
|
|
1798
|
+
if (!file) {
|
|
1799
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE, "The URL must be of scheme file", 30, "ERR_INVALID_URL_SCHEME");
|
|
1800
|
+
return NULL;
|
|
1801
|
+
}
|
|
1802
|
+
ScrDyn *host = url_property_read(value, "hostname");
|
|
1803
|
+
if (!host || scr_exc_pending()) { scr_dyn_release(host); return NULL; }
|
|
1804
|
+
ScrDyn *path = url_property_read(value, "pathname");
|
|
1805
|
+
if (!path || scr_exc_pending()) { scr_dyn_release(host); scr_dyn_release(path); return NULL; }
|
|
1806
|
+
if (host->kind != SCR_DYN_STR || path->kind != SCR_DYN_STR) {
|
|
1807
|
+
static const char message[] = "file URL-like objects require string hostname and pathname properties in scriptc";
|
|
1808
|
+
scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1);
|
|
1809
|
+
scr_dyn_release(host); scr_dyn_release(path);
|
|
1810
|
+
return NULL;
|
|
1811
|
+
}
|
|
1812
|
+
ScrUrl *url = scr_url_new_file(scr_str_retain(host->v.str), scr_str_retain(path->v.str));
|
|
1813
|
+
scr_dyn_release(host); scr_dyn_release(path);
|
|
1814
|
+
return url;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
ScrStr *scr_url_checked_to_path_options(const ScrDyn *value, const ScrDyn *options) {
|
|
1818
|
+
bool windows;
|
|
1819
|
+
if (!url_options_windows(options, &windows)) return NULL;
|
|
1820
|
+
ScrUrl *url = url_checked_file_input(value);
|
|
1821
|
+
if (!url) return NULL;
|
|
1822
|
+
ScrStr *path = scr_url_to_path_impl(url, windows);
|
|
1823
|
+
scr_url_release(url);
|
|
1824
|
+
return path;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
ScrUrl *scr_url_checked_from_path(const ScrDyn *value, const ScrDyn *options) {
|
|
1828
|
+
if (value->kind != SCR_DYN_STR) {
|
|
1829
|
+
scr_dyn_arg_type_fail("path", "of type string", value);
|
|
1830
|
+
return NULL;
|
|
1831
|
+
}
|
|
1832
|
+
bool windows;
|
|
1833
|
+
if (!url_options_windows(options, &windows)) return NULL;
|
|
1834
|
+
return scr_url_from_path_impl(value->v.str, windows);
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
ScrBytes *scr_url_checked_to_path_buffer(const ScrDyn *value, const ScrDyn *options) {
|
|
1838
|
+
bool windows;
|
|
1839
|
+
if (!url_options_windows(options, &windows)) return NULL;
|
|
1840
|
+
ScrUrl *url = url_checked_file_input(value);
|
|
1841
|
+
if (!url) return NULL;
|
|
1842
|
+
if (!url_file_scheme(url) || (!windows && !url_file_posix_host(url))) {
|
|
1843
|
+
scr_url_release(url);
|
|
1844
|
+
return NULL;
|
|
1845
|
+
}
|
|
1846
|
+
UrlBuf decoded;
|
|
1847
|
+
ub_init(&decoded);
|
|
1848
|
+
if (windows && url->host->len) {
|
|
1849
|
+
ub_append(&decoded, "\\\\", 2);
|
|
1850
|
+
ub_append(&decoded, url->host->data, url->host->len);
|
|
1851
|
+
}
|
|
1852
|
+
const char *path = url->path->data;
|
|
1853
|
+
for (size_t i = 0; i < url->path->len; i++) {
|
|
1854
|
+
if (path[i] == '%' && i + 2 < url->path->len) {
|
|
1855
|
+
int high = hex_val(path[i + 1]), low = hex_val(path[i + 2]);
|
|
1856
|
+
if (high >= 0 && low >= 0) {
|
|
1857
|
+
ub_push(&decoded, (char)((high << 4) | low));
|
|
1858
|
+
i += 2;
|
|
1859
|
+
continue;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
/* Convert literal separators before decoding: encoded %2F stays '/'.
|
|
1863
|
+
* Invalid escapes and invalid UTF-8 are preserved as raw bytes. */
|
|
1864
|
+
ub_push(&decoded, windows && path[i] == '/' ? '\\' : path[i]);
|
|
1865
|
+
}
|
|
1866
|
+
size_t start = 0;
|
|
1867
|
+
if (windows && url->host->len == 0) {
|
|
1868
|
+
int letter = (decoded.len > 1 ? (unsigned char)decoded.data[1] : 0) | 0x20;
|
|
1869
|
+
if (letter < 'a' || letter > 'z' || decoded.len < 3 || decoded.data[2] != ':') {
|
|
1870
|
+
free(decoded.data);
|
|
1871
|
+
scr_url_release(url);
|
|
1872
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE, "File URL path must be absolute", 30, "ERR_INVALID_FILE_URL_PATH");
|
|
1873
|
+
return NULL;
|
|
1874
|
+
}
|
|
1875
|
+
start = 1;
|
|
1876
|
+
}
|
|
1877
|
+
ScrBytes *result = scr_bytes_new(SCR_BYTES_U8, (double)(decoded.len - start));
|
|
1878
|
+
result->is_buffer = true;
|
|
1879
|
+
if (decoded.len > start) memcpy(result->data, decoded.data + start, decoded.len - start);
|
|
1880
|
+
free(decoded.data);
|
|
1881
|
+
scr_url_release(url);
|
|
1882
|
+
return result;
|
|
1883
|
+
}
|