CtrlK
BlogDocsLog inGet started
Tessl Logo

design

Design or review software architecture, API contracts, data models, and module boundaries for the Static Web Server (SWS) project

68

Quality

83%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

SKILL.md
Quality
Evals
Security

Software Design

Load this skill when designing new features, refactoring modules, defining configuration interfaces, or reviewing architecture decisions for SWS.

When to load: a new feature spans more than one module, a config option is being added or changed, a new step is needed in the request pipeline, a Cargo feature flag is being introduced, or an architecture decision needs review.

Principles

  • Static file server first: Every design decision starts from "how does this improve serving static files securely and efficiently?"
  • Small, static binary: Release binary is ~4MB (uncompressed, musl). New dependencies must not increase it by more than 100KB unless they replace existing functionality or gate behind a feature flag
  • Feature-gate optional functionality: Every non-core feature lives behind a Cargo feature flag AND a #[cfg(feature = "...")] gate. Users compile only what they need
  • Three channels, one source of truth: CLI args, env vars, and TOML config all map to the same General struct. Precedence (highest→lowest): CLI args → env vars → TOML config → compiled defaults
  • Pre-compute at startup, serve at speed: Resolve, canonicalize, and validate everything possible at server startup. The request hot path is allocation-light and syscall-minimal

Module Architecture

Core Pipeline

settings/     →  server/opts.rs  →  handler.rs  →  static_files.rs
  (parse)         (init)              (pipeline)      (serve file)

Module Responsibilities

ModuleResponsibility
settings/Parse CLI/env/TOML, merge, validate
server/Bind listener, start HTTP/1 or HTTP/2+TLS, graceful shutdown
handler.rsOrchestrate request pre/post processing pipeline
static_files.rsPath resolution, index files, directory listing, byte-range, pre-compressed variants
compression.rsOn-the-fly gzip/deflate/brotli/zstd compression
compression_static.rsServe pre-compressed .br/.gz/.zst files from disk
security_headers.rsAppend HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy
control_headers.rsAppend Cache-Control based on file extension
cors.rsCORS pre-flight and header injection
fs/File system utilities: path sanitization (fs/path.rs), metadata (fs/meta.rs), streaming (fs/stream.rs)
exts/HTTP extensions: Accept-Encoding parsing, content-coding negotiation (exts/http.rs, exts/headers/, exts/mime.rs)
directory_listing/HTML/JSON directory index generation
body.rsUnified response body type — pub type Body = BoxBody<Bytes, io::Error> (alias, not a struct)
service.rsHyper Service bridge: RouterServiceRequestServiceRequestHandler

Feature Flags as Module Boundaries

Every optional feature is both a Cargo feature AND a #[cfg(feature = "...")] gate:

  • compressioncompression.rs + compression_static.rs (meta-feature: compression-brotli/-deflate/-gzip/-zstd)
  • directory-listingdirectory_listing/
  • http2server/http2.rs (requires tls)
  • tls (base plumbing, no crypto provider) → tls.rs + server/http1_tls.rs. tls-ring (default) or tls-fips selects the provider
  • basic-authbasic_auth.rs
  • fallback-pagefallback_page.rs
  • metricsmetrics.rs. experimental adds tokio-metrics-collector and requires RUSTFLAGS="--cfg tokio_unstable"
  • mem-cachemem_cache/ (LFU admission + LRU eviction via mini-moka, CompactString keys)

Request Pipeline Design

The handler's handle() method is the single entry point. The pipeline is linear with three phases:

#StepPhaseCan Short-Circuit?
1Method checkPreYes (405)
2Health/metricsPreYes
3CORS validationPreYes (preflight 204)
4Basic authPreYes (401)
5Maintenance modePreYes (503)
6RedirectsPreYes (301/302)
7RewritesPreNo (modifies URI, continues)
8Virtual hostsPreNo (selects config, continues)
9Markdown negotiationPreNo (sets content-type hint, continues)
10static_files::handle()CoreNo (always produces a response)
11Fallback pagePostNo
12CORS headersPostNo
13Markdown content-typePostNo
14Text charsetPostNo
15Static compression varyPostNo
16Dynamic compressionPostNo
17Cache-ControlPostNo
18Security headersPostNo
19Custom headersPostNo

When adding a new step, specify its position relative to an existing step by number.

Design Rules for the Pipeline

  1. Pre-processing steps return early when they handle the request (CORS preflight, redirect, health check)
  2. Post-processing steps are additive — they append or modify headers. No step removes headers set by prior steps
  3. Order matters: static compression runs before dynamic compression (pre-compressed files avoid CPU cost), cache-control runs before security headers (custom headers — applied last — take final precedence)

Configuration Design

The General struct

CLI arguments, environment variables, and TOML keys all resolve to the same General struct:

--port 8787  ↔  SERVER_PORT=8787  ↔  [general] port = 8787

TOML Config File

Advanced features (custom headers, rewrites, redirects, virtual hosts) are TOML-only. They live in a separate Advanced struct and require glob/regex patterns.

Default Values Philosophy

  • Secure by default: Hidden files ignored, symlinks disabled, security headers enabled when TLS is active
  • Performant by default: Compression, cache-control, and HTTP/2 are default-on Cargo features (opt-out via --no-default-features). Disable them to reduce binary size if not needed
  • Conservative where it matters: Grace period at 0 (explicit opt-in), directory listing off, CORS off

File Serving Design

Index File Resolution

  1. Request for / or /dir/ → directory detected via metadata
  2. Try each index file in the user-configured order (default: ["index.html", "index.htm"])
  3. For each index candidate: check pre-compressed variant, then regular file, then .html suffix fallback
  4. If no index found → directory listing (if enabled) or 404

Pre-compressed Variant Priority

Static (on-disk) compression is tried before dynamic (on-the-fly). The client's Accept-Encoding header determines variant selection. SWS honors quality values.

Byte-Range Serving

static_files.rs supports Range: bytes= for partial content delivery. Multi-range responses use multipart/byteranges.

Review Checklist

  • Is the new code behind an appropriate feature flag if optional?
  • Does the request pipeline order make sense (pre → core → post)?
  • Are paths canonicalized once, not per-request?
  • Can every public function be tested with the existing fixture infrastructure?
  • Are error states mapped to appropriate HTTP status codes?
  • Does the config change work across all three channels (CLI, env, TOML)?
Repository
static-web-server/static-web-server
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.