harden runtime config and docs
This commit is contained in:
parent
c148c1b36b
commit
991a0f62b4
11
README.md
11
README.md
@ -311,9 +311,13 @@ The example contains the filesystem and FastCGI settings:
|
||||
BIN_DIRECTORY=/var/cache/uce/work
|
||||
TMP_UPLOAD_PATH=/var/lib/uce/uploads
|
||||
SESSION_PATH=/var/lib/uce/sessions
|
||||
SESSION_COOKIE_SECURE=1
|
||||
|
||||
FCGI_SOCKET_PATH=/run/uce/fastcgi.sock
|
||||
FCGI_SOCKET_MODE=0666
|
||||
FCGI_PORT=9993
|
||||
CLI_SOCKET_PATH=/run/uce/cli.sock
|
||||
CLI_SOCKET_MODE=0600
|
||||
|
||||
PRECOMPILE_FILES_IN=
|
||||
SITE_DIRECTORY=/var/www/html
|
||||
@ -328,7 +332,7 @@ For nginx deployments, the most important setting is:
|
||||
|
||||
- `FCGI_SOCKET_PATH=/run/uce/fastcgi.sock`
|
||||
|
||||
That is the Unix socket nginx should use for normal `.uce` requests.
|
||||
That is the Unix socket nginx should use for normal `.uce` requests. `CLI_SOCKET_PATH` is for local admin/test execution through `scripts/uce-cli`; keep `CLI_SOCKET_MODE=0600` unless a trusted Unix group explicitly needs access.
|
||||
|
||||
`FCGI_PORT` is optional if nginx is talking to the Unix socket. Leave it set if you also want a TCP FastCGI listener, or remove it if you want the socket to be the only FastCGI entry point.
|
||||
|
||||
@ -350,6 +354,7 @@ Recommended deployment notes:
|
||||
|
||||
- keep `HTTP_PORT` bound to localhost only at the firewall or by network policy; nginx should be the public entry point
|
||||
- keep `BIN_DIRECTORY`, `TMP_UPLOAD_PATH`, and `SESSION_PATH` on writable local storage
|
||||
- use `SESSION_COOKIE_SECURE=1` for HTTPS-only deployments; leave it `0` only for local/plain-HTTP development
|
||||
- after editing `/etc/uce/settings.cfg`, restart `uce.service`
|
||||
|
||||
### 4. Install and enable the systemd service
|
||||
@ -362,8 +367,8 @@ scripts/systemd/manage-uce-service.sh setup
|
||||
|
||||
That script:
|
||||
|
||||
- installs `scripts/systemd/uce.service` as `/etc/systemd/system/uce.service`
|
||||
- installs `etc/uce/settings.cfg` to `/etc/uce/settings.cfg` if it does not already exist
|
||||
- installs `scripts/systemd/uce.service` as `/etc/systemd/system/uce.service`, rewriting the repository-root path in the unit to the checkout you ran it from
|
||||
- installs `etc/uce/settings.cfg` to `/etc/uce/settings.cfg` if it does not already exist, likewise rewriting checkout-root paths
|
||||
- reloads systemd
|
||||
- enables the service at boot
|
||||
- starts the runtime immediately
|
||||
|
||||
@ -11,20 +11,20 @@ A typical deployment has four pieces:
|
||||
3. `uce.service`, a systemd service that builds/starts/restarts the runtime.
|
||||
4. nginx or Apache as the public HTTP server.
|
||||
|
||||
Recommended filesystem layout for a source checkout:
|
||||
Recommended filesystem layout for a source checkout (replace paths as needed):
|
||||
|
||||
```text
|
||||
/opt/uce/ UCE repository/runtime root
|
||||
/var/www/html/ public web root served by nginx/Apache
|
||||
/etc/uce/settings.cfg runtime configuration
|
||||
/run/uce/fastcgi.sock FastCGI socket used by nginx/Apache
|
||||
/run/uce/cli.sock local CLI/admin/test socket
|
||||
/var/cache/uce/work generated source, wasm modules, caches
|
||||
/var/lib/uce/uploads multipart upload scratch space
|
||||
/var/lib/uce/sessions session files
|
||||
/path/to/uce-root UCE repository/runtime root (for example `/opt/uce` or `/Code/uce.openfu.com/uce`)
|
||||
/var/www/html/ public web root served by nginx/Apache
|
||||
/etc/uce/settings.cfg runtime configuration
|
||||
/run/uce/fastcgi.sock FastCGI socket used by nginx/Apache
|
||||
/run/uce/cli.sock local CLI/admin/test socket
|
||||
/var/cache/uce/work generated source, wasm modules, caches
|
||||
/var/lib/uce/uploads multipart upload scratch space
|
||||
/var/lib/uce/sessions session files
|
||||
```
|
||||
|
||||
For packaged installs, the runtime may live under `/usr/lib/uce` instead of `/opt/uce`. Keep the public web root at `/var/www/html` or another normal web-root path, not under the runtime source tree.
|
||||
For packaged installs, the runtime may live under `/usr/lib/uce` instead of your checkout root. Keep the public web root at `/var/www/html` or another normal web-root path, not under the runtime source tree.
|
||||
|
||||
## Build requirements
|
||||
|
||||
@ -62,10 +62,11 @@ apt install -y nginx
|
||||
apt install -y apache2
|
||||
```
|
||||
|
||||
Build UCE from the repository root:
|
||||
Build UCE from your repository root:
|
||||
|
||||
```bash
|
||||
cd /opt/uce
|
||||
repo_root=/path/to/uce-root
|
||||
cd "$repo_root"
|
||||
bash scripts/build_core_wasm.sh
|
||||
bash scripts/build_linux.sh
|
||||
```
|
||||
@ -104,7 +105,8 @@ The expected directories are:
|
||||
Install the WASI SDK:
|
||||
|
||||
```bash
|
||||
cd /opt/uce
|
||||
repo_root=/path/to/uce-root
|
||||
cd "$repo_root"
|
||||
scripts/install_wasi_sdk.sh
|
||||
scripts/install_wasi_sdk.sh --check-only
|
||||
```
|
||||
@ -163,7 +165,7 @@ systemctl restart uce.service
|
||||
|
||||
## Runtime configuration
|
||||
|
||||
Create `/etc/uce/settings.cfg` from `etc/uce/settings.cfg` and adjust paths if your runtime is not under `/opt/uce`. Replace any checkout-specific paths such as `WASM_CORE_PATH` with `/opt/uce/bin/wasm/core.wasm` or your actual runtime path.
|
||||
Create `/etc/uce/settings.cfg` from `etc/uce/settings.cfg` and adjust paths to your checkout root. Replace checkout-specific settings such as `WASM_CORE_PATH` with `<UCE_REPO_ROOT>/bin/wasm/core.wasm` or leave it relative to `COMPILER_SYS_PATH` as appropriate.
|
||||
|
||||
Minimum useful settings:
|
||||
|
||||
@ -171,9 +173,12 @@ Minimum useful settings:
|
||||
BIN_DIRECTORY=/var/cache/uce/work
|
||||
TMP_UPLOAD_PATH=/var/lib/uce/uploads
|
||||
SESSION_PATH=/var/lib/uce/sessions
|
||||
SESSION_COOKIE_SECURE=1
|
||||
|
||||
FCGI_SOCKET_PATH=/run/uce/fastcgi.sock
|
||||
FCGI_SOCKET_MODE=0666
|
||||
CLI_SOCKET_PATH=/run/uce/cli.sock
|
||||
CLI_SOCKET_MODE=0600
|
||||
|
||||
SITE_DIRECTORY=/var/www/html
|
||||
HTTP_DOCUMENT_ROOT=/var/www/html
|
||||
@ -183,7 +188,7 @@ PROACTIVE_COMPILE_CHECK_INTERVAL=60
|
||||
|
||||
WASM_COMPILE_SCRIPT=scripts/compile_wasm_unit
|
||||
WASM_BACKEND_VERBOSE=0
|
||||
WASM_CORE_PATH=/opt/uce/bin/wasm/core.wasm
|
||||
WASM_CORE_PATH=<UCE_REPO_ROOT>/bin/wasm/core.wasm
|
||||
WASM_MEMORY_LIMIT_BYTES=536870912
|
||||
WASM_EPOCH_DEADLINE_TICKS=200
|
||||
WASM_EPOCH_PERIOD_MS=50
|
||||
@ -199,11 +204,13 @@ WS_BROKER_OUTBOUND_TIMEOUT_SECONDS=30
|
||||
Important settings:
|
||||
|
||||
- `FCGI_SOCKET_PATH` is the Unix socket used for normal `.uce` requests. Set it explicitly and keep this value and the web-server `fastcgi_pass` path identical. The reference config uses `/run/uce/fastcgi.sock`; if you choose `/run/uce.sock`, use it in both places.
|
||||
- `CLI_SOCKET_PATH` is a local HTTP-over-Unix socket used by `scripts/uce-cli` and test/admin units.
|
||||
- `CLI_SOCKET_PATH` is a local HTTP-over-Unix socket used by `scripts/uce-cli` and test/admin units. Keep it private (`CLI_SOCKET_MODE=0600`) unless you intentionally delegate admin/test execution to a trusted Unix group (`0660`).
|
||||
- `FCGI_SOCKET_MODE` and `CLI_SOCKET_MODE` are octal permission modes applied after socket bind. Prefer tightening `FCGI_SOCKET_MODE` to `0660` when nginx/Apache can share a trusted group with the UCE worker.
|
||||
- `SITE_DIRECTORY` is the public site tree to scan for `.uce` files. Use `/var/www/html` when the web root is outside the runtime tree; relative paths are resolved from the runtime working directory.
|
||||
- `HTTP_DOCUMENT_ROOT` is the root used by the built-in HTTP/WebSocket listener when it resolves upgrade requests. Set it to the same web root as nginx/Apache.
|
||||
- `BIN_DIRECTORY` stores generated C++, wasm artifacts, compile output, and runtime caches.
|
||||
- `TMP_UPLOAD_PATH` and `SESSION_PATH` must be writable by the runtime.
|
||||
- `SESSION_COOKIE_SECURE=1` adds the `Secure` attribute to UCE-managed session cookies and should be used for HTTPS-only deployments. Leave it `0` only for local/plain-HTTP development.
|
||||
- `HTTP_PORT` is the built-in HTTP/WebSocket listener used for WebSocket upgrade traffic and direct local probes. Bind/firewall it for local access only; nginx/Apache should be the public entry point.
|
||||
- `WS_BROKER_OUTBOUND_TIMEOUT_SECONDS` controls how long a forwarded WS message can remain queued in the broker before being dropped (default `30`). Set to `0` to disable the timeout.
|
||||
- `WASM_COMPILE_SCRIPT` must point to `scripts/compile_wasm_unit` unless you provide an equivalent compiler. Relative paths are resolved from the runtime root/`COMPILER_SYS_PATH`. That script calls `scripts/check_unit_wasm.py` after linking each unit and uses the pinned WASI SDK on every deployment host.
|
||||
@ -220,11 +227,12 @@ systemctl restart uce.service
|
||||
For source-checkout deployments, install the provided service helper:
|
||||
|
||||
```bash
|
||||
cd /opt/uce
|
||||
repo_root=/path/to/uce-root
|
||||
cd "$repo_root"
|
||||
scripts/systemd/manage-uce-service.sh setup
|
||||
```
|
||||
|
||||
That helper installs `scripts/systemd/uce.service`, creates runtime directories, enables the service, and starts it.
|
||||
That helper installs `scripts/systemd/uce.service` from your checked-out tree, rewrites the checked-out repository path into the installed unit and first-time config, creates runtime directories, enables the service, and starts it. Use a custom unit only if you need a nonstandard runtime layout.
|
||||
|
||||
Useful commands:
|
||||
|
||||
@ -234,7 +242,7 @@ scripts/systemd/manage-uce-service.sh restart
|
||||
scripts/systemd/manage-uce-service.sh logs 200
|
||||
```
|
||||
|
||||
Equivalent manual systemd service for a source checkout:
|
||||
Equivalent manual systemd service for a source checkout (`<UCE_REPO>` = checkout root):
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
@ -244,14 +252,14 @@ Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/uce
|
||||
WorkingDirectory=<UCE_REPO>
|
||||
RuntimeDirectory=uce
|
||||
StateDirectory=uce
|
||||
CacheDirectory=uce
|
||||
ExecStartPre=/usr/bin/mkdir -p /var/cache/uce/work /var/lib/uce/uploads /var/lib/uce/sessions
|
||||
ExecStartPre=/usr/bin/rm -f /run/uce/fastcgi.sock
|
||||
ExecStartPre=/usr/bin/bash /opt/uce/scripts/build_linux.sh
|
||||
ExecStart=/opt/uce/bin/uce_fastcgi.linux.bin
|
||||
ExecStartPre=/usr/bin/bash <UCE_REPO>/scripts/build_linux.sh
|
||||
ExecStart=<UCE_REPO>/bin/uce_fastcgi.linux.bin
|
||||
ExecStopPost=/usr/bin/rm -f /run/uce/fastcgi.sock
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
@ -584,7 +592,8 @@ curl -i http://127.0.0.1/examples/uce-starter/ -H 'Host: example.com'
|
||||
Check the local CLI path:
|
||||
|
||||
```bash
|
||||
cd /opt/uce
|
||||
repo_root=/path/to/uce-root
|
||||
cd "$repo_root"
|
||||
scripts/uce-cli /tests/cli.uce action=echo message=hello
|
||||
scripts/run_cli_tests.sh
|
||||
```
|
||||
@ -615,7 +624,7 @@ PY
|
||||
## Operational footguns
|
||||
|
||||
- Keep the FastCGI socket path consistent: `FCGI_SOCKET_PATH` and the web-server `fastcgi_pass` must match exactly. The reference config uses `/run/uce/fastcgi.sock`; if you choose `/run/uce.sock`, use it in both places.
|
||||
- Keep the public web root separate from the runtime source tree. The examples use `/opt/uce` for runtime files and `/var/www/html` for public files.
|
||||
- Keep the public web root separate from the runtime source tree. Replace `/opt/uce` with your actual checkout path in local examples (for example `/opt/uce` or `/Code/uce.openfu.com/uce`), and keep public files under `/var/www/html`.
|
||||
- Set `HTTP_DOCUMENT_ROOT` when the web root is outside the runtime working directory. The built-in HTTP/WebSocket listener resolves upgrade paths from this setting.
|
||||
- Do not expose `CLI_SOCKET_PATH` or `HTTP_PORT` as public entry points. The public path should be nginx/Apache.
|
||||
- Do not trust `Script-Filename` request headers from direct HTTP clients. The built-in HTTP listener resolves from `HTTP_DOCUMENT_ROOT` and rejects `..` path segments.
|
||||
|
||||
@ -26,10 +26,10 @@ gets invoked*.
|
||||
|
||||
```
|
||||
┌────────────────────────────┐
|
||||
nginx ──FastCGI──► worker pool (N processes) │ /run/uce.sock
|
||||
nginx ──FastCGI──► worker pool (N processes) │ $FCGI_SOCKET_PATH (example `/run/uce/fastcgi.sock`)
|
||||
(port 80 etc.) │ uniform unit renderers │ (FastCGI + CLI)
|
||||
└─────────────▲──────────────┘
|
||||
│ forward render (FastCGI, uce.sock)
|
||||
│ forward render (FastCGI, FCGI_SOCKET_PATH)
|
||||
│
|
||||
browser ──raw HTTP / WS──► ┌────────┴─────────┐
|
||||
(HTTP_PORT 8080) │ WS broker │ owns HTTP_PORT + every
|
||||
@ -48,14 +48,14 @@ gets invoked*.
|
||||
| Process | Owns | Renders units? | Source |
|
||||
|---|---|---|---|
|
||||
| **Parent** | nothing; supervises children | no | `main()`, `init_base_process()` |
|
||||
| **Worker** (×`WORKER_COUNT`) | `FCGI_SOCKET_PATH` (`/run/uce.sock`) + `CLI_SOCKET_PATH` | **yes** — the only processes that run wasm | `listen_for_connections()` |
|
||||
| **Worker** (×`WORKER_COUNT`) | `FCGI_SOCKET_PATH` (configured socket path; example `/run/uce/fastcgi.sock`) + `CLI_SOCKET_PATH` | **yes** — the only processes that run wasm | `listen_for_connections()` |
|
||||
| **WS broker** (×1) | `HTTP_PORT` + every live WS connection + `WS_BROKER_SOCKET_PATH` | no — forwards to the pool | `run_ws_broker()` |
|
||||
| **serve_http dispatcher** (×bind) | one custom-server bind address | no — forwards to the pool | `custom_server_http_dispatcher_loop()` |
|
||||
| **Proactive compiler** | nothing; pre-compiles units | no | `run_proactive_compiler()` |
|
||||
|
||||
**only workers instantiate Wasmtime and run unit code.**
|
||||
Every connection-owning process (broker, serve_http dispatcher) forwards the
|
||||
request invocation back to a worker over `/run/uce.sock` using the minimal
|
||||
request invocation back to a worker via `FCGI_SOCKET_PATH` using the minimal
|
||||
FastCGI client in [`src/lib/fcgi_forward.h`](../src/lib/fcgi_forward.h). This is
|
||||
forced by Wasmtime: an `Engine`/`Store` cannot be safely re-created across
|
||||
`fork()`, and the brokers fork from the parent that already touched the
|
||||
@ -137,7 +137,7 @@ Each request gets a fresh **workspace** — a per-request wasm instance tree wit
|
||||
the membrane wired in. `wasm_worker_serve(worker, ctx, entry_unit, handler)`
|
||||
(`src/wasm/worker.cpp`) is the single entry point for *every* mode:
|
||||
|
||||
1. Birth a workspace (CoW-snapshot-based where available).
|
||||
1. Birth a request-scoped workspace with fresh per-request state. Current production workers instantiate a fresh workspace for each request; any future snapshot/CoW optimization must preserve that request-isolation contract.
|
||||
2. Resolve `entry_unit` + `handler` to an export; components referenced at
|
||||
runtime are resolved on demand via the `uce_host_component_resolve` hostcall
|
||||
(`component_resolve()` → `__uce_<...>` slot), loading dependency modules
|
||||
@ -158,8 +158,7 @@ Wasmtime's own trap signals are not escalated into a native fatal signal (see
|
||||
captures the current `WasmWorkspace*`, but `src/lib/sys.cpp::task()` invokes the
|
||||
captured callback only in the forked child, before the hostcall stack unwinds in
|
||||
that child. The parent request may return and destroy its workspace; the child
|
||||
still has its own copy-on-write stack and its own copy of the per-request wasm
|
||||
workspace. This means a delayed task callback can run after the spawning request
|
||||
is forked from the parent and keeps a private request-context copy of the per-request workspace. This means a delayed task callback can run after the spawning request
|
||||
returns without dereferencing the parent's destroyed workspace. It is still a
|
||||
callback into the inherited child workspace, not a fresh normal request
|
||||
workspace; avoid adding host resources to `WasmWorkspace` that are invalid across
|
||||
@ -182,7 +181,7 @@ otherwise (page) → serve_via_wasm(entry_unit, "render")
|
||||
|
||||
The `UCE_*` params are set by whichever broker forwarded the request:
|
||||
|
||||
- **Page render**: FastCGI nginx → `/run/uce.sock` directly; no `UCE_*` flags → `render`.
|
||||
- **Page render**: FastCGI nginx → `FCGI_SOCKET_PATH` directly; no `UCE_*` flags → `render`.
|
||||
- **CLI**: the CLI socket sets `is_cli`.
|
||||
- **serve_http**: the custom-server dispatcher sets `UCE_SERVE_HTTP=1` plus
|
||||
`UCE_SERVE_HTTP_FUNCTION` and rewrites `SCRIPT_FILENAME` to the configured
|
||||
@ -218,7 +217,7 @@ broker loop:
|
||||
2. The message rides as `UCE_WS_MESSAGE` (base64) with an **empty STDIN body** —
|
||||
a non-empty STDIN makes the FastCGI transport flush a premature response
|
||||
before `on_complete` ever runs.
|
||||
3. Connect to `/run/uce.sock` (non-blocking) and queue the encoded request in
|
||||
3. Connect to `FCGI_SOCKET_PATH` (non-blocking) and queue the encoded request in
|
||||
`ws_broker_outbound[fd]` with an enqueue timestamp.
|
||||
|
||||
`ws_broker_drain_outbound()` runs after every `process(50)` tick: it finishes
|
||||
@ -310,8 +309,10 @@ header free-functions are `inline`. The wasm backend exposes only declarations
|
||||
| Key | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `WASM_BACKEND_VERBOSE` | `0` | Emit `X-UCE-Wasm-*` workspace timing headers (benchmark only). |
|
||||
| `FCGI_SOCKET_PATH` | `/run/uce.sock` | Worker pool FastCGI socket (brokers forward here). |
|
||||
| `CLI_SOCKET_PATH` | `/run/uce/cli.sock` | Worker CLI socket. |
|
||||
| `FCGI_SOCKET_PATH` | runtime-configured (`/run/uce/fastcgi.sock` in this doc) | Worker pool FastCGI socket (brokers forward here). |
|
||||
| `CLI_SOCKET_PATH` | `/run/uce/cli.sock` | Worker CLI/admin socket. Keep private; reference `CLI_SOCKET_MODE` is `0600`. |
|
||||
| `FCGI_SOCKET_MODE` | `0666` | Permission mode applied to `FCGI_SOCKET_PATH` after bind; set tighter if nginx/Apache can use a trusted group. |
|
||||
| `CLI_SOCKET_MODE` | `0600` | Permission mode applied to `CLI_SOCKET_PATH`; set `0660` only for a trusted admin group. |
|
||||
| `HTTP_PORT` | `8080` | Raw HTTP + WebSocket port — owned by the WS broker. |
|
||||
| `WS_BROKER_SOCKET_PATH` | `/run/uce/ws-broker.sock` | Broker command socket for `ws_*` flushes. |
|
||||
| `WS_BROKER_OUTBOUND_TIMEOUT_SECONDS` | `30` | Max lifetime in seconds for queued WS broker forwards before drop. |
|
||||
|
||||
@ -5,11 +5,15 @@ SESSION_PATH=/var/lib/uce/sessions
|
||||
|
||||
# LISTEN ON SOCKETS
|
||||
FCGI_SOCKET_PATH=/run/uce/fastcgi.sock
|
||||
# FastCGI is normally consumed by the local web server user/group.
|
||||
FCGI_SOCKET_MODE=0666
|
||||
FCGI_PORT=9993
|
||||
|
||||
# HTTP-over-Unix command socket for local CLI/control tooling.
|
||||
# Example: curl --unix-socket /run/uce/cli.sock http://localhost/ping
|
||||
CLI_SOCKET_PATH=/run/uce/cli.sock
|
||||
# Keep the CLI/admin socket private by default; set 0660 only for a trusted group.
|
||||
CLI_SOCKET_MODE=0600
|
||||
|
||||
# Built-in HTTP/WebSocket listener used for WebSocket Upgrade requests.
|
||||
# Keep this behind nginx/Apache on localhost or firewall it from public access.
|
||||
@ -34,7 +38,7 @@ WASM_COMPILE_SCRIPT=scripts/compile_wasm_unit
|
||||
|
||||
# WASM RUNTIME SETTINGS. Unit execution is always routed through wasm.
|
||||
WASM_BACKEND_VERBOSE=0
|
||||
WASM_CORE_PATH=/Code/uce.openfu.com/uce/bin/wasm/core.wasm
|
||||
WASM_CORE_PATH=bin/wasm/core.wasm
|
||||
WASM_MEMORY_LIMIT_BYTES=536870912
|
||||
WASM_EPOCH_DEADLINE_TICKS=200
|
||||
WASM_EPOCH_PERIOD_MS=50
|
||||
@ -85,6 +89,8 @@ ARCHIVE_MAX_ZIP_ENTRIES=4096
|
||||
|
||||
# LIFETIME OF SESSION COOKIES IN SECONDS
|
||||
SESSION_TIME=2592000
|
||||
# Set to 1 behind HTTPS-only frontends to add Secure to session cookies.
|
||||
SESSION_COOKIE_SECURE=0
|
||||
|
||||
# DEVELOPER-DEFINED ERROR PAGES (see /doc/index.uce?p=error_pages and
|
||||
# /doc/index.uce?p=3_blocked_functions). The unit receives the error details in
|
||||
|
||||
@ -19,10 +19,23 @@ CONFIG_DEST="/etc/uce/settings.cfg"
|
||||
|
||||
action="${1:-setup}"
|
||||
|
||||
render_runtime_file() {
|
||||
local source="$1"
|
||||
local destination="$2"
|
||||
local mode="$3"
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
trap 'rm -f "$tmp"' RETURN
|
||||
sed "s#/Code/uce.openfu.com/uce#$REPO_ROOT#g" "$source" > "$tmp"
|
||||
install -D -m "$mode" "$tmp" "$destination"
|
||||
rm -f "$tmp"
|
||||
trap - RETURN
|
||||
}
|
||||
|
||||
install_unit() {
|
||||
install -D -m 0644 "$UNIT_SOURCE" "$UNIT_DEST"
|
||||
render_runtime_file "$UNIT_SOURCE" "$UNIT_DEST" 0644
|
||||
if [[ ! -f "$CONFIG_DEST" ]]; then
|
||||
install -D -m 0644 "$CONFIG_SOURCE" "$CONFIG_DEST"
|
||||
render_runtime_file "$CONFIG_SOURCE" "$CONFIG_DEST" 0644
|
||||
fi
|
||||
systemctl daemon-reload
|
||||
}
|
||||
|
||||
@ -8,9 +8,9 @@ session_name : the name of the session
|
||||
>session
|
||||
|
||||
:content
|
||||
Deletes the cookie specified by `session_name` and clears the data stored under the current session ID.
|
||||
Deletes the cookie specified by `session_name`, removes the matching server-side session file, and clears the data stored under the current session ID.
|
||||
|
||||
This also empties `context.session_id` and `context.session`.
|
||||
This also empties `context.session_id`, `context.session_name`, and `context.session`.
|
||||
|
||||
|
||||
:example
|
||||
|
||||
@ -11,7 +11,7 @@ return value : the current session ID
|
||||
:content
|
||||
Starts a session or reconnects to an existing one.
|
||||
|
||||
If the cookie named by `session_name` does not exist, UCE creates it and fills it with a new unique session ID. The function then loads the session data for that ID.
|
||||
If the cookie named by `session_name` does not exist, UCE creates it and fills it with a new unique session ID. The function then loads the session data for that ID. Session cookies are emitted with `Path=/`, `HttpOnly`, `SameSite=Lax`, and `Secure` when `SESSION_COOKIE_SECURE=1` is set in the runtime config.
|
||||
|
||||
After `session_start()` completes, the following `context` fields are populated:
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
u64 socket_connect(String host, u16 port)
|
||||
|
||||
:params
|
||||
host : host name
|
||||
host : IPv4 address (for example `127.0.0.1`), as a dotted-quad string
|
||||
port : port number
|
||||
return value : the socket handle
|
||||
|
||||
@ -12,7 +12,7 @@ return value : the socket handle
|
||||
:content
|
||||
Opens a socket connection to the given `host` and `port`.
|
||||
|
||||
The returned socket handle is then used with `socket_read()`, `socket_write()`, and `socket_close()`.
|
||||
The returned socket handle is then used with `socket_read()`, `socket_write()`, and `socket_close()`. Currently this helper accepts IPv4 dotted-quad addresses in socket calls and does not perform hostname resolution.
|
||||
|
||||
:example
|
||||
u64 fd = socket_connect("127.0.0.1", 80);
|
||||
|
||||
@ -17,8 +17,9 @@ RENDER(Request& context)
|
||||
|
||||
String action = first(context.get["action"], "touch");
|
||||
String session_id = session_start("uce-site-tests");
|
||||
String session_path = context.server->config["SESSION_PATH"] + "/" + session_id;
|
||||
if(action == "destroy")
|
||||
session_destroy();
|
||||
session_destroy("uce-site-tests");
|
||||
else
|
||||
context.session["suite"] = "http";
|
||||
|
||||
@ -56,7 +57,7 @@ RENDER(Request& context)
|
||||
check("session_id_create()", generated_session.length() >= 16, generated_session);
|
||||
|
||||
if(action == "destroy")
|
||||
check("session_destroy()", session_dump.find("suite") == String::npos, session_dump);
|
||||
check("session_destroy()", session_dump.find("suite") == String::npos && context.session_id == "" && context.session_name == "" && !file_exists(session_path), session_dump + " path=" + session_path);
|
||||
else
|
||||
check("context.session writes", context.session["suite"] == "http", session_dump);
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
// Minimal FastCGI client used by the connection brokers (the custom HTTP server
|
||||
// dispatcher and the websocket exec child) to render a request through a normal
|
||||
// worker on /run/uce.sock instead of rendering wasm in the broker's own forked
|
||||
// worker on FCGI_SOCKET_PATH instead of rendering wasm in the broker's own forked
|
||||
// process. Wasmtime cannot be safely re-created across fork, so the broker owns
|
||||
// the connection but forwards the actual unit invocation to a clean-engine
|
||||
// worker — the "broker holds connections, units respond like RENDER()" model.
|
||||
|
||||
@ -876,7 +876,6 @@ String shell_exec(String cmd)
|
||||
|
||||
String shell_escape(String raw)
|
||||
{
|
||||
// FIXME
|
||||
String result = "";
|
||||
for(auto c : raw)
|
||||
{
|
||||
@ -971,8 +970,12 @@ bool path_is_within(String path, String root)
|
||||
|
||||
bool mkdir(String path)
|
||||
{
|
||||
shell_exec(String("mkdir -p ")+" "+shell_escape(path));
|
||||
return(true);
|
||||
if(path == "")
|
||||
return(false);
|
||||
std::error_code ec;
|
||||
if(std::filesystem::exists(path, ec))
|
||||
return(std::filesystem::is_directory(path, ec));
|
||||
return(std::filesystem::create_directories(path, ec) || std::filesystem::is_directory(path, ec));
|
||||
}
|
||||
|
||||
bool file_exists(String path)
|
||||
@ -1605,7 +1608,18 @@ void on_child_exit(int sig)
|
||||
|
||||
StringList ls(String dir)
|
||||
{
|
||||
return(split(trim(shell_exec("ls -1 "+shell_escape(dir))), "\n"));
|
||||
StringList entries;
|
||||
std::error_code ec;
|
||||
if(!std::filesystem::is_directory(dir, ec))
|
||||
return(entries);
|
||||
for(auto const& entry : std::filesystem::directory_iterator(dir, ec))
|
||||
{
|
||||
if(ec)
|
||||
break;
|
||||
entries.push_back(entry.path().filename().string());
|
||||
}
|
||||
std::sort(entries.begin(), entries.end());
|
||||
return(entries);
|
||||
}
|
||||
|
||||
StringMap make_server_settings()
|
||||
@ -1622,8 +1636,10 @@ StringMap make_server_settings()
|
||||
cfg["SETUP_TEMPLATE"] = "scripts/setup.h.template";
|
||||
cfg["LIT_ESC"] = "3d5b5_1";
|
||||
cfg["CONTENT_TYPE"] = "text/html; charset=utf-8";
|
||||
cfg["FCGI_SOCKET_PATH"] = "/run/uce.sock";
|
||||
cfg["FCGI_SOCKET_PATH"] = "/run/uce/fastcgi.sock";
|
||||
cfg["FCGI_SOCKET_MODE"] = "0666";
|
||||
cfg["CLI_SOCKET_PATH"] = "/run/uce/cli.sock";
|
||||
cfg["CLI_SOCKET_MODE"] = "0600";
|
||||
// Command socket the WS broker listens on; workers flush ws_* dispatch
|
||||
// command batches here at workspace teardown.
|
||||
cfg["WS_BROKER_SOCKET_PATH"] = "/run/uce/ws-broker.sock";
|
||||
@ -1632,6 +1648,7 @@ StringMap make_server_settings()
|
||||
cfg["UCE_HOSTCALL_BLOCKLIST"] = "";
|
||||
cfg["TMP_UPLOAD_PATH"] = "/tmp/uce/uploads";
|
||||
cfg["SESSION_PATH"] = "/tmp/uce/sessions";
|
||||
cfg["SESSION_COOKIE_SECURE"] = "0";
|
||||
cfg["COMPILER_SYS_PATH"] = ".";
|
||||
cfg["PRECOMPILE_FILES_IN"] = "";
|
||||
cfg["SITE_DIRECTORY"] = "site";
|
||||
|
||||
@ -843,7 +843,8 @@ String session_start(String session_name)
|
||||
if(session_id.length() == 0)
|
||||
{
|
||||
session_id = session_id_create();
|
||||
set_cookie(session_name, session_id, time() + int_val(context->server->config["SESSION_TIME"]));
|
||||
bool secure_cookie = context->server->config["SESSION_COOKIE_SECURE"] == "1";
|
||||
set_cookie(session_name, session_id, time() + int_val(context->server->config["SESSION_TIME"]), "/", "", secure_cookie, true);
|
||||
}
|
||||
context->session_id = session_id;
|
||||
context->session_name = session_name;
|
||||
@ -856,12 +857,23 @@ String session_start(String session_name)
|
||||
|
||||
void session_destroy(String session_name)
|
||||
{
|
||||
if(context->cookies[session_name].length() > 0)
|
||||
String cookie_session_id = context->cookies[session_name];
|
||||
String active_session_id = context->session_name == session_name ? context->session_id : "";
|
||||
String destroy_session_id = active_session_id != "" ? active_session_id : cookie_session_id;
|
||||
if(cookie_session_id.length() > 0 || active_session_id.length() > 0)
|
||||
{
|
||||
set_cookie(session_name, "", time() - int_val(context->server->config["SESSION_TIME"]));
|
||||
context->session.clear();
|
||||
save_session_data(context->session_id, context->session);
|
||||
context->session_id = "";
|
||||
bool secure_cookie = context->server->config["SESSION_COOKIE_SECURE"] == "1";
|
||||
set_cookie(session_name, "", time() - int_val(context->server->config["SESSION_TIME"]), "/", "", secure_cookie, true);
|
||||
String session_path = session_file_path(destroy_session_id);
|
||||
if(session_path != "")
|
||||
file_unlink(session_path);
|
||||
if(active_session_id != "")
|
||||
{
|
||||
context->session.clear();
|
||||
context->session_loaded_hash = session_hash_serialized(session_serialize(context->session));
|
||||
context->session_id = "";
|
||||
context->session_name = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1353,6 +1353,27 @@ void listen_for_connections()
|
||||
}
|
||||
}
|
||||
|
||||
mode_t configured_socket_mode(String value, mode_t fallback)
|
||||
{
|
||||
value = trim(value);
|
||||
if(value == "")
|
||||
return(fallback);
|
||||
char* end = 0;
|
||||
long parsed = strtol(value.c_str(), &end, 8);
|
||||
if(end == value.c_str() || *end != '\0' || parsed < 0 || parsed > 0777)
|
||||
return(fallback);
|
||||
return((mode_t)parsed);
|
||||
}
|
||||
|
||||
void chmod_configured_socket(String path, String mode_value, mode_t fallback)
|
||||
{
|
||||
if(path == "")
|
||||
return;
|
||||
mode_t mode = configured_socket_mode(mode_value, fallback);
|
||||
if(chmod(path.c_str(), mode) != 0)
|
||||
fprintf(stderr, "(!) Could not chmod socket %s to %04o: %s\n", path.c_str(), (unsigned int)mode, strerror(errno));
|
||||
}
|
||||
|
||||
void init_base_process()
|
||||
{
|
||||
printf("(P) Starting parent server PID:%i\n", getpid());
|
||||
@ -1369,13 +1390,13 @@ void init_base_process()
|
||||
if(server_state.config["FCGI_SOCKET_PATH"] != "")
|
||||
{
|
||||
server.listen(server_state.config["FCGI_SOCKET_PATH"]);
|
||||
chmod(server_state.config["FCGI_SOCKET_PATH"].c_str(), S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
chmod_configured_socket(server_state.config["FCGI_SOCKET_PATH"], server_state.config["FCGI_SOCKET_MODE"], 0666);
|
||||
}
|
||||
|
||||
if(server_state.config["CLI_SOCKET_PATH"] != "")
|
||||
{
|
||||
server.listen_cli(server_state.config["CLI_SOCKET_PATH"]);
|
||||
chmod(server_state.config["CLI_SOCKET_PATH"].c_str(), S_IRWXU | S_IRGRP | S_IWGRP);
|
||||
chmod_configured_socket(server_state.config["CLI_SOCKET_PATH"], server_state.config["CLI_SOCKET_MODE"], 0600);
|
||||
}
|
||||
|
||||
// HTTP_PORT (WebSocket + raw HTTP) is owned by the dedicated WS broker, not
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user