Files
RustProxy/docs/V0.29.1_IMPLEMENTATION.md
T
2026-10-08 22:22:46 +02:00

128 lines
5.4 KiB
Markdown

# RustProxy 0.29.1 implementation note
RustProxy 0.29.1 adds explicit Nginx-style internal error routing without parsing Nginx configuration, plus multipart byte ranges and optional PHP `PATH_INFO` support. SQLite remains schema 9 and Cold Cache remains format 3.
## Internal error fallback
A vhost main source and each Custom location can define:
```json
"error_fallback": {
"target": "redirect-check",
"statuses": [404]
}
```
`target` is the stable `id` of an enabled Custom location in the same vhost with `"internal": true`. Internal locations are retained in the compiled route table but never participate in normal public URI matching. The supported intercepted status set is deliberately bounded to `403`, `404`, `500`, `502`, `503` and `504`; omitting `statuses` defaults to `404`.
The dispatch is internal, not a `3xx` client redirect. RustProxy rebuilds the fallback request with the original HTTP method, URI, query string, HTTP version, request headers and the existing transport/request context. The target location then executes through the normal vhost/location path, including ACL/authentication, header rules, cache policy, compression and response processing. Vhost rate limiting is not charged a second time for the same client request.
For requests with a body, RustProxy can replay a body only when its exact size is known and no larger than 8 MiB. Such a request is buffered once so the same bytes can be sent to the fallback target. Unknown-size or larger streaming bodies continue to the original target, but an error fallback cannot replay them; the original error response is retained.
Configuration validation rejects missing/public fallback targets and recursive fallback cycles. A runtime depth limit of 8 internal dispatches remains as a second guard against loops after hot-reload/state inconsistencies.
Configured upstream response statuses are intercepted before normal response finalization and cache publication. RustProxy-generated reverse-proxy failures also participate where applicable: missing backend (`500`), unavailable/capacity (`503`), connect failure (`503`), invalid upstream response (`502`) and response timeout (`504`). A configured stale cached response still wins before transport-error fallback.
## Example: static files -> application -> redirector
The following vhost fragment expresses the same request flow as an Nginx `try_files`/`error_page` chain, without an HTTP redirect between stages:
```json
{
"source": {
"type": "web_server",
"web_service_id": "www-linuxiarz"
},
"error_fallback": {
"target": "to8000",
"statuses": [404]
},
"backends": [
{
"id": "app",
"url": "http://127.0.0.1:8000",
"enabled": true,
"allow_private": true,
"address_allowlist": ["127.0.0.1/32"]
},
{
"id": "redirector",
"url": "http://127.0.0.1:9000",
"enabled": true,
"allow_private": true,
"address_allowlist": ["127.0.0.1/32"]
}
],
"routes": [
{
"id": "to8000",
"internal": true,
"backend_id": "app",
"source": {"type": "reverse_proxy"},
"error_fallback": {
"target": "redirect-check",
"statuses": [404]
}
},
{
"id": "redirect-check",
"internal": true,
"backend_id": "redirector",
"source": {"type": "reverse_proxy"},
"cache": false
}
]
}
```
The effective flow is:
```text
public request
-> Web Server
2xx/3xx -> return normally
404 -> @to8000 (internal)
-> backend app
non-404 -> return normally
404 -> @redirect-check (internal)
-> redirector backend
```
Normal public Custom locations can still route `/stats`, `/user-info`, `/health`, RBL files or other paths directly before the main source is used. An internal location's `path_prefix` is not used for public matching; its `id` is the fallback name.
## Multipart byte ranges
The Web Server now accepts comma-separated byte ranges such as:
```http
Range: bytes=0-99,200-299
```
One satisfiable range retains the existing single-part `206` response. Multiple satisfiable ranges produce a streaming `multipart/byteranges` response with per-part `Content-Type` and `Content-Range`. At most 16 ranges are accepted. Malformed or entirely unsatisfiable range sets return `416`. Multipart responses use the identity file representation rather than `.br`/`.gz` sidecars so the multipart MIME framing and `Content-Encoding` semantics cannot conflict.
## PHP PATH_INFO
Web Service PHP configuration gains the default-off field:
```json
"php": {
"enabled": true,
"path_info": true
}
```
When enabled, RustProxy may resolve a request such as `/index.php/foo/bar` by finding the longest existing configured PHP script prefix under the Web Service document root. FastCGI then receives, conceptually:
```text
SCRIPT_FILENAME=/document/root/index.php
SCRIPT_NAME=/index.php
PATH_INFO=/foo/bar
REQUEST_URI=/index.php/foo/bar
```
The split uses the same document-root confinement and PHP file checks as normal script resolution. It is disabled by default because it changes URL-to-script resolution semantics.
## Compatibility
No SQLite migration is required. Existing vhosts, locations and Web Services deserialize unchanged because `internal`, `error_fallback` and PHP `path_info` use backward-compatible defaults. Existing single-range responses are retained.