@sproutboat/runtime 0.34.4 → 0.34.5
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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/native-fetch-prelude.js +11 -0
- package/src/transport-embedded.js +32 -12
- package/test/native-d1.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# @sproutboat/runtime
|
|
2
2
|
|
|
3
|
+
## 0.34.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e62b600: The client address is folded to plain IPv4 once per distinct address instead of on every request: a request read `x-sb-remote-addr` and, for an IPv4-mapped IPv6 peer, lowercased, split and hex-parsed it each time. The last address and its result are kept; a different address takes the same path as before.
|
|
8
|
+
- 0b12b94: A strict D1 query hands its rows to JavaScript with fewer copies: the text of every cell goes into one arena instead of one `malloc` per cell, and a cell that is plain ASCII becomes its JS string in one copy (it used to go through a UTF-16 buffer, an 8-bit buffer and a third copy, three `malloc`s each). Non-ASCII text still takes the old path, so the strings are unchanged.
|
|
9
|
+
|
|
3
10
|
## 0.34.4
|
|
4
11
|
|
|
5
12
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -7959,8 +7959,19 @@ function __sbParseHex(s) {
|
|
|
7959
7959
|
// uWS hands back IPv4-mapped IPv6 for IPv4 clients on a dual-stack socket
|
|
7960
7960
|
// (`::ffff:1.2.3.4`, or fully expanded `0:0:0:0:0:ffff:0102:0304`). Fold those
|
|
7961
7961
|
// to the dotted IPv4 so CIDR matching and `clientIp` see a plain address.
|
|
7962
|
+
// The last address folded and its result: a client keeps the same address from one request to the
|
|
7963
|
+
// next, and folding an IPv6 text costs a lowercase, a split and eight hex parses.
|
|
7964
|
+
let __sbIpRaw = "";
|
|
7965
|
+
let __sbIpFolded = "";
|
|
7962
7966
|
function __sbNormalizeIp(ip) {
|
|
7963
7967
|
const s = String(ip || "");
|
|
7968
|
+
if (s === __sbIpRaw) return __sbIpFolded;
|
|
7969
|
+
const folded = __sbFoldIp(s);
|
|
7970
|
+
__sbIpRaw = s;
|
|
7971
|
+
__sbIpFolded = folded;
|
|
7972
|
+
return folded;
|
|
7973
|
+
}
|
|
7974
|
+
function __sbFoldIp(s) {
|
|
7964
7975
|
if (s.indexOf(":") === -1) return s;
|
|
7965
7976
|
const low = s.toLowerCase();
|
|
7966
7977
|
const dotted = low.indexOf("::ffff:");
|
|
@@ -2162,13 +2162,33 @@ static char* sb_sql_error(sqlite3* db, const char* message, int code, int skip)
|
|
|
2162
2162
|
// A strict D1 query can hand its rows back as cells instead of JSON text: the caller turns
|
|
2163
2163
|
// them into JS arrays, with no JSON written here and none parsed there. t is 0 NULL,
|
|
2164
2164
|
// 1 number, 2 TEXT (UTF-8 in p), 3 BLOB (bytes in p).
|
|
2165
|
-
|
|
2166
|
-
|
|
2165
|
+
// The text and blob bytes of every cell share one arena (a cell holds an offset into it), and a
|
|
2166
|
+
// TEXT cell says whether it is all ASCII: that one becomes a JS string with a single copy.
|
|
2167
|
+
typedef struct { unsigned char t; unsigned char ascii; double d; size_t off; int n; } sb_cell;
|
|
2168
|
+
typedef struct { sb_cell* c; size_t n; size_t cap; int ncol; int used; char* a; size_t alen; size_t acap; } sb_cells;
|
|
2167
2169
|
static void sb_cells_free(sb_cells* cs) {
|
|
2168
2170
|
if (!cs) return;
|
|
2169
|
-
for (size_t i = 0; i < cs->n; i++) free(cs->c[i].p);
|
|
2170
2171
|
free(cs->c);
|
|
2171
|
-
cs->
|
|
2172
|
+
free(cs->a);
|
|
2173
|
+
cs->c = 0; cs->a = 0; cs->n = cs->cap = cs->alen = cs->acap = 0;
|
|
2174
|
+
}
|
|
2175
|
+
// Copies n bytes into the arena and returns their offset, or (size_t)-1 when out of memory.
|
|
2176
|
+
static size_t sb_cells_bytes(sb_cells* cs, const unsigned char* src, size_t n, unsigned char* ascii) {
|
|
2177
|
+
if (cs->alen + n + 1 > cs->acap) {
|
|
2178
|
+
size_t cap = cs->acap ? cs->acap * 2 : 1024;
|
|
2179
|
+
while (cap < cs->alen + n + 1) cap *= 2;
|
|
2180
|
+
char* grown = (char*)realloc(cs->a, cap);
|
|
2181
|
+
if (!grown) return (size_t)-1;
|
|
2182
|
+
cs->a = grown; cs->acap = cap;
|
|
2183
|
+
}
|
|
2184
|
+
const size_t off = cs->alen;
|
|
2185
|
+
unsigned char high = 0;
|
|
2186
|
+
for (size_t i = 0; i < n; i++) high |= src[i];
|
|
2187
|
+
if (n) memcpy(cs->a + off, src, n);
|
|
2188
|
+
cs->a[off + n] = 0;
|
|
2189
|
+
cs->alen = off + n + 1;
|
|
2190
|
+
*ascii = high < 0x80;
|
|
2191
|
+
return off;
|
|
2172
2192
|
}
|
|
2173
2193
|
static sb_cell* sb_cells_add(sb_cells* cs) {
|
|
2174
2194
|
if (cs->n == cs->cap) {
|
|
@@ -2178,7 +2198,7 @@ static sb_cell* sb_cells_add(sb_cells* cs) {
|
|
|
2178
2198
|
cs->c = grown; cs->cap = cap;
|
|
2179
2199
|
}
|
|
2180
2200
|
sb_cell* cell = &cs->c[cs->n++];
|
|
2181
|
-
cell->t = 0; cell->d = 0; cell->
|
|
2201
|
+
cell->t = 0; cell->ascii = 0; cell->d = 0; cell->off = 0; cell->n = 0;
|
|
2182
2202
|
return cell;
|
|
2183
2203
|
}
|
|
2184
2204
|
static char* sb_sql_run_x(const char* path, const char* sql, const char* params, sb_cells* cells) {
|
|
@@ -2226,10 +2246,8 @@ static char* sb_sql_run_x(const char* path, const char* sql, const char* params,
|
|
|
2226
2246
|
int n = sqlite3_column_bytes(st, i);
|
|
2227
2247
|
cell->t = t == 4 ? 3 : 2;
|
|
2228
2248
|
cell->n = txt ? n : 0;
|
|
2229
|
-
cell->
|
|
2230
|
-
if (
|
|
2231
|
-
if (cell->n) memcpy(cell->p, txt, (size_t)cell->n);
|
|
2232
|
-
cell->p[cell->n] = 0;
|
|
2249
|
+
cell->off = sb_cells_bytes(cells, txt, (size_t)cell->n, &cell->ascii);
|
|
2250
|
+
if (cell->off == (size_t)-1) { cells->used = -1; break; }
|
|
2233
2251
|
}
|
|
2234
2252
|
if (cells->used < 0) break;
|
|
2235
2253
|
continue;
|
|
@@ -4261,12 +4279,14 @@ function __sbSqlRowsRaw(path, sql, paramsJson) {
|
|
|
4261
4279
|
const sb_cell* __cell = &__cells.c[__r * __ncol + __c];
|
|
4262
4280
|
jsval __v = porf_box(0.0, 7);
|
|
4263
4281
|
if (__cell->t == 1) __v = porf_box_num(__cell->d);
|
|
4264
|
-
else if (__cell->t == 2) {
|
|
4282
|
+
else if (__cell->t == 2 && __cell->ascii) {
|
|
4283
|
+
__v = porf_box((f64)porf_native_fetch_alloc_bytestring(__cells.a + __cell->off, (size_t)__cell->n), 195);
|
|
4284
|
+
} else if (__cell->t == 2) {
|
|
4265
4285
|
const size_t __n = (size_t)__cell->n;
|
|
4266
4286
|
uint16_t* __u = (uint16_t*)malloc(__n * 2 + 2);
|
|
4267
4287
|
if (__u) {
|
|
4268
4288
|
int __wide = 0;
|
|
4269
|
-
const size_t __k = sb_text_units((const unsigned char*)__cell->
|
|
4289
|
+
const size_t __k = sb_text_units((const unsigned char*)(__cells.a + __cell->off), __n, __u, &__wide);
|
|
4270
4290
|
if (__wide) {
|
|
4271
4291
|
const u32 __str = porf_native_fetch_alloc((u32)(4 + __k * 2), 67);
|
|
4272
4292
|
*(u32*)(MEM + __str) = (u32)__k;
|
|
@@ -4284,7 +4304,7 @@ function __sbSqlRowsRaw(path, sql, paramsJson) {
|
|
|
4284
4304
|
}
|
|
4285
4305
|
} else if (__cell->t == 3) {
|
|
4286
4306
|
const u32 __bytes = porf_arr_new((i32)__cell->n, (i32)__cell->n);
|
|
4287
|
-
for (int __i = 0; __i < __cell->n; __i++) porf_arr_set(__bytes, (u32)__i, porf_box_num((f64)(unsigned char)__cell->
|
|
4307
|
+
for (int __i = 0; __i < __cell->n; __i++) porf_arr_set(__bytes, (u32)__i, porf_box_num((f64)(unsigned char)__cells.a[__cell->off + __i]));
|
|
4288
4308
|
__v = porf_box((f64)__bytes, 72);
|
|
4289
4309
|
}
|
|
4290
4310
|
porf_arr_set(__row, (u32)__c, __v);
|
package/test/native-d1.ts
CHANGED
|
@@ -67,12 +67,12 @@ int main(void) {
|
|
|
67
67
|
else if (x->t == 1) printf("%.17g", x->d);
|
|
68
68
|
else if (x->t == 2) {
|
|
69
69
|
uint16_t* u = (uint16_t*)malloc((size_t)x->n * 2 + 2); int wide = 0;
|
|
70
|
-
size_t k = sb_text_units((const unsigned char*)x->
|
|
70
|
+
size_t k = sb_text_units((const unsigned char*)(cs.a + x->off), (size_t)x->n, u, &wide);
|
|
71
71
|
printf("\\"");
|
|
72
72
|
for (size_t i = 0; i < k; i++) printf("\\\\u%04x", u[i]);
|
|
73
73
|
printf("\\"");
|
|
74
74
|
free(u);
|
|
75
|
-
} else { printf("{\\"$blob\\":\\""); for (int i = 0; i < x->n; i++) printf("%02x", (unsigned char)x->
|
|
75
|
+
} else { printf("{\\"$blob\\":\\""); for (int i = 0; i < x->n; i++) printf("%02x", (unsigned char)cs.a[x->off + i]); printf("\\"}"); }
|
|
76
76
|
}
|
|
77
77
|
printf("]");
|
|
78
78
|
}
|