Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

214 Commits

Folders and files

Repository files navigation

mazda-browser

A real browser with memory as a first-class feature: a trusted shell process plus a sandboxed renderer process. The engine — HTML, CSS, JavaScript, DOM, layout, and paint — is written from scratch in Rust.

Phase S proved the process split is worth its cost (see SPIKE.md). P1 is in place: a real IPC protocol, double-buffered shared-memory frames, a renderer supervisor, tabs, and snapshot restore. P2 is in place too: the renderer runs in an OS sandbox (AppContainer + Job Object on Windows, no_new_privs + seccomp on Linux). P3 is in place: <video>/<audio> play through Media Foundation + WASAPI, decoded by a pure-Rust media crate, with DRM refused before any decoder is created. P4 has started: <a download> streams to disk with a progress panel and lands in the user's Downloads folder, <input type=file> posts files as multipart/form-data through the native picker, Ctrl+F finds text in the page with scroll-to-match highlights, Ctrl+= / Ctrl+- zoom the page, the printer button (or Ctrl+P) saves the page as a PDF in Downloads, and Ctrl+D / Ctrl+H drive bookmarks and the visit log.

Workspace

crates/engine     HTML/CSS/JS/DOM/layout/paint (copied from mazda-browser-rust)
crates/ipc        P1 protocol: stdio lines + double-buffered mmap frames
crates/media      P3 playback: MP4 header parse, Media Foundation, WASAPI
crates/media-probe media self-test (plain + sandboxed decode/audio/DRM)
crates/renderer   headless renderer process
crates/sandbox    OS containment for the renderer + `sandbox-probe` self-test
crates/shell      trusted shell (eframe/egui), owns the window and input
tools/            memory, reload-soak, tab and sandbox harnesses

The engine still carries engine::app — the old single-process shell and paint pipeline — because run_headless reuses that pipeline unchanged.

Build

cargo build --release --workspace

If the crate mirror is unreachable (the environment uses rsproxy), add --offline; the dependency cache is already populated.

Run

.\target\release\shell.exe https://example.com
.\target\release\shell.exe --tabs "https://www.google.com,https://github.com" --active 1

The shell has no OS titlebar: the titlebar, tab strip, address bar and window buttons are drawn in egui. Tabs are Chrome-like (hover, close, middle-click, drag-to-move, +), and the window controls minimize / maximize / close.

Keyboard: Ctrl+T new tab, Ctrl+W close, Ctrl+R reload, Ctrl+L focus address, Ctrl+Tab / Ctrl+Shift+Tab cycle, Ctrl+1…9 select.

The shell (trusted, parent) spawns renderer.exe inside the OS sandbox, forwards scroll/click over stdin, and blits the memory-mapped frame the renderer produces. Background tabs are metadata only (URL, label, scroll), so the single renderer holds just the active page; switching tabs restores from the tab's snapshot.

Sandbox behaviour (P2):

  • Windows: AppContainer with only internetClient; a Job Object allows one process, blocks UI/clipboard/desktop access, and kills the renderer with the shell. There is no memory cap: the renderer is kept lean by what it allocates. %TMP%/%LOCALAPPDATA% point at a directory granted to the package SID, so the frame file and cache work while the real user profile stays unreadable.
  • Linux: no_new_privs and a seccomp filter that refuses execve/execveat. Landlock/net-namespace filesystem isolation is the next increment; the code is compile-checked but not yet run on Linux here.
  • MAZDA_SANDBOX=off is a debugging escape hatch (local test servers, profilers); the normal path never uses it.

Network (P63–P67): gzip and brotli request codings, an on-disk cache that honours Cache-Control and revalidates with If-None-Match. HTTP/2 is available with MAZDA_HTTP2=1: it shortens the multi-request phases, but a single warm document is measurably slower over it, so HTTP/1.1 stays the default until that is fixed (SPIKE P67/P68).

Media (P3): <video> is a replaced element — layout sizes it from width/height, the worker fetches the file, parses the MP4 header (DRM and unsupported containers are refused before a decoder exists), and the renderer decodes through Media Foundation into the page's frame. Audio goes to WASAPI shared mode. Only autoplay muted starts by itself; any other video opens on the first click, and a click inside the video toggles play/pause. The whole playback path is in crates/media; on Linux it is a stub that reports Unsupported. MAZDA_NO_MEDIA=1 disables probing for an A/B memory check.

