@php-wasm/universal 3.0.18 → 3.0.20
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/index.cjs +6 -6
- package/index.cjs.map +1 -1
- package/index.js +306 -155
- package/index.js.map +1 -1
- package/lib/php-request-handler.d.ts +89 -0
- package/lib/universal-php.d.ts +3 -1
- package/package.json +7 -7
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
1
|
+
var B = (t) => {
|
|
2
2
|
throw TypeError(t);
|
|
3
3
|
};
|
|
4
|
-
var O = (t, e, r) => e.has(t) ||
|
|
5
|
-
var u = (t, e, r) => (O(t, e, "read from private field"), r ? r.call(t) : e.get(t)),
|
|
4
|
+
var O = (t, e, r) => e.has(t) || B("Cannot " + r);
|
|
5
|
+
var u = (t, e, r) => (O(t, e, "read from private field"), r ? r.call(t) : e.get(t)), y = (t, e, r) => e.has(t) ? B("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, r), w = (t, e, r, s) => (O(t, e, "write to private field"), s ? s.call(t, r) : e.set(t, r), r), f = (t, e, r) => (O(t, e, "access private method"), r);
|
|
6
6
|
import "@php-wasm/node-polyfills";
|
|
7
7
|
import { logger } from "@php-wasm/logger";
|
|
8
8
|
import { dirname, joinPaths, Semaphore, createSpawnHandler, basename, normalizePath, AcquireTimeoutError } from "@php-wasm/util";
|
|
@@ -363,12 +363,12 @@ FSHelpers.copyRecursive = rethrowFileSystemError(
|
|
|
363
363
|
'Could not copy files from "{path}"'
|
|
364
364
|
)(FSHelpers.copyRecursive);
|
|
365
365
|
const _private = /* @__PURE__ */ new WeakMap();
|
|
366
|
-
var
|
|
366
|
+
var S;
|
|
367
367
|
class PHPWorker {
|
|
368
368
|
/** @inheritDoc */
|
|
369
369
|
constructor(e, r) {
|
|
370
|
-
|
|
371
|
-
this.absoluteUrl = "", this.documentRoot = "", this.chroot = null, w(this,
|
|
370
|
+
y(this, S);
|
|
371
|
+
this.absoluteUrl = "", this.documentRoot = "", this.chroot = null, w(this, S, /* @__PURE__ */ new Map()), this.onMessageListeners = [], _private.set(this, {
|
|
372
372
|
monitor: r
|
|
373
373
|
}), e && this.__internal_setRequestHandler(e);
|
|
374
374
|
}
|
|
@@ -524,7 +524,7 @@ class PHPWorker {
|
|
|
524
524
|
}
|
|
525
525
|
/** @inheritDoc @php-wasm/universal!/PHP.addEventListener */
|
|
526
526
|
addEventListener(e, r) {
|
|
527
|
-
u(this,
|
|
527
|
+
u(this, S).has(e) || u(this, S).set(e, /* @__PURE__ */ new Set()), u(this, S).get(e).add(r);
|
|
528
528
|
}
|
|
529
529
|
/**
|
|
530
530
|
* Removes an event listener for a PHP event.
|
|
@@ -533,10 +533,10 @@ class PHPWorker {
|
|
|
533
533
|
*/
|
|
534
534
|
removeEventListener(e, r) {
|
|
535
535
|
var s;
|
|
536
|
-
(s = u(this,
|
|
536
|
+
(s = u(this, S).get(e)) == null || s.delete(r);
|
|
537
537
|
}
|
|
538
538
|
dispatchEvent(e) {
|
|
539
|
-
const r = u(this,
|
|
539
|
+
const r = u(this, S).get(e.type);
|
|
540
540
|
if (r)
|
|
541
541
|
for (const s of r)
|
|
542
542
|
s(e);
|
|
@@ -558,7 +558,7 @@ class PHPWorker {
|
|
|
558
558
|
await ((e = _private.get(this).requestHandler) == null ? void 0 : e[Symbol.asyncDispose]());
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
|
-
|
|
561
|
+
S = new WeakMap();
|
|
562
562
|
function isExitCode(t) {
|
|
563
563
|
return t instanceof Error ? (t == null ? void 0 : t.name) === "ExitStatus" && "status" in t : !1;
|
|
564
564
|
}
|
|
@@ -950,7 +950,7 @@ class PHPExecutionFailureError extends Error {
|
|
|
950
950
|
}
|
|
951
951
|
}
|
|
952
952
|
const PHP_INI_PATH = "/internal/shared/php.ini", AUTO_PREPEND_SCRIPT = "/internal/shared/auto_prepend_file.php", OPCACHE_FILE_FOLDER = "/internal/shared/opcache";
|
|
953
|
-
var
|
|
953
|
+
var M, H, T, v, F, k, _, h, z, $, V, G, J, Y, Q, K, U, X, j, D;
|
|
954
954
|
class PHP {
|
|
955
955
|
/**
|
|
956
956
|
* Initializes a PHP runtime.
|
|
@@ -960,17 +960,17 @@ class PHP {
|
|
|
960
960
|
* @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
|
|
961
961
|
*/
|
|
962
962
|
constructor(t) {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
963
|
+
y(this, h);
|
|
964
|
+
y(this, M);
|
|
965
|
+
y(this, H, !1);
|
|
966
|
+
y(this, T, null);
|
|
967
|
+
y(this, v, /* @__PURE__ */ new Map([
|
|
968
968
|
// Listen to all events
|
|
969
969
|
["*", /* @__PURE__ */ new Set()]
|
|
970
970
|
]));
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
971
|
+
y(this, F, []);
|
|
972
|
+
y(this, k, {});
|
|
973
|
+
y(this, _, {
|
|
974
974
|
enabled: !1,
|
|
975
975
|
recreateRuntime: () => 0,
|
|
976
976
|
needsRotating: !1,
|
|
@@ -987,7 +987,7 @@ class PHP {
|
|
|
987
987
|
* @param listener - The listener function to be called when the event is triggered.
|
|
988
988
|
*/
|
|
989
989
|
addEventListener(t, e) {
|
|
990
|
-
u(this,
|
|
990
|
+
u(this, v).has(t) || u(this, v).set(t, /* @__PURE__ */ new Set()), u(this, v).get(t).add(e);
|
|
991
991
|
}
|
|
992
992
|
/**
|
|
993
993
|
* Removes an event listener for a PHP event.
|
|
@@ -996,12 +996,12 @@ class PHP {
|
|
|
996
996
|
*/
|
|
997
997
|
removeEventListener(t, e) {
|
|
998
998
|
var r;
|
|
999
|
-
(r = u(this,
|
|
999
|
+
(r = u(this, v).get(t)) == null || r.delete(e);
|
|
1000
1000
|
}
|
|
1001
1001
|
dispatchEvent(t) {
|
|
1002
1002
|
const e = [
|
|
1003
|
-
...u(this,
|
|
1004
|
-
...u(this,
|
|
1003
|
+
...u(this, v).get(t.type) || [],
|
|
1004
|
+
...u(this, v).get("*") || []
|
|
1005
1005
|
];
|
|
1006
1006
|
if (e)
|
|
1007
1007
|
for (const r of e)
|
|
@@ -1163,7 +1163,7 @@ class PHP {
|
|
|
1163
1163
|
throw new Error(
|
|
1164
1164
|
"Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
|
|
1165
1165
|
);
|
|
1166
|
-
w(this,
|
|
1166
|
+
w(this, M, t);
|
|
1167
1167
|
}
|
|
1168
1168
|
/**
|
|
1169
1169
|
* Changes the current working directory in the PHP filesystem.
|
|
@@ -1387,7 +1387,7 @@ class PHP {
|
|
|
1387
1387
|
async runStream(t) {
|
|
1388
1388
|
const e = await this.semaphore.acquire();
|
|
1389
1389
|
let r;
|
|
1390
|
-
const s =
|
|
1390
|
+
const s = f(this, h, D).call(this, async () => {
|
|
1391
1391
|
if (u(this, H) || (await this[__private__dont__use].ccall(
|
|
1392
1392
|
"php_wasm_init",
|
|
1393
1393
|
null,
|
|
@@ -1400,22 +1400,22 @@ class PHP {
|
|
|
1400
1400
|
throw new Error(
|
|
1401
1401
|
`The script path "${t.scriptPath}" does not exist.`
|
|
1402
1402
|
);
|
|
1403
|
-
|
|
1404
|
-
const i = normalizeHeaders(t.headers || {}), o = i.host || "example.com:443", a =
|
|
1405
|
-
if (
|
|
1406
|
-
this.writeFile("/internal/eval.php", t.code),
|
|
1403
|
+
f(this, h, $).call(this, t.relativeUri || ""), f(this, h, Y).call(this, t.method || "GET");
|
|
1404
|
+
const i = normalizeHeaders(t.headers || {}), o = i.host || "example.com:443", a = f(this, h, J).call(this, o, t.protocol || "http");
|
|
1405
|
+
if (f(this, h, V).call(this, o), f(this, h, G).call(this, a), f(this, h, Q).call(this, i), t.body && (r = f(this, h, K).call(this, t.body)), typeof t.code == "string")
|
|
1406
|
+
this.writeFile("/internal/eval.php", t.code), f(this, h, U).call(this, "/internal/eval.php");
|
|
1407
1407
|
else if (typeof t.scriptPath == "string")
|
|
1408
|
-
|
|
1408
|
+
f(this, h, U).call(this, t.scriptPath || "");
|
|
1409
1409
|
else
|
|
1410
1410
|
throw new TypeError(
|
|
1411
1411
|
"The request object must have either a `code` or a `scriptPath` property."
|
|
1412
1412
|
);
|
|
1413
|
-
const c =
|
|
1413
|
+
const c = f(this, h, z).call(this, t.$_SERVER, i, a);
|
|
1414
1414
|
for (const d in c)
|
|
1415
|
-
|
|
1415
|
+
f(this, h, X).call(this, d, c[d]);
|
|
1416
1416
|
const l = t.env || {};
|
|
1417
1417
|
for (const d in l)
|
|
1418
|
-
|
|
1418
|
+
f(this, h, j).call(this, d, l[d]);
|
|
1419
1419
|
return await this[__private__dont__use].ccall(
|
|
1420
1420
|
"wasm_sapi_handle_request",
|
|
1421
1421
|
NUMBER,
|
|
@@ -1661,28 +1661,35 @@ class PHP {
|
|
|
1661
1661
|
* @param runtime
|
|
1662
1662
|
*/
|
|
1663
1663
|
async hotSwapPHPRuntime(t) {
|
|
1664
|
-
const e = this[__private__dont__use].FS, r = this.listFiles("/").map((
|
|
1664
|
+
const e = this[__private__dont__use].FS, r = this.listFiles("/").map((c) => `/${c}`), s = this[__private__dont__use].spawnProcess, n = e.cwd();
|
|
1665
1665
|
e.chdir("/");
|
|
1666
|
-
const i =
|
|
1667
|
-
|
|
1668
|
-
|
|
1666
|
+
const i = Object.entries(u(this, k)).map(
|
|
1667
|
+
([c, l]) => ({
|
|
1668
|
+
mountHandler: l.mountHandler,
|
|
1669
|
+
vfsPath: c
|
|
1670
|
+
})
|
|
1671
|
+
), o = Object.values(
|
|
1672
|
+
u(this, k)
|
|
1673
|
+
).reverse();
|
|
1674
|
+
for (const c of o)
|
|
1675
|
+
await c.unmount();
|
|
1669
1676
|
try {
|
|
1670
1677
|
this.exit();
|
|
1671
1678
|
} catch {
|
|
1672
1679
|
}
|
|
1673
|
-
this.initializeRuntime(t), s && (this[__private__dont__use].spawnProcess = s), u(this,
|
|
1674
|
-
const
|
|
1675
|
-
for (const
|
|
1676
|
-
|
|
1677
|
-
for (const { mountHandler:
|
|
1678
|
-
this.mkdir(
|
|
1680
|
+
this.initializeRuntime(t), s && (this[__private__dont__use].spawnProcess = s), u(this, M) && this.setSapiName(u(this, M));
|
|
1681
|
+
const a = this[__private__dont__use].FS;
|
|
1682
|
+
for (const c of r)
|
|
1683
|
+
c && c !== "/request" && copyMEMFSNodes(e, a, c);
|
|
1684
|
+
for (const { mountHandler: c, vfsPath: l } of i)
|
|
1685
|
+
this.mkdir(l), await this.mount(l, c);
|
|
1679
1686
|
try {
|
|
1680
|
-
|
|
1681
|
-
} catch (
|
|
1687
|
+
a.chdir(n);
|
|
1688
|
+
} catch (c) {
|
|
1682
1689
|
throw new Error(
|
|
1683
1690
|
`Failed to restore CWD to ${n} after PHP runtime rotation.`,
|
|
1684
1691
|
{
|
|
1685
|
-
cause:
|
|
1692
|
+
cause: c
|
|
1686
1693
|
}
|
|
1687
1694
|
);
|
|
1688
1695
|
}
|
|
@@ -1702,10 +1709,10 @@ class PHP {
|
|
|
1702
1709
|
), s = {
|
|
1703
1710
|
mountHandler: e,
|
|
1704
1711
|
unmount: async () => {
|
|
1705
|
-
await r(), delete u(this,
|
|
1712
|
+
await r(), delete u(this, k)[t];
|
|
1706
1713
|
}
|
|
1707
1714
|
};
|
|
1708
|
-
return u(this,
|
|
1715
|
+
return u(this, k)[t] = s, () => {
|
|
1709
1716
|
s.unmount();
|
|
1710
1717
|
};
|
|
1711
1718
|
}
|
|
@@ -1727,10 +1734,10 @@ class PHP {
|
|
|
1727
1734
|
return this.subProcess(t, e);
|
|
1728
1735
|
u(this, H) && (u(this, _).needsRotating = !0);
|
|
1729
1736
|
const r = await this.semaphore.acquire();
|
|
1730
|
-
return await
|
|
1737
|
+
return await f(this, h, D).call(this, () => {
|
|
1731
1738
|
const s = e.env || {};
|
|
1732
1739
|
for (const [n, i] of Object.entries(s))
|
|
1733
|
-
|
|
1740
|
+
f(this, h, j).call(this, n, i);
|
|
1734
1741
|
t = [t[0], "-c", PHP_INI_PATH, ...t.slice(1)];
|
|
1735
1742
|
for (const n of t)
|
|
1736
1743
|
this[__private__dont__use].ccall(
|
|
@@ -1821,7 +1828,7 @@ class PHP {
|
|
|
1821
1828
|
this.exit(0);
|
|
1822
1829
|
}
|
|
1823
1830
|
}
|
|
1824
|
-
|
|
1831
|
+
M = new WeakMap(), H = new WeakMap(), T = new WeakMap(), v = new WeakMap(), F = new WeakMap(), k = new WeakMap(), _ = new WeakMap(), h = new WeakSet(), /**
|
|
1825
1832
|
* Prepares the $_SERVER entries for the PHP runtime.
|
|
1826
1833
|
*
|
|
1827
1834
|
* @param defaults Default entries to include in $_SERVER.
|
|
@@ -1830,7 +1837,7 @@ C = new WeakMap(), H = new WeakMap(), T = new WeakMap(), E = new WeakMap(), F =
|
|
|
1830
1837
|
* was provided.
|
|
1831
1838
|
* @returns Computed $_SERVER entries.
|
|
1832
1839
|
*/
|
|
1833
|
-
|
|
1840
|
+
z = function(t, e, r) {
|
|
1834
1841
|
const s = {
|
|
1835
1842
|
...t || {}
|
|
1836
1843
|
};
|
|
@@ -1882,7 +1889,7 @@ B = function(t, e, r) {
|
|
|
1882
1889
|
[STRING],
|
|
1883
1890
|
[t]
|
|
1884
1891
|
);
|
|
1885
|
-
},
|
|
1892
|
+
}, Q = function(t) {
|
|
1886
1893
|
t.cookie && this[__private__dont__use].ccall(
|
|
1887
1894
|
"wasm_set_cookies",
|
|
1888
1895
|
null,
|
|
@@ -1899,7 +1906,7 @@ B = function(t, e, r) {
|
|
|
1899
1906
|
[NUMBER],
|
|
1900
1907
|
[parseInt(t["content-length"], 10)]
|
|
1901
1908
|
);
|
|
1902
|
-
},
|
|
1909
|
+
}, K = function(t) {
|
|
1903
1910
|
let e, r;
|
|
1904
1911
|
typeof t == "string" ? (logger.warn(
|
|
1905
1912
|
"Passing a string as the request body is deprecated. Please use a Uint8Array instead. See https://github.com/WordPress/wordpress-playground/issues/997 for more details"
|
|
@@ -1929,14 +1936,14 @@ B = function(t, e, r) {
|
|
|
1929
1936
|
[STRING],
|
|
1930
1937
|
[t]
|
|
1931
1938
|
);
|
|
1932
|
-
},
|
|
1939
|
+
}, X = function(t, e) {
|
|
1933
1940
|
this[__private__dont__use].ccall(
|
|
1934
1941
|
"wasm_add_SERVER_entry",
|
|
1935
1942
|
null,
|
|
1936
1943
|
[STRING, STRING],
|
|
1937
1944
|
[t, e]
|
|
1938
1945
|
);
|
|
1939
|
-
},
|
|
1946
|
+
}, j = function(t, e) {
|
|
1940
1947
|
this[__private__dont__use].ccall(
|
|
1941
1948
|
"wasm_add_ENV_entry",
|
|
1942
1949
|
null,
|
|
@@ -1967,27 +1974,27 @@ B = function(t, e, r) {
|
|
|
1967
1974
|
return await Promise.race([
|
|
1968
1975
|
t(),
|
|
1969
1976
|
new Promise((g, b) => {
|
|
1970
|
-
var
|
|
1977
|
+
var q;
|
|
1971
1978
|
c = (W) => {
|
|
1972
1979
|
isExitCode(W.error) || b(W.error);
|
|
1973
|
-
}, (
|
|
1980
|
+
}, (q = u(this, T)) == null || q.addEventListener(
|
|
1974
1981
|
"error",
|
|
1975
1982
|
c,
|
|
1976
1983
|
{ once: !0 }
|
|
1977
1984
|
);
|
|
1978
1985
|
})
|
|
1979
1986
|
]);
|
|
1980
|
-
} catch (
|
|
1981
|
-
if (isExitCode(
|
|
1982
|
-
return
|
|
1983
|
-
i.controller.error(
|
|
1987
|
+
} catch (m) {
|
|
1988
|
+
if (isExitCode(m))
|
|
1989
|
+
return m.status;
|
|
1990
|
+
i.controller.error(m), o.controller.error(m), r.controller.error(m), a = !0;
|
|
1984
1991
|
for (const g in this)
|
|
1985
1992
|
typeof this[g] == "function" && (this[g] = () => {
|
|
1986
1993
|
throw new Error(
|
|
1987
1994
|
"PHP runtime has crashed – see the earlier error for details."
|
|
1988
1995
|
);
|
|
1989
1996
|
});
|
|
1990
|
-
throw this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify(),
|
|
1997
|
+
throw this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify(), m;
|
|
1991
1998
|
} finally {
|
|
1992
1999
|
a || (i.controller.close(), o.controller.close(), n(), a = !0), (p = u(this, T)) == null || p.removeEventListener(
|
|
1993
2000
|
"error",
|
|
@@ -2004,11 +2011,11 @@ B = function(t, e, r) {
|
|
|
2004
2011
|
source: "php-wasm"
|
|
2005
2012
|
}), p),
|
|
2006
2013
|
(p) => {
|
|
2007
|
-
const
|
|
2014
|
+
const m = p.source ?? "php-wasm";
|
|
2008
2015
|
throw this.dispatchEvent({
|
|
2009
2016
|
type: "request.error",
|
|
2010
2017
|
error: p,
|
|
2011
|
-
source:
|
|
2018
|
+
source: m
|
|
2012
2019
|
}), p;
|
|
2013
2020
|
}
|
|
2014
2021
|
);
|
|
@@ -2473,7 +2480,7 @@ const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "app
|
|
|
2473
2480
|
xspf,
|
|
2474
2481
|
zip
|
|
2475
2482
|
};
|
|
2476
|
-
var
|
|
2483
|
+
var P, I, L, C, A, E, N, R, x, Z, ee, te, re;
|
|
2477
2484
|
class PHPRequestHandler {
|
|
2478
2485
|
/**
|
|
2479
2486
|
* The request handler needs to decide whether to serve a static asset or
|
|
@@ -2487,15 +2494,15 @@ class PHPRequestHandler {
|
|
|
2487
2494
|
* @param config - Request Handler configuration.
|
|
2488
2495
|
*/
|
|
2489
2496
|
constructor(e) {
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2497
|
+
y(this, x);
|
|
2498
|
+
y(this, P);
|
|
2499
|
+
y(this, I);
|
|
2500
|
+
y(this, L);
|
|
2501
|
+
y(this, C);
|
|
2502
|
+
y(this, A);
|
|
2503
|
+
y(this, E);
|
|
2504
|
+
y(this, N);
|
|
2505
|
+
y(this, R);
|
|
2499
2506
|
const {
|
|
2500
2507
|
documentRoot: r = "/www/",
|
|
2501
2508
|
absoluteUrl: s = typeof location == "object" ? location.href : DEFAULT_BASE_URL,
|
|
@@ -2511,17 +2518,17 @@ class PHPRequestHandler {
|
|
|
2511
2518
|
return l.isDir(r) || l.mkdir(r), l.chdir(r), l.requestHandler = this, l;
|
|
2512
2519
|
},
|
|
2513
2520
|
maxPhpInstances: e.maxPhpInstances
|
|
2514
|
-
}), w(this,
|
|
2521
|
+
}), w(this, R, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), w(this, P, r);
|
|
2515
2522
|
const o = new URL(s);
|
|
2516
|
-
w(this, L, o.hostname), w(this,
|
|
2517
|
-
const a = u(this,
|
|
2523
|
+
w(this, L, o.hostname), w(this, C, o.port ? Number(o.port) : o.protocol === "https:" ? 443 : 80), w(this, I, (o.protocol || "").replace(":", ""));
|
|
2524
|
+
const a = u(this, C) !== 443 && u(this, C) !== 80;
|
|
2518
2525
|
w(this, A, [
|
|
2519
2526
|
u(this, L),
|
|
2520
|
-
a ? `:${u(this,
|
|
2521
|
-
].join("")), w(this,
|
|
2527
|
+
a ? `:${u(this, C)}` : ""
|
|
2528
|
+
].join("")), w(this, E, o.pathname.replace(/\/+$/, "")), w(this, N, [
|
|
2522
2529
|
`${u(this, I)}://`,
|
|
2523
2530
|
u(this, A),
|
|
2524
|
-
u(this,
|
|
2531
|
+
u(this, E)
|
|
2525
2532
|
].join("")), this.rewriteRules = n, this.getFileNotFoundAction = i;
|
|
2526
2533
|
}
|
|
2527
2534
|
async getPrimaryPhp() {
|
|
@@ -2546,7 +2553,7 @@ class PHPRequestHandler {
|
|
|
2546
2553
|
*/
|
|
2547
2554
|
internalUrlToPath(e) {
|
|
2548
2555
|
const r = new URL(e, "https://playground.internal");
|
|
2549
|
-
return r.pathname.startsWith(u(this,
|
|
2556
|
+
return r.pathname.startsWith(u(this, E)) && (r.pathname = r.pathname.slice(u(this, E).length)), toRelativeUrl(r);
|
|
2550
2557
|
}
|
|
2551
2558
|
/**
|
|
2552
2559
|
* The absolute URL of this PHPRequestHandler instance.
|
|
@@ -2559,7 +2566,7 @@ class PHPRequestHandler {
|
|
|
2559
2566
|
* for the files to serve. Default: `/var/www`.
|
|
2560
2567
|
*/
|
|
2561
2568
|
get documentRoot() {
|
|
2562
|
-
return u(this,
|
|
2569
|
+
return u(this, P);
|
|
2563
2570
|
}
|
|
2564
2571
|
/**
|
|
2565
2572
|
* Serves the request – either by serving a static file, or by
|
|
@@ -2614,38 +2621,61 @@ class PHPRequestHandler {
|
|
|
2614
2621
|
// Remove the hash part of the URL as it's not meant for the server.
|
|
2615
2622
|
e.url.split("#")[0],
|
|
2616
2623
|
r ? void 0 : DEFAULT_BASE_URL
|
|
2617
|
-
), n =
|
|
2624
|
+
), n = f(this, x, Z).call(this, s), i = await this.getPrimaryPhp();
|
|
2625
|
+
let o = joinPaths(
|
|
2626
|
+
u(this, P),
|
|
2627
|
+
/**
|
|
2628
|
+
* Turn a URL such as `https://playground/scope:my-site/wp-admin/index.php`
|
|
2629
|
+
* into a site-relative path, such as `/wp-admin/index.php`.
|
|
2630
|
+
*/
|
|
2618
2631
|
removePathPrefix(
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2632
|
+
/**
|
|
2633
|
+
* URL.pathname returns a URL-encoded path. We need to decode it
|
|
2634
|
+
* before using it as a filesystem path.
|
|
2635
|
+
*/
|
|
2636
|
+
decodeURIComponent(n.pathname),
|
|
2637
|
+
u(this, E)
|
|
2638
|
+
)
|
|
2639
|
+
);
|
|
2625
2640
|
if (i.isDir(o)) {
|
|
2626
2641
|
if (!o.endsWith("/"))
|
|
2627
2642
|
return new PHPResponse(
|
|
2628
2643
|
301,
|
|
2629
|
-
{ Location: [`${
|
|
2644
|
+
{ Location: [`${n.pathname}/`] },
|
|
2630
2645
|
new Uint8Array(0)
|
|
2631
2646
|
);
|
|
2632
2647
|
for (const a of ["index.php", "index.html"]) {
|
|
2633
2648
|
const c = joinPaths(o, a);
|
|
2634
2649
|
if (i.isFile(c)) {
|
|
2635
|
-
o = c
|
|
2650
|
+
o = c, n.pathname = joinPaths(
|
|
2651
|
+
n.pathname,
|
|
2652
|
+
a
|
|
2653
|
+
);
|
|
2654
|
+
break;
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
if (!i.isFile(o)) {
|
|
2659
|
+
let a = n.pathname;
|
|
2660
|
+
for (; a.startsWith("/") && a !== dirname(a); ) {
|
|
2661
|
+
a = dirname(a);
|
|
2662
|
+
const c = joinPaths(u(this, P), a);
|
|
2663
|
+
if (i.isFile(c) && // Only run partial path resolution for PHP files.
|
|
2664
|
+
c.endsWith(".php")) {
|
|
2665
|
+
o = joinPaths(u(this, P), a);
|
|
2636
2666
|
break;
|
|
2637
2667
|
}
|
|
2638
2668
|
}
|
|
2639
2669
|
}
|
|
2640
2670
|
if (!i.isFile(o)) {
|
|
2641
2671
|
const a = this.getFileNotFoundAction(
|
|
2642
|
-
n
|
|
2672
|
+
n.pathname
|
|
2643
2673
|
);
|
|
2644
2674
|
switch (a.type) {
|
|
2645
2675
|
case "response":
|
|
2646
2676
|
return a.response;
|
|
2647
2677
|
case "internal-redirect":
|
|
2648
|
-
o = joinPaths(u(this,
|
|
2678
|
+
o = joinPaths(u(this, P), a.uri);
|
|
2649
2679
|
break;
|
|
2650
2680
|
case "404":
|
|
2651
2681
|
return PHPResponse.forHttpCode(404);
|
|
@@ -2657,34 +2687,153 @@ class PHPRequestHandler {
|
|
|
2657
2687
|
}
|
|
2658
2688
|
if (i.isFile(o))
|
|
2659
2689
|
if (o.endsWith(".php")) {
|
|
2660
|
-
const a =
|
|
2661
|
-
|
|
2662
|
-
// Pass along URL with the #fragment filtered out
|
|
2663
|
-
url: s.toString()
|
|
2664
|
-
}, c = await y(this, R, ee).call(this, a, o);
|
|
2665
|
-
return c.ok() && c.exitCode !== 0 ? new PHPResponse(
|
|
2690
|
+
const a = await f(this, x, te).call(this, e, s, n, o);
|
|
2691
|
+
return a.ok() && a.exitCode !== 0 ? new PHPResponse(
|
|
2666
2692
|
500,
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
) :
|
|
2693
|
+
a.headers,
|
|
2694
|
+
a.bytes,
|
|
2695
|
+
a.errors,
|
|
2696
|
+
a.exitCode
|
|
2697
|
+
) : a;
|
|
2672
2698
|
} else
|
|
2673
|
-
return
|
|
2699
|
+
return f(this, x, ee).call(this, i, o);
|
|
2674
2700
|
else
|
|
2675
2701
|
return PHPResponse.forHttpCode(404);
|
|
2676
2702
|
}
|
|
2703
|
+
/**
|
|
2704
|
+
* Computes the essential $_SERVER entries for a request.
|
|
2705
|
+
*
|
|
2706
|
+
* php_wasm.c sets some defaults, assuming it runs as a CLI script.
|
|
2707
|
+
* This function overrides them with the values correct in the request
|
|
2708
|
+
* context.
|
|
2709
|
+
*
|
|
2710
|
+
* @TODO: Consolidate the $_SERVER setting logic into a single place instead
|
|
2711
|
+
* of splitting it between the C SAPI and the TypeScript code. The PHP
|
|
2712
|
+
* class has a `.cli()` method that could take care of the CLI-specific
|
|
2713
|
+
* $_SERVER values.
|
|
2714
|
+
*
|
|
2715
|
+
* Path and URL-related $_SERVER entries are theoretically documented
|
|
2716
|
+
* at https://www.php.net/manual/en/reserved.variables.server.php,
|
|
2717
|
+
* but that page is not very helpful in practice. Here are tables derived
|
|
2718
|
+
* by interacting with PHP servers:
|
|
2719
|
+
*
|
|
2720
|
+
* ## PHP Dev Server
|
|
2721
|
+
*
|
|
2722
|
+
* Setup:
|
|
2723
|
+
* – `/home/adam/subdir/script.php` file contains `<?php phpinfo(); ?>`
|
|
2724
|
+
* – `php -S 127.0.0.1:8041` running in `/home/adam` directory
|
|
2725
|
+
* – A request is sent to `http://127.0.0.1:8041/subdir/script.php/b.php/c.php`
|
|
2726
|
+
*
|
|
2727
|
+
* Results:
|
|
2728
|
+
*
|
|
2729
|
+
* $_SERVER['REQUEST_URI'] | `/subdir/script.php/b.php/c.php`
|
|
2730
|
+
* $_SERVER['SCRIPT_NAME'] | `/subdir/script.php`
|
|
2731
|
+
* $_SERVER['SCRIPT_FILENAME']| `/home/adam/subdir/script.php`
|
|
2732
|
+
* $_SERVER['PATH_INFO'] | `/b.php/c.php`
|
|
2733
|
+
* $_SERVER['PHP_SELF'] | `/subdir/script.php/b.php/c.php`
|
|
2734
|
+
*
|
|
2735
|
+
* ## Apache – rewriting rules
|
|
2736
|
+
*
|
|
2737
|
+
* Setup:
|
|
2738
|
+
* – `/var/www/html/subdir/script.php` file contains `<?php phpinfo(); ?>`
|
|
2739
|
+
* – Apache is listening on port 8041
|
|
2740
|
+
* – The document root is `/var/www/html`
|
|
2741
|
+
* – A request is sent to `http://127.0.0.1:8041/api/v1/user/123`
|
|
2742
|
+
*
|
|
2743
|
+
* .htaccess file:
|
|
2744
|
+
*
|
|
2745
|
+
* ```apache
|
|
2746
|
+
* RewriteEngine On
|
|
2747
|
+
* RewriteRule ^api/v1/user/([0-9]+)$ /subdir/script.php?endpoint=user&id=$1 [L,QSA]
|
|
2748
|
+
* ```
|
|
2749
|
+
*
|
|
2750
|
+
* Results:
|
|
2751
|
+
*
|
|
2752
|
+
* ```
|
|
2753
|
+
* $_SERVER['REQUEST_URI'] | /api/v1/user/123
|
|
2754
|
+
* $_SERVER['SCRIPT_NAME'] | /subdir/script.php
|
|
2755
|
+
* $_SERVER['SCRIPT_FILENAME'] | /var/www/html/subdir/script.php
|
|
2756
|
+
* $_SERVER['PATH_INFO'] | (key not set)
|
|
2757
|
+
* $_SERVER['PHP_SELF'] | /subdir/script.php
|
|
2758
|
+
* $_SERVER['QUERY_STRING'] | endpoint=user&id=123
|
|
2759
|
+
* $_SERVER['REDIRECT_STATUS'] | 200
|
|
2760
|
+
* $_SERVER['REDIRECT_URL'] | /api/v1/user/123
|
|
2761
|
+
* $_SERVER['REDIRECT_QUERY_STRING'] | endpoint=user&id=123
|
|
2762
|
+
* === $_GET Variables ===
|
|
2763
|
+
* $_GET['endpoint'] | user
|
|
2764
|
+
* $_GET['id'] | 123
|
|
2765
|
+
* ```
|
|
2766
|
+
*
|
|
2767
|
+
* ## Apache – vanilla request
|
|
2768
|
+
*
|
|
2769
|
+
* Setup:
|
|
2770
|
+
* – The same as above.
|
|
2771
|
+
* – A request sent http://localhost:8041/subdir/script.php?param=value
|
|
2772
|
+
*
|
|
2773
|
+
* Results:
|
|
2774
|
+
*
|
|
2775
|
+
* ```
|
|
2776
|
+
* $_SERVER['REQUEST_URI'] | /subdir/script.php?param=value
|
|
2777
|
+
* $_SERVER['SCRIPT_NAME'] | /subdir/script.php
|
|
2778
|
+
* $_SERVER['SCRIPT_FILENAME'] | /var/www/html/subdir/script.php
|
|
2779
|
+
* $_SERVER['PATH_INFO'] | (key not set)
|
|
2780
|
+
* $_SERVER['PHP_SELF'] | /subdir/script.php
|
|
2781
|
+
* $_SERVER['REDIRECT_URL'] | (key not set)
|
|
2782
|
+
* $_SERVER['REDIRECT_STATUS'] | (key not set)
|
|
2783
|
+
* $_SERVER['QUERY_STRING'] | param=value
|
|
2784
|
+
* $_SERVER['REQUEST_METHOD'] | GET
|
|
2785
|
+
* $_SERVER['DOCUMENT_ROOT'] | /var/www/html
|
|
2786
|
+
*
|
|
2787
|
+
* === $_GET Variables ===
|
|
2788
|
+
* $_GET['param'] | value
|
|
2789
|
+
* ```
|
|
2790
|
+
*/
|
|
2791
|
+
prepare_$_SERVER_superglobal(e, r, s) {
|
|
2792
|
+
const n = {
|
|
2793
|
+
REMOTE_ADDR: "127.0.0.1",
|
|
2794
|
+
DOCUMENT_ROOT: u(this, P),
|
|
2795
|
+
HTTPS: u(this, N).startsWith("https://") ? "on" : ""
|
|
2796
|
+
};
|
|
2797
|
+
return n.REQUEST_URI = e.pathname + e.search, s.startsWith(u(this, P)) && (n.SCRIPT_NAME = s.substring(
|
|
2798
|
+
u(this, P).length
|
|
2799
|
+
), n.PHP_SELF = r.pathname, n.REQUEST_URI.startsWith(n.SCRIPT_NAME) && (n.PATH_INFO = n.REQUEST_URI.substring(
|
|
2800
|
+
n.SCRIPT_NAME.length
|
|
2801
|
+
), n.PATH_INFO.includes("?") && (n.PATH_INFO = n.PATH_INFO.substring(
|
|
2802
|
+
0,
|
|
2803
|
+
n.PATH_INFO.indexOf("?")
|
|
2804
|
+
)))), n.QUERY_STRING = r.search.substring(1), n;
|
|
2805
|
+
}
|
|
2677
2806
|
async [Symbol.asyncDispose]() {
|
|
2678
2807
|
await this.processManager[Symbol.asyncDispose]();
|
|
2679
2808
|
}
|
|
2680
2809
|
}
|
|
2681
|
-
|
|
2810
|
+
P = new WeakMap(), I = new WeakMap(), L = new WeakMap(), C = new WeakMap(), A = new WeakMap(), E = new WeakMap(), N = new WeakMap(), R = new WeakMap(), x = new WeakSet(), /**
|
|
2811
|
+
* Apply the rewrite rules to the original request URL.
|
|
2812
|
+
*
|
|
2813
|
+
* @param originalRequestUrl - The original request URL.
|
|
2814
|
+
* @returns The rewritten request URL.
|
|
2815
|
+
*/
|
|
2816
|
+
Z = function(e) {
|
|
2817
|
+
const r = removePathPrefix(
|
|
2818
|
+
decodeURIComponent(e.pathname),
|
|
2819
|
+
u(this, E)
|
|
2820
|
+
), s = applyRewriteRules(
|
|
2821
|
+
r,
|
|
2822
|
+
this.rewriteRules
|
|
2823
|
+
), n = new URL(
|
|
2824
|
+
joinPaths(u(this, E), s),
|
|
2825
|
+
e.toString()
|
|
2826
|
+
);
|
|
2827
|
+
for (const [i, o] of e.searchParams.entries())
|
|
2828
|
+
n.searchParams.append(i, o);
|
|
2829
|
+
return n;
|
|
2830
|
+
}, /**
|
|
2682
2831
|
* Serves a static file from the PHP filesystem.
|
|
2683
2832
|
*
|
|
2684
2833
|
* @param fsPath - Absolute path of the static file to serve.
|
|
2685
2834
|
* @returns The response.
|
|
2686
2835
|
*/
|
|
2687
|
-
|
|
2836
|
+
ee = function(e, r) {
|
|
2688
2837
|
const s = e.readFileAsBuffer(r);
|
|
2689
2838
|
return new PHPResponse(
|
|
2690
2839
|
200,
|
|
@@ -2699,58 +2848,58 @@ Z = function(e, r) {
|
|
|
2699
2848
|
},
|
|
2700
2849
|
s
|
|
2701
2850
|
);
|
|
2702
|
-
},
|
|
2703
|
-
let
|
|
2851
|
+
}, te = async function(e, r, s, n) {
|
|
2852
|
+
let i;
|
|
2704
2853
|
try {
|
|
2705
|
-
|
|
2854
|
+
i = await this.processManager.acquirePHPInstance({
|
|
2706
2855
|
considerPrimary: !0
|
|
2707
2856
|
});
|
|
2708
|
-
} catch (
|
|
2709
|
-
return
|
|
2857
|
+
} catch (o) {
|
|
2858
|
+
return o instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
|
|
2710
2859
|
}
|
|
2711
2860
|
try {
|
|
2712
|
-
return await
|
|
2861
|
+
return await f(this, x, re).call(this, i.php, e, r, s, n);
|
|
2713
2862
|
} finally {
|
|
2714
|
-
|
|
2863
|
+
i.reap();
|
|
2715
2864
|
}
|
|
2716
|
-
},
|
|
2717
|
-
let
|
|
2718
|
-
const
|
|
2865
|
+
}, re = async function(e, r, s, n, i) {
|
|
2866
|
+
let o = "GET";
|
|
2867
|
+
const a = {
|
|
2719
2868
|
host: u(this, A),
|
|
2720
2869
|
...normalizeHeaders(r.headers || {})
|
|
2721
2870
|
};
|
|
2722
|
-
u(this,
|
|
2723
|
-
let
|
|
2724
|
-
if (typeof
|
|
2725
|
-
|
|
2726
|
-
const { bytes:
|
|
2727
|
-
|
|
2871
|
+
u(this, R) && (a.cookie = u(this, R).getCookieRequestHeader());
|
|
2872
|
+
let c = r.body;
|
|
2873
|
+
if (typeof c == "object" && !(c instanceof Uint8Array)) {
|
|
2874
|
+
o = "POST";
|
|
2875
|
+
const { bytes: l, contentType: d } = await encodeAsMultipart(c);
|
|
2876
|
+
c = l, a["content-type"] = d;
|
|
2728
2877
|
}
|
|
2729
2878
|
try {
|
|
2730
|
-
const
|
|
2879
|
+
const l = await e.run({
|
|
2731
2880
|
relativeUri: ensurePathPrefix(
|
|
2732
|
-
toRelativeUrl(new URL(
|
|
2733
|
-
u(this,
|
|
2881
|
+
toRelativeUrl(new URL(n.toString())),
|
|
2882
|
+
u(this, E)
|
|
2734
2883
|
),
|
|
2735
2884
|
protocol: u(this, I),
|
|
2736
|
-
method: r.method ||
|
|
2737
|
-
$_SERVER:
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
body:
|
|
2743
|
-
scriptPath:
|
|
2744
|
-
headers:
|
|
2885
|
+
method: r.method || o,
|
|
2886
|
+
$_SERVER: this.prepare_$_SERVER_superglobal(
|
|
2887
|
+
s,
|
|
2888
|
+
n,
|
|
2889
|
+
i
|
|
2890
|
+
),
|
|
2891
|
+
body: c,
|
|
2892
|
+
scriptPath: i,
|
|
2893
|
+
headers: a
|
|
2745
2894
|
});
|
|
2746
|
-
return u(this,
|
|
2747
|
-
|
|
2748
|
-
),
|
|
2749
|
-
} catch (
|
|
2750
|
-
const
|
|
2751
|
-
if (
|
|
2752
|
-
return
|
|
2753
|
-
throw
|
|
2895
|
+
return u(this, R) && u(this, R).rememberCookiesFromResponseHeaders(
|
|
2896
|
+
l.headers
|
|
2897
|
+
), l;
|
|
2898
|
+
} catch (l) {
|
|
2899
|
+
const d = l;
|
|
2900
|
+
if (d != null && d.response)
|
|
2901
|
+
return d.response;
|
|
2902
|
+
throw l;
|
|
2754
2903
|
}
|
|
2755
2904
|
};
|
|
2756
2905
|
function inferMimeType(t) {
|
|
@@ -2759,8 +2908,10 @@ function inferMimeType(t) {
|
|
|
2759
2908
|
}
|
|
2760
2909
|
function applyRewriteRules(t, e) {
|
|
2761
2910
|
for (const r of e)
|
|
2762
|
-
if (new RegExp(r.match).test(t))
|
|
2763
|
-
|
|
2911
|
+
if (new RegExp(r.match).test(t)) {
|
|
2912
|
+
t = t.replace(r.match, r.replacement);
|
|
2913
|
+
break;
|
|
2914
|
+
}
|
|
2764
2915
|
return t;
|
|
2765
2916
|
}
|
|
2766
2917
|
function rotatePHPRuntime({
|
|
@@ -3044,10 +3195,10 @@ function expose(t, e = globalThis, r = ["*"], s) {
|
|
|
3044
3195
|
}, l = (i.data.argumentList || []).map(fromWireValue);
|
|
3045
3196
|
let d;
|
|
3046
3197
|
try {
|
|
3047
|
-
const p = c.slice(0, -1).reduce((g, b) => g[b], t),
|
|
3198
|
+
const p = c.slice(0, -1).reduce((g, b) => g[b], t), m = c.reduce((g, b) => g[b], t);
|
|
3048
3199
|
switch (a) {
|
|
3049
3200
|
case MessageType.GET:
|
|
3050
|
-
d =
|
|
3201
|
+
d = m;
|
|
3051
3202
|
break;
|
|
3052
3203
|
case MessageType.SET:
|
|
3053
3204
|
p[c.slice(-1)[0]] = fromWireValue(
|
|
@@ -3055,11 +3206,11 @@ function expose(t, e = globalThis, r = ["*"], s) {
|
|
|
3055
3206
|
), d = !0;
|
|
3056
3207
|
break;
|
|
3057
3208
|
case MessageType.APPLY:
|
|
3058
|
-
d =
|
|
3209
|
+
d = m.apply(p, l);
|
|
3059
3210
|
break;
|
|
3060
3211
|
case MessageType.CONSTRUCT:
|
|
3061
3212
|
{
|
|
3062
|
-
const g = new
|
|
3213
|
+
const g = new m(...l);
|
|
3063
3214
|
d = proxy(g);
|
|
3064
3215
|
}
|
|
3065
3216
|
break;
|
|
@@ -3079,14 +3230,14 @@ function expose(t, e = globalThis, r = ["*"], s) {
|
|
|
3079
3230
|
d = { value: p, [throwMarker]: 0 };
|
|
3080
3231
|
}
|
|
3081
3232
|
Promise.resolve(d).catch((p) => ({ value: p, [throwMarker]: 0 })).then((p) => {
|
|
3082
|
-
const [
|
|
3083
|
-
e.postMessage({ ...
|
|
3233
|
+
const [m, g] = toWireValue(p);
|
|
3234
|
+
e.postMessage({ ...m, id: o }, g), a === MessageType.RELEASE && (e.removeEventListener("message", n), closeEndPoint(e), finalizer in t && typeof t[finalizer] == "function" && t[finalizer]());
|
|
3084
3235
|
}).catch(() => {
|
|
3085
|
-
const [p,
|
|
3236
|
+
const [p, m] = toWireValue({
|
|
3086
3237
|
value: new TypeError("Unserializable return value"),
|
|
3087
3238
|
[throwMarker]: 0
|
|
3088
3239
|
});
|
|
3089
|
-
e.postMessage({ ...p, id: o },
|
|
3240
|
+
e.postMessage({ ...p, id: o }, m);
|
|
3090
3241
|
}).finally(() => {
|
|
3091
3242
|
s == null || s(i);
|
|
3092
3243
|
});
|
|
@@ -3184,7 +3335,7 @@ function createProxy(t, e, r = [], s = function() {
|
|
|
3184
3335
|
e,
|
|
3185
3336
|
{
|
|
3186
3337
|
type: MessageType.APPLY,
|
|
3187
|
-
path: r.map((
|
|
3338
|
+
path: r.map((m) => m.toString()),
|
|
3188
3339
|
argumentList: d
|
|
3189
3340
|
},
|
|
3190
3341
|
p
|