Agent Skills
› static-web-server/static-web-server
› rust-backend
rust-backend
GitHub提供Rust后端开发规范,涵盖SWS项目的代码编写、审查与重构。强制使用Clippy、Fmt和测试工具,禁止unsafe代码,规范错误处理与异步编程标准,确保代码质量与一致性。
Trigger Scenarios
编写或修改Rust源代码
审查涉及Rust源码的PR
重构模块或错误处理逻辑
Install
npx skills add static-web-server/static-web-server --skill rust-backend -g -y
SKILL.md
Frontmatter
{
"name": "rust-backend",
"description": "Write or review Rust backend code for the Static Web Server (SWS) project — crates, modules, functions, types, error handling, and async code"
}
Rust Backend Coding Standards
Load this skill when writing, reviewing, or refactoring Rust code in the SWS project.
When to load: editing any file under src/, adding a new module, changing error handling, touching async code, or reviewing a PR that modifies Rust source.
Mandatory Tools
Always use the following commands to maintain code quality and consistency:
Linting
cargo clippy --features all -- -D warningscargo clippy --features all --tests -- -D warnings
Formatting
cargo fmt --all -- --check tests/*.rs
Testing
cargo test -v --features allcargo test -v --no-default-features
Cargo docs lint
cargo +nightly rustdoc --lib -Zrustdoc-map --features all \
--config "build.rustflags=[\"--cfg\", \"tokio_unstable\"]" \
-Zhost-config -Ztarget-applies-to-host \
--config "host.rustflags=[\"--cfg\", \"tokio_unstable\"]" \
--config "build.rustdocflags=[\"--cfg\", \"docsrs\", \"--cfg\", \"docsrs\", \"--cfg\", \"tokio_unstable\", \"-Z\", \"unstable-options\", \"--emit=invocation-specific\", \"--cap-lints\", \"warn\", \"--extern-html-root-takes-precedence\"]" \
-Zunstable-options -- --document-private-items
Code Quality
- All clippy commands in Mandatory Tools must pass with zero warnings before committing
unsafeis forbidden at the crate level: SWS uses#![forbid(unsafe_code)]. Consider refactoring to avoidunsafeentirely- Prefer
&Pathover&PathBufin function parameters. Acceptimpl AsRef<Path>for public APIs - Use
#[must_use]on pure functions whose return value should not be silently discarded - Derive common traits explicitly:
Debug,Clone,PartialEq,Eqon all public types unless there is a reason not to - No commented-out code: Delete it. Git history preserves it
Error Handling
- Use the crate's
Result<T>andErrortypes: Defined insrc/error.rs. All fallible functions returnResult<T>orResult<T, StatusCode>for HTTP-level errors - Use
anyhow::Contextfor wrapping:fallible_op().with_context(|| "failed to parse config")? - No
unwrap()orexpect()in production code: Use?or match. Allowexpectonly for values guaranteed by prior validation (e.g., a regex that is known to compile, a lock that should never be poisoned). Add an inline comment explaining the invariant - Log errors at the boundary: Module code returns errors. The HTTP handler (
handler.rs) logs them and converts to HTTP status codes - Distinguish HTTP status codes from internal errors:
StatusCode(hyper) for HTTP semantics;Error(anyhow) for internal failures. Functions useResult<T, StatusCode>when the only possible failures are HTTP-level
Async Code
- Use
tokioas the runtime: All async code targetstokio(multi-threaded,rt-multi-threadfeature) - No
block_onin async context: Never calltokio::runtime::Handle::block_oninside an async function - Prefer
spawn_blockingfor CPU-bound work: Offload file hashing, compression dictionary building, etc. - Use
hyperas the HTTP framework: SWS is built onhyperv1 withhttp-body-util.src/service.rsdefinesRouterServiceandRequestService, which implementhyper::service::Serviceand delegate toRequestHandler::handle()
HTTP & Request Handling
- Request pipeline ordering:
handler.rsorchestrates the request flow in a fixed order with three phases:- Pre-processing (may short-circuit with a response): method check → health/metrics → CORS → basic auth → maintenance mode → redirects → rewrites → virtual hosts → markdown negotiation
- Core: static file resolution and serving
- Post-processing (additive, runs on every response): fallback page → CORS headers → text charset → static compression → dynamic compression → cache-control → security headers → custom headers
- Post-processing is additive: Each post-processing step appends or modifies headers. No step removes headers set by a previous step unless explicitly documented
- Response body type:
crate::body::Bodyis a type alias forBoxBody<Bytes, std::io::Error>(defined insrc/body.rs). Use the constructorscrate::body::empty(),crate::body::full(impl Into<Bytes>), orcrate::body::stream<S>(s) - Static file serving is the core:
static_files.rshandles path resolution, index files, directory listing, pre-compressed variants, and byte-range requests
Settings & Configuration
- Three equivalent channels: CLI arguments (
clap), environment variables, and TOML config file. Defined insrc/settings/ - Precedence (lowest to highest): compiled defaults → TOML config file → environment variables → CLI arguments. Runtime validation runs after merging
- Feature-gated settings: Settings that require Cargo features (e.g.,
compression,directory-listing) are conditionally compiled with#[cfg(feature = "...")] - Validation at startup, not per-request: Canonicalize paths, validate TLS certificates, parse index files once at startup in
server/opts.rs
File System
- Canonicalize paths once at startup: The root directory is canonicalized in
server/opts.rs. Per-request path resolution reuses this canonical base - Path traversal prevention:
sanitize_path()(insrc/fs/path.rs) strips.., root prefixes, and other traversal components.resolve_and_contain()(insrc/static_files/security.rs) verifies the resolved path stays within the base directory - Symlink policy: When
--follow-symlinksis disabled (default),enforce_symlink_policy()(insrc/static_files/security.rs) walks each path component checking for symlinks viasymlink_metadata(). This is a syscall per component — check cheaper guards (hidden files) first - File metadata operations:
try_metadata()andtry_metadata_with_html_suffix()(insrc/fs/meta.rs) encapsulate filesystem access with proper error mapping to HTTP status codes
Patterns to Avoid
- No
Stringas an error type: Use structured errors orStatusCode - No
Box<dyn Error>: Useanyhow::Error - No global mutable state: No
static mutorlazy_static!withMutex. SWS usesArc<RequestHandlerOpts>for shared read-only config - No deep nesting: Extract nested conditionals into named functions or match guards
- No per-request canonicalize or alloc when avoidable: Cache canonical paths, reuse buffers, avoid
clone()in the hot path
Version History
- 21dc11b Current 2026-08-20 17:42