Downloads (P4): <a href download> saves instead of navigating. The renderer streams the response in 64 KB chunks into its own temp dir (progress every 150 ms, no body in RAM); the trusted shell then moves the finished file into %USERPROFILE%\Downloads (name (n) dedupe) because the sandbox keeps the profile unwritable. Names from the download attribute are sanitized so a page cannot pick a path. The toolbar's download button opens a panel with live progress bars and clickable saved files; the status bar shows the active transfer.

Uploads (P4): <input type=file> shows "Choose File", then the picked name. The renderer only emits pick-file <node>; the trusted shell opens the Win32 Open dialog, copies the file into the renderer's sandbox temp dir and answers file-chosen. A POST with a pick (or enctype="multipart/form-data") is built as a boundary'd multipart body with Content-Length, text fields first, then the file. Scripts never see the path or the bytes.

Find (P4): Ctrl+F opens a bar; typing sends find <query> and the renderer scans the laid-out text runs itself, replying find-result <active> <total>. Enter (or Shift+Enter) sends find-step ±1 and the reply includes scroll-to <y>, which the shell adopts for the active tab. Highlights are blended over the finished frame in the renderer (yellow for matches, orange for the active one), so closing the bar is just another repaint.

Zoom (P4): Ctrl+= / Ctrl+- step 25%…500% (Ctrl+0 resets), shown in the status bar. The renderer lays the page out at physical / zoom CSS pixels and scales the painted frame back up, so the page reflows like a narrower window; clicks and wheel deltas are converted at the boundary.

The stdin control channel also accepts find, find-step, find-close and zoom in|out|reset, so the bar, highlights and zoom badge can be exercised without taking the foreground from another app.

Print (P4): the toolbar printer button (or Ctrl+P) sends print. The renderer paints the whole document in A4 slices at CSS resolution, scales each slice into a 794x1123 page bitmap with a half-inch margin, zlib-compresses the RGB planes and assembles a PDF 1.4 file with an xref table in its temp dir. The trusted shell moves the finished file into %USERPROFILE%\Downloads as <host>.pdf with the same dedupe and lists it in the Downloads panel. Pages are bitmaps, so text is not selectable, and a slice boundary cuts at a fixed height rather than at paragraph breaks.

History and bookmarks (P4): every committed load appends one tab-separated line to %LOCALAPPDATA%\mazda-browser\history.tsv (reloads collapse to one visit, newest 5,000 kept); Ctrl+D or the toolbar star adds/removes bookmarks.tsv. The clock button or Ctrl+H opens the library panel: bookmarks on top with a remove button, then the visit log with relative times. Clicking any row navigates the active tab; history has a Clear button. Both stores are read once at startup and written from the trusted shell only; a failed write never breaks browsing.

Self-test (decode, audio endpoint and DRM rejection, plain and through the real sandbox):

cargo run --release -p media-probe -- --file "$env:TEMP\mazda-test.mp4"

Single-process reference (the pre-split app):

.\target\release\mazda.exe https://example.com

Measure

.\tools\mem-harness.ps1 -Url https://example.com
.\tools\measure-sites.ps1            # Google, GitHub, YouTube: old vs split + scroll latency
.\tools\measure-tabs.ps1             # 10 tabs, one renderer, <= 300 MB (P1 gate)
.\tools\reload-soak.ps1 -Cycles 100  # 100 reloads, RSS plateau / live-heap leak gate
.\tools\crash-check.ps1              # kill the renderer -> supervisor restarts + restores
.\tools\sandbox-check.ps1            # home unreadable, no child, network (P2 gate)
.\tools\screenshot-shell.ps1 -Url https://example.com   # capture the real window
.\tools\ui-smoke.ps1                 # click print/star/clock, assert stores + screenshots
.\target\release\js-bench.exe --iterations 10 --warmup 3   # JS engine speed (P5)
.\target\release\test262.exe --dir "$env:TEMP\test262\test\language" --harness "$env:TEMP\test262\harness"
                                     # JS engine correctness, non-strict subset (P5)

The test262 runner needs a sparse checkout of the suite; see SPIKE.md ("JavaScript performance baseline") for the clone command and the current counts.

Reference sites: Google, GitHub, YouTube — heavy, real-world pages used for memory and latency work; example.com / Wikipedia stay as the light sanity set.

Headless one-frame render (no window; useful for CI and profiling):

.\target\release\renderer.exe --once https://example.com

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages