rhttp/AGENTS.md

6.2 KiB

AGENTS.md - Rust HTTP Server Project Guide

This file provides essential information for agentic coding agents working on the rhttpd project.

Project Overview

rhttpd is a high-performance, configurable HTTP server written in Rust that supports:

  • Multi-site hosting on a single port
  • Multiple proxy types (reverse, forward, TCP)
  • JavaScript dynamic configuration
  • Static file serving with MIME type detection

Build, Test, and Development Commands

Core Commands

# Build the project
cargo build

# Build with optimizations
cargo build --release

# Run the server
cargo run

# Run tests
cargo test

# Run a single test (replace test_name with actual test)
cargo test test_name

# Run tests with output
cargo test -- --nocapture

# Check code without building
cargo check

# Format code
cargo fmt

# Run clippy lints
cargo clippy

# Run clippy with all targets and features
cargo clippy --all-targets --all-features

# Generate documentation
cargo doc --open

# Clean build artifacts
cargo clean

Code Style Guidelines

General Rust Conventions

  • Use rustfmt for formatting (run cargo fmt before commits)
  • Follow Rust 2024 edition standards
  • Use cargo clippy to catch common issues and improve code

Imports and Dependencies

  • Group imports in the following order:
    1. Standard library imports (std::*)
    2. Third-party crate imports
    3. Local module imports (crate::*)
  • Use explicit imports rather than glob imports where possible
  • Prefer use crate::module::Item; over use super::module::Item;

Naming Conventions

  • Functions and variables: snake_case
  • Types and structs: PascalCase
  • Constants: SCREAMING_SNAKE_CASE
  • Modules: snake_case
  • File names: snake_case.rs

Error Handling

  • Use Result<T, E> for functions that can fail
  • Create custom error types using thiserror or anyhow when needed
  • Use ? operator for error propagation
  • Handle errors gracefully with proper logging
  • Avoid using unwrap() or expect() in production code

Async/Await Patterns

  • Use async/await for asynchronous operations
  • Prefer tokio runtime for async operations
  • Use .await instead of blocking calls in async contexts
  • Handle async errors with Result types

Struct and Enum Design

  • Use #[derive(Debug, Clone, PartialEq, Eq)] where appropriate
  • Implement Default for structs with sensible defaults
  • Use serde derives for configuration structs:
    #[derive(Debug, Clone, Serialize, Deserialize)]
    
  • Use builder pattern for complex configuration

Memory Management

  • Use Arc<RwLock<T>> for shared configuration that needs concurrent access
  • Use Arc<Mutex<T>> when exclusive access is needed
  • Prefer borrowing over cloning when possible
  • Use Cow<str> for string data that might be borrowed or owned

Module Organization

  • Keep modules focused and cohesive
  • Use mod.rs for directory modules
  • Declare public APIs with pub keyword
  • Use pub(crate) for internal APIs shared across modules

Testing Guidelines

  • Write unit tests for all public functions
  • Use #[cfg(test)] for test modules
  • Use integration tests in tests/ directory for end-to-end testing
  • Mock external dependencies in tests
  • Use tokio::test for async tests

Documentation

  • Document all public APIs with /// doc comments
  • Use #[doc] attributes for module-level documentation
  • Include examples in doc comments where helpful
  • Use cargo doc to verify documentation builds correctly

Performance Considerations

  • Use Vec<T> for collections when size is known
  • Use String for owned string data
  • Avoid unnecessary allocations
  • Use &str for string references when possible
  • Profile with cargo flamegraph for performance optimization

Security Best Practices

  • Validate all external inputs
  • Use type-safe configurations
  • Avoid unsafe code unless absolutely necessary
  • Sanitize file paths to prevent directory traversal
  • Implement rate limiting for proxy endpoints

Project Structure

rhttpd/
├── src/
│   ├── main.rs          # Application entry point
│   ├── lib.rs           # Library root (if applicable)
│   ├── server/          # Server implementation
│   ├── config/          # Configuration management
│   ├── proxy/           # Proxy implementations
│   └── js_engine/       # JavaScript integration
├── tests/               # Integration tests
├── doc/                 # Documentation and requirements
├── Cargo.toml           # Project configuration
└── AGENTS.md           # This file

Key Dependencies (as specified in requirements)

Core Runtime

  • tokio - Async runtime
  • hyper or axum - HTTP server framework
  • tower - Middleware and service abstractions

Configuration

  • serde - Serialization/deserialization
  • serde_json - JSON support
  • toml - TOML configuration support

Static Files

  • tower-http - HTTP service utilities
  • mime_guess - MIME type detection

Proxy Support

  • reqwest - HTTP client for reverse proxy
  • tokio-util - Utilities for async I/O
  • tokio-native-tls - TLS support

JavaScript Engine

  • Choose one: deno_core, rquickjs, or boa_engine

Development Workflow

  1. Run cargo check to verify code compiles
  2. Run cargo clippy to catch issues
  3. Run cargo fmt to format code
  4. Run cargo test to verify tests pass
  5. Commit changes with descriptive messages

Testing Strategy

  • Unit tests for individual components
  • Integration tests for end-to-end functionality
  • Performance tests for proxy operations
  • Configuration validation tests

Common Patterns

Configuration Loading

#[derive(Debug, Deserialize)]
struct ServerConfig {
    port: u16,
    sites: HashMap<String, SiteConfig>,
}

Error Types

#[derive(Debug, thiserror::Error)]
enum ServerError {
    #[error("Configuration error: {0}")]
    Config(#[from] ConfigError),
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
}

Async Service Pattern

#[async_trait]
trait ProxyService {
    async fn handle_request(&self, req: Request<Body>) -> Result<Response<Body>, ServerError>;
}

Remember to run cargo fmt and cargo clippy before committing changes!