@scriptc/cli-darwin-x64 0.2.1 → 0.2.3
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 +158 -31
- package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
- package/dist/lib/llvm/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_async_dyn.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_crypto_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_dyn_invoke.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_qs.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_async_dyn.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_crypto_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_dyn_invoke.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_island.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_qs.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_web.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_dyn_invoke.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_dyn_invoke.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_dyn_invoke.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_dyn_invoke.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_async_dyn.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_crypto_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_dyn_invoke.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_qs.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_assert.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_async_dyn.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_crypto_async.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_dyn_invoke.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_events.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_exception.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_file_handle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_island.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_node_builtin.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_qs.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_symbol.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_url.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_url_params.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_util_style.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_web.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/runtime-pack.json +423 -297
- package/dist/lib/runtime-sources/package.json +1 -1
- package/dist/lib/runtime-sources/src/scr_abort.c +5 -0
- package/dist/lib/runtime-sources/src/scr_array.c +5 -0
- package/dist/lib/runtime-sources/src/scr_assert.c +26 -0
- package/dist/lib/runtime-sources/src/scr_async.c +56 -4
- package/dist/lib/runtime-sources/src/scr_async_dyn.c +118 -24
- package/dist/lib/runtime-sources/src/scr_bytes.c +226 -0
- package/dist/lib/runtime-sources/src/scr_bytes_io.c +355 -51
- package/dist/lib/runtime-sources/src/scr_crypto_async.c +22 -2
- package/dist/lib/runtime-sources/src/scr_dyn_invoke.c +181 -43
- 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_fetch.c +45 -1
- package/dist/lib/runtime-sources/src/scr_file_handle.c +42 -0
- package/dist/lib/runtime-sources/src/scr_island.c +2166 -786
- package/dist/lib/runtime-sources/src/scr_island_manifest.h +19 -13
- package/dist/lib/runtime-sources/src/scr_json.c +584 -54
- package/dist/lib/runtime-sources/src/scr_json.test.ts +1 -0
- package/dist/lib/runtime-sources/src/scr_lib.c +1192 -43
- package/dist/lib/runtime-sources/src/scr_map.c +8 -0
- package/dist/lib/runtime-sources/src/scr_node_builtin.c +78 -0
- package/dist/lib/runtime-sources/src/scr_qs.c +10 -0
- package/dist/lib/runtime-sources/src/scr_regex.c +107 -5
- package/dist/lib/runtime-sources/src/scr_runtime.h +136 -9
- 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_text_decoder_labels.h +12 -12
- package/dist/lib/runtime-sources/src/scr_url.c +547 -64
- 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 +849 -264
- 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
|
|
|
@@ -763,6 +776,33 @@ ScrStr *scr_url_protocol(ScrUrl *u) {
|
|
|
763
776
|
return ub_take(&b);
|
|
764
777
|
}
|
|
765
778
|
|
|
779
|
+
/* Input conversion is the caller's responsibility. Only parser errors are
|
|
780
|
+
* suppressed: user toString errors must still escape the public factories. */
|
|
781
|
+
static ScrUrl *url_try_parse(ScrStr *input, ScrStr *base) {
|
|
782
|
+
ScrUrl *u = base ? scr_url_new_base(input, base) : scr_url_new(input);
|
|
783
|
+
if (!u) scr_exc_clear();
|
|
784
|
+
return u;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
bool scr_url_can_parse_base(ScrStr *input, ScrStr *base) {
|
|
788
|
+
ScrUrl *u = url_try_parse(input, base);
|
|
789
|
+
bool valid = u != NULL;
|
|
790
|
+
scr_url_release(u);
|
|
791
|
+
return valid;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
bool scr_url_can_parse(ScrStr *input) { return scr_url_can_parse_base(input, NULL); }
|
|
795
|
+
|
|
796
|
+
ScrDyn *scr_url_parse_base(ScrStr *input, ScrStr *base) {
|
|
797
|
+
ScrUrl *u = url_try_parse(input, base);
|
|
798
|
+
if (!u) return scr_dyn_new_null();
|
|
799
|
+
ScrDyn *value = scr_dyn_native_url(u);
|
|
800
|
+
scr_url_release(u);
|
|
801
|
+
return value;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
ScrDyn *scr_url_parse(ScrStr *input) { return scr_url_parse_base(input, NULL); }
|
|
805
|
+
|
|
766
806
|
ScrStr *scr_url_pathname(ScrUrl *u) { return scr_str_retain(u->path); }
|
|
767
807
|
|
|
768
808
|
/* WHATWG host getter: host[:port] — the port only when non-default (the
|
|
@@ -770,12 +810,15 @@ ScrStr *scr_url_pathname(ScrUrl *u) { return scr_str_retain(u->path); }
|
|
|
770
810
|
* normalized form findRoute-style authority compares want (lowercased
|
|
771
811
|
* host, no default :443/:80). */
|
|
772
812
|
ScrStr *scr_url_host(ScrUrl *u) {
|
|
773
|
-
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);
|
|
774
814
|
UrlBuf b;
|
|
775
815
|
ub_init(&b);
|
|
776
816
|
ub_append(&b, u->host->data, u->host->len);
|
|
777
|
-
|
|
778
|
-
|
|
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);
|
|
779
822
|
return ub_take(&b);
|
|
780
823
|
}
|
|
781
824
|
|
|
@@ -851,12 +894,289 @@ ScrStr *scr_url_href(ScrUrl *u) {
|
|
|
851
894
|
ub_append(&b, u->port->data, u->port->len);
|
|
852
895
|
}
|
|
853
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);
|
|
854
900
|
ub_append(&b, u->path->data, u->path->len);
|
|
855
901
|
ub_append(&b, u->query->data, u->query->len);
|
|
856
902
|
ub_append(&b, u->fragment->data, u->fragment->len);
|
|
857
903
|
return ub_take(&b);
|
|
858
904
|
}
|
|
859
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
|
+
|
|
860
1180
|
/* ── the file-URL bridge ─────────────────────────────────────────────── */
|
|
861
1181
|
|
|
862
1182
|
static int hex_val(char c) {
|
|
@@ -866,15 +1186,36 @@ static int hex_val(char c) {
|
|
|
866
1186
|
return -1;
|
|
867
1187
|
}
|
|
868
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
|
+
|
|
869
1213
|
/* fileURLToPath over a parsed URL: Node's checks, Node's messages. The
|
|
870
1214
|
* posix arm rejects hosts and keeps forward slashes; the win32 arm maps
|
|
871
1215
|
* hosts to UNC \\host prefixes, flips separators, and demands a drive
|
|
872
1216
|
* letter otherwise. The public wrappers below select by TARGET. */
|
|
873
1217
|
static ScrStr *scr_url_to_path_impl(ScrUrl *u, bool win32) {
|
|
874
|
-
if (!(u
|
|
875
|
-
scr_throw_error_msg(SCR_ERR_TYPE, "The URL must be of scheme file", 30);
|
|
876
|
-
return NULL;
|
|
877
|
-
}
|
|
1218
|
+
if (!url_file_scheme(u)) return NULL;
|
|
878
1219
|
const char *p = u->path->data;
|
|
879
1220
|
size_t len = u->path->len;
|
|
880
1221
|
if (win32) {
|
|
@@ -884,8 +1225,8 @@ static ScrStr *scr_url_to_path_impl(ScrUrl *u, bool win32) {
|
|
|
884
1225
|
char c1 = p[n + 1];
|
|
885
1226
|
int third = (n + 2 < len ? (unsigned char)p[n + 2] : 0) | 0x20;
|
|
886
1227
|
if ((c1 == '2' && third == 'f') || (c1 == '5' && third == 'c')) {
|
|
887
|
-
|
|
888
|
-
"File URL path must not include encoded \\ or / characters", 56);
|
|
1228
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE,
|
|
1229
|
+
"File URL path must not include encoded \\ or / characters", 56, "ERR_INVALID_FILE_URL_PATH");
|
|
889
1230
|
return NULL;
|
|
890
1231
|
}
|
|
891
1232
|
}
|
|
@@ -916,7 +1257,7 @@ static ScrStr *scr_url_to_path_impl(ScrUrl *u, bool win32) {
|
|
|
916
1257
|
char drive_sep = plen > 2 ? pp[2] : 0;
|
|
917
1258
|
if (letter < 'a' || letter > 'z' || drive_sep != ':') {
|
|
918
1259
|
free(out.data);
|
|
919
|
-
|
|
1260
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE, "File URL path must be absolute", 30, "ERR_INVALID_FILE_URL_PATH");
|
|
920
1261
|
return NULL;
|
|
921
1262
|
}
|
|
922
1263
|
/* pathname.slice(1): the leading backslash drops. */
|
|
@@ -924,23 +1265,7 @@ static ScrStr *scr_url_to_path_impl(ScrUrl *u, bool win32) {
|
|
|
924
1265
|
free(out.data);
|
|
925
1266
|
return s;
|
|
926
1267
|
}
|
|
927
|
-
if (u
|
|
928
|
-
/* Parse-time normalization already emptied "localhost". */
|
|
929
|
-
const char *plat =
|
|
930
|
-
#if defined(__APPLE__)
|
|
931
|
-
"darwin";
|
|
932
|
-
#elif defined(__linux__)
|
|
933
|
-
"linux";
|
|
934
|
-
#elif defined(_WIN32)
|
|
935
|
-
"win32";
|
|
936
|
-
#else
|
|
937
|
-
"posix";
|
|
938
|
-
#endif
|
|
939
|
-
char msg[96];
|
|
940
|
-
int mlen = snprintf(msg, sizeof msg, "File URL host must be \"localhost\" or empty on %s", plat);
|
|
941
|
-
scr_throw_error_msg(SCR_ERR_TYPE, msg, (size_t)mlen);
|
|
942
|
-
return NULL;
|
|
943
|
-
}
|
|
1268
|
+
if (!url_file_posix_host(u)) return NULL;
|
|
944
1269
|
for (size_t i = 0; i < len; i++) {
|
|
945
1270
|
if (p[i] == '%' && i + 2 < len) {
|
|
946
1271
|
int hi = hex_val(p[i + 1]);
|
|
@@ -948,8 +1273,8 @@ static ScrStr *scr_url_to_path_impl(ScrUrl *u, bool win32) {
|
|
|
948
1273
|
if (hi >= 0 && lo >= 0) {
|
|
949
1274
|
unsigned char decoded = (unsigned char)((hi << 4) | lo);
|
|
950
1275
|
if (decoded == '/') {
|
|
951
|
-
|
|
952
|
-
"File URL path must not include encoded / characters", 51);
|
|
1276
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE,
|
|
1277
|
+
"File URL path must not include encoded / characters", 51, "ERR_INVALID_FILE_URL_PATH");
|
|
953
1278
|
return NULL;
|
|
954
1279
|
}
|
|
955
1280
|
i += 2;
|
|
@@ -994,7 +1319,9 @@ static ScrUrl *scr_url_new_file(ScrStr *host, ScrStr *encoded_path) {
|
|
|
994
1319
|
u->query = scr_str_new("", 0);
|
|
995
1320
|
u->fragment = scr_str_new("", 0);
|
|
996
1321
|
u->has_authority = true;
|
|
1322
|
+
u->host_path_escape = false;
|
|
997
1323
|
u->sp_cache = NULL;
|
|
1324
|
+
u->sp_reload = NULL;
|
|
998
1325
|
return u;
|
|
999
1326
|
}
|
|
1000
1327
|
|
|
@@ -1017,7 +1344,7 @@ static void scr_url_throw_arg_value(const char *reason, ScrStr *value) {
|
|
|
1017
1344
|
ub_append(&msg, reason, strlen(reason));
|
|
1018
1345
|
ub_append(&msg, ". Received ", 11);
|
|
1019
1346
|
ub_push_inspected(&msg, value->data, value->len);
|
|
1020
|
-
|
|
1347
|
+
scr_throw_error_msg_code(SCR_ERR_TYPE, msg.data, msg.len, "ERR_INVALID_ARG_VALUE");
|
|
1021
1348
|
free(msg.data);
|
|
1022
1349
|
}
|
|
1023
1350
|
|
|
@@ -1206,10 +1533,21 @@ static ScrDyn *scr_native_url_invoke(void *ptr, ScrDyn *self, const char *method
|
|
|
1206
1533
|
return NULL;
|
|
1207
1534
|
}
|
|
1208
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
|
+
|
|
1209
1547
|
ScrDyn *scr_dyn_native_url(ScrUrl *value) {
|
|
1210
1548
|
static const ScrDynHandleOps ops = {
|
|
1211
1549
|
"URL", &scr_url_retain_v, &scr_url_release_v, &scr_native_url_invoke,
|
|
1212
|
-
&scr_native_url_get,
|
|
1550
|
+
&scr_native_url_get, &scr_native_url_set, NULL, NULL,
|
|
1213
1551
|
};
|
|
1214
1552
|
scr_dyn_handle_install(SCR_DYNH_URL, &ops);
|
|
1215
1553
|
return scr_dyn_new_handle(value, SCR_DYNH_URL);
|
|
@@ -1398,3 +1736,148 @@ ScrStr *scr_url_checked_to_path(const ScrDyn *value) {
|
|
|
1398
1736
|
scr_dyn_arg_type_fail("path", "of type string or an instance of URL", value);
|
|
1399
1737
|
return NULL;
|
|
1400
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
|
+
}
|