Serving pages

How the viewer answers a request: the URL names a file in the served folder, the path is checked to stay inside it, and the file is served as what it is — a document, a page in its document's frame, or bytes. It also covers the built-in assets, the address devpage listens on and what it logs. It is a mechanism page under the viewer, for someone about to change how requests are served; which document a file belongs to and rendering a page go one level deeper.

flowchart LR
  req["GET /path"] --> route{"Route"}
  route -->|"/"| entry["The entry document"]
  route -->|"/__devpage/…"| own["devpage's own:<br/>events, comments,<br/>widgets, assets"]
  route -->|"Watch, *.design.png"| designs["Designs:<br/>watch stream, PNG"]
  route -->|"anything else"| file["A file in the<br/>served folder"]
  click route href "#routes" "Routes"
  click entry href "#routes" "Routes"
  click own href "#routes" "Routes"
  click designs href "../design-engine/README.md#in-the-server" "The design engine in the server"
  click file href "#the-url-is-the-file-path" "The URL is the file path"

Routes

Route Response
/ 307 Temporary Redirect to the entry document as its file says now — a site's root page, or a doc's or deck's document file (or the Markdown file devpage was given); while the entry's file is invalid, the page saying why
/__devpage/events the live-update event stream — see Live updates
/__devpage/comments… the comment store's requests — see Comments; 404 with comments off
/__devpage/system-widgets/{name} a system widget, compiled — see Widgets
/__devpage/widgets/{*path} a project widget or helper in the served folder, compiled — see Widgets
/__devpage/{asset} one of the built-in assets
/devpage.design.v1.Designs/Watch a page's watch stream over every design it shows, as gRPC-Web; it is the service's only method, and the only path under /devpage.design.v1.Designs/ that answers — see Design engine
/{*path}.design.png the design at path painted as a PNG — see Looking at a design as a PNG
/{*path}.yml/{n}.png slide n of the deck at path.yml (or .yaml) as a 1920 × 1080 PNG, drawn by chrome-headless-shell; 404 with the reason when the file isn't a deck or has no slide n — see A slide as an image
/{*path} the file at path in the served folder

A query of ?print renders a doc's or deck's document file in print mode, the page devpage pdf has Chrome print (Printing to PDF). A site is never printed, so on a Markdown file ?print always renders it as a doc of one chapter in print mode, even when the file is a page of a site — which is how devpage pdf prints one Markdown file.

The URL is the file path

A URL path is joined to the served folder — /docs/boxes/README.md is <served folder>/docs/boxes/README.md — so relative links between files work as written. Nothing is precomputed: every request reads its files from disk.

Path safety. Every path takes the same three checks (the rule):

flowchart LR
  path["/path"] --> join["Joined to the served folder,<br/>canonicalized"]
  join --> inside{"Still inside the<br/>served folder?"}
  inside -->|"yes"| file{"A regular file?"}
  inside -->|"no"| nf["404"]
  file -->|"yes"| ok["Served"]
  file -->|"no"| nf
  click ok href "#what-a-file-is-served-as" "What a file is served as"

Canonicalizing resolves .. and symbolic links, and fails if the file doesn't exist. Anything that fails — a path escaping with .., a symbolic link pointing outside, a missing file, a folder — gets 404 with the body <path> is not part of the served folder. A file that exists but can't be read gets 500 with the error's text.

What a file is served as

A file that passes the checks is one of four things:

The file Is served as
A document file — YAML with kind: site, doc or slides the document, as its kind
A Markdown file a page, in the frame of the document it belongs to
A .design file the canvas page
Anything else its bytes, as they are — see Other files

The canvas page

A .design file is shown on the canvas page: a frame holding a <canvas>, the light/dark switch in the corner with the head script that sets the theme before the page paints, and the design script, which draws it as the design engine describes and runs the switch. It belongs to no site and has no sidebar, navbar or comments.

Which document a file belongs to

What makes a file a document file, which site a page belongs to and the index that answers it are on Which document a file belongs to.

Rendering a Markdown file

How a page is turned into HTML and put in its frame is on Rendering a page.

Other files

Any other file is read as bytes and returned with a Content-Type guessed from its extension (mime_guess), or application/octet-stream when the extension is unknown.

Built-in assets

The page's own files are compiled into the binary with include_str!, and the design engine's module with include_bytes!:

URL Source Content type
/__devpage/style.css assets/style.css text/css
/__devpage/devpage.js assets/devpage.js text/javascript
/__devpage/pele.js assets/vendor/pele.js text/javascript
/__devpage/react.js assets/vendor/react.js text/javascript
/__devpage/design.js assets/design.js, the design script: the canvas page's, and loaded by the page script on a page that embeds a design text/javascript
/__devpage/design-engine.js assets/vendor/design-engine.js, the design engine's vendored bindings text/javascript
/__devpage/design-engine.wasm assets/vendor/design-engine.wasm, the design engine's vendored WebAssembly module application/wasm

They are sent with Cache-Control: no-cache; any other name under /__devpage/ is 404. Changing an asset means rebuilding devpage.

The address

devpage listens on 127.0.0.1 — the local machine only — unless --host names another address, which makes it deployed. It takes the first free port from 3030 up, or exactly the port --port names. It prints <title> → http://localhost:<port> (with the host in place of localhost when one is given) on standard output.

Request logging

The server devpage runs has a middleware that logs every request to standard error, as <method> <path> → <status> in <ms> ms, for example GET /README.md → 200 in 0.7 ms. The time is until the response starts, so an event stream logs once, when it opens.

The exact document file fields and command line are in the configuration reference.

Topics