Summary
WFL's built-in web server cannot serve binary files (fonts, images, etc.) losslessly. Both the file-read path and the HTTP response body are String/UTF-8-based, so any non-UTF-8 bytes are corrupted before they reach the client. This blocks natural static-asset serving — e.g. self-hosting a .ttf font or serving a .png/.ico directly from a WFL web server.
Impact / motivation
Building the WFL website in WFL (serving its own marketing site via listen on port ...) requires serving a self-hosted Alegreya .ttf, a favicon, and potentially raster images. Today that's impossible without a workaround (base64 data: URIs embedded in a text CSS file), which inflates payloads and isn't how anyone expects static serving to work.
Root cause (two text-only chokepoints)
All references are in src/interpreter/mod.rs.
-
File read is text-only. The WFL read content path uses read_to_string:
// src/interpreter/mod.rs:739
match AsyncReadExt::read_to_string(&mut file_clone, &mut contents).await {
A .ttf/.png is corrupted the moment it is loaded. Note that binary-capable readers already exist internally but aren't wired to a WFL keyword or to the serve path:
// src/interpreter/mod.rs:842
async fn read_binary(&self, handle_id: &str) -> Result<Vec<u8>, String> { ... }
// src/interpreter/mod.rs:869
async fn read_binary_n(&self, handle_id: &str, count: usize) -> Result<Vec<u8>, String> { ... }
-
The HTTP response body is a String. The response (and request) content is typed as String:
// src/interpreter/mod.rs:75 (WflHttpRequest)
pub body: String,
// src/interpreter/mod.rs:82 (WflHttpResponse)
pub content: String,
So even a correctly-read Vec<u8> can't be carried through respond to req with <bytes> without a lossy String conversion.
Good news — the outbound warp path already accepts bytes
The warp reply is already built from bytes, so only the WFL-facing plumbing needs to change, not the HTTP layer:
// src/interpreter/mod.rs:5199 (approx)
match reply_builder.body(content_bytes) { ... }
Reproduction
- Write a WFL web server that reads a
.ttf and responds with it:
listen on port 8080 as server
main loop:
wait for request comes in on server as req
open file at "public/assets/fonts/Alegreya-Variable.ttf" for reading as f
store data as read content from f
close file f
respond to req with data and content_type "font/ttf"
end loop
curl -s localhost:8080/ -o out.ttf and compare with the source file.
- Expected: byte-identical font. Actual: size/bytes differ (UTF-8 lossy replacement) and the font fails to load in a browser.
Proposed fix
Keep bytes end-to-end from read → respond → warp:
- Expose a binary read at the WFL level (e.g.
read binary content from f) backed by the existing read_binary (mod.rs:842), yielding a bytes-capable value.
- Allow
respond to req with <bytes> ... to carry those bytes into warp's existing .body(content_bytes) (mod.rs:5199) without routing through the String content field — e.g. add a bytes variant to WflHttpResponse (content: Bytes | String) so text responses stay unchanged and binary responses stay lossless.
- Bonus: a small built-in static-file/MIME helper so
.ttf/.woff2/.png/.ico/.svg serve correctly out of the box (extension → content type, binary when appropriate).
Backward compatibility
Text responses (respond to req with "...") and text read content must keep working exactly as-is — the change is additive (a new binary read form + a bytes-capable response variant), preserving the backward-compatibility invariant.
Workaround until fixed
Base64-embed binary assets as data: URIs inside a text CSS file (which WFL serves fine as UTF-8). Works, but bloats payloads and defeats normal static serving.
Summary
WFL's built-in web server cannot serve binary files (fonts, images, etc.) losslessly. Both the file-read path and the HTTP response body are
String/UTF-8-based, so any non-UTF-8 bytes are corrupted before they reach the client. This blocks natural static-asset serving — e.g. self-hosting a.ttffont or serving a.png/.icodirectly from a WFL web server.Impact / motivation
Building the WFL website in WFL (serving its own marketing site via
listen on port ...) requires serving a self-hosted Alegreya.ttf, a favicon, and potentially raster images. Today that's impossible without a workaround (base64data:URIs embedded in a text CSS file), which inflates payloads and isn't how anyone expects static serving to work.Root cause (two text-only chokepoints)
All references are in
src/interpreter/mod.rs.File read is text-only. The WFL
read contentpath usesread_to_string:A
.ttf/.pngis corrupted the moment it is loaded. Note that binary-capable readers already exist internally but aren't wired to a WFL keyword or to the serve path:The HTTP response body is a
String. The response (and request) content is typed asString:So even a correctly-read
Vec<u8>can't be carried throughrespond to req with <bytes>without a lossyStringconversion.Good news — the outbound warp path already accepts bytes
The warp reply is already built from bytes, so only the WFL-facing plumbing needs to change, not the HTTP layer:
Reproduction
.ttfand responds with it:curl -s localhost:8080/ -o out.ttfand compare with the source file.Proposed fix
Keep bytes end-to-end from read → respond → warp:
read binary content from f) backed by the existingread_binary(mod.rs:842), yielding a bytes-capable value.respond to req with <bytes> ...to carry those bytes into warp's existing.body(content_bytes)(mod.rs:5199) without routing through theStringcontentfield — e.g. add a bytes variant toWflHttpResponse(content: Bytes | String) so text responses stay unchanged and binary responses stay lossless..ttf/.woff2/.png/.ico/.svgserve correctly out of the box (extension → content type, binary when appropriate).Backward compatibility
Text responses (
respond to req with "...") and textread contentmust keep working exactly as-is — the change is additive (a new binary read form + a bytes-capable response variant), preserving the backward-compatibility invariant.Workaround until fixed
Base64-embed binary assets as
data:URIs inside a text CSS file (which WFL serves fine as UTF-8). Works, but bloats payloads and defeats normal static serving.