# Overview This project is a very simple gemini server which only serves static files, nothing else. It is meant to be generic so other people can use it. # Build/Test/Lint Commands ## Core Commands - `cargo build` - Build the project - `cargo build --release` - Build optimized release version - `cargo run` - Run the server with default config - `cargo test` - Run all unit tests - `cargo test ` - Run a specific test - `cargo test ::tests` - Run tests in a specific module - `cargo clippy` - Run linter checks - `cargo fmt` - Format code according to Rust standards - `cargo check` - Quick compile check without building ## Common Test Patterns - `cargo test config::tests` - Run config module tests - `cargo test request::tests` - Run request handling tests - `cargo test -- --nocapture` - Show println output in tests # Code Style Guidelines ## Imports - Group imports: std libs first, then external crates, then local modules - Use `use crate::module::function` for internal imports - Prefer specific imports over `use std::prelude::*` - Keep imports at module level, not inside functions ## Code Structure - Use `#[tokio::main]` for async main function - Keep functions small and focused (single responsibility) - Use `const` for configuration values that don't change - Error handling with `Result` and `?` operator - Use `tracing` for logging, not `println!` in production code ## Naming Conventions - `PascalCase` for types, structs, enums - `snake_case` for functions, variables, modules - `SCREAMING_SNAKE_CASE` for constants - Use descriptive names that indicate purpose ## Error Handling - Use `io::Result<()>` for I/O operations - Convert errors to appropriate types with `map_err` when needed - Use `unwrap()` only in tests and main() for unrecoverable errors - Use `expect()` with meaningful messages for debugging - Return early with `Err()` for validation failures ## Security Requirements - **Critical**: Always validate file paths with `path_security::validate_path` - Never construct paths from user input without validation - Use timeouts for network operations (`tokio::time::timeout`) - Limit request sizes (see `MAX_REQUEST_SIZE` constant) - Validate TLS certificates properly - Never expose directory listings ## Testing Guidelines - Use `tempfile::TempDir` for temporary directories in tests - Test both success and error paths - Use `#[cfg(test)]` for test modules - Create temporary test files in `tmp/` directory - Test security boundaries (path traversal, invalid inputs) - Use `assert_eq!` and `assert!` for validations ## Async Patterns - Use `.await` on async calls - Prefer `tokio::fs` over `std::fs` in async contexts - Handle timeouts for network operations - Use `Arc` for shared data across tasks ## Gemini Protocol Specific - Response format: "STATUS META\r\n" - Status 20: Success (follow with MIME type) - Status 51: Not found - Status 59: Bad request - Default MIME: "text/gemini" for .gmi files - Default file: "index.gmi" for directory requests ## Configuration - TOML config files with `serde::Deserialize` - CLI args override config file values - Required fields: root, cert, key, host - Optional: port, log_level # Development Notes - Generate self-signed certificates for local testing in `tmp/` directory - Use CN=localhost for development - Fix every compiler warning before committing any code - Create temporary files in the tmp/ directory for your tests like .gem files or images, etc., so they are gitignored - Use `path-security` crate for path validation - Default port: 1965 (standard Gemini port) - Default host: 0.0.0.0 for listening - Log level defaults to "info"