static

package
v1.19.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2026 License: MIT Imports: 37 Imported by: 0

README

Static File Server

Go Version

High-performance, security-focused static file server for Go with enterprise-grade features including WAF/IDS/EDR integration, rate limiting, path traversal protection, and advanced HTTP caching.


Table of Contents


Overview

The static package provides a production-ready static file server built on top of Go's embed.FS with comprehensive security features designed for modern web applications. It seamlessly integrates with the Gin web framework and provides enterprise-grade security monitoring through WAF/IDS/EDR webhook integration.

Design Philosophy
  1. Security First - Multiple layers of protection against common web attacks
  2. Zero Mutex - Lock-free concurrency using atomic operations for maximum performance
  3. Observable - Built-in security event streaming to SIEM systems
  4. Production Ready - Battle-tested with 82.6% test coverage and zero race conditions
  5. Developer Friendly - Simple API with sensible defaults

Key Features

Core Features
  • Embedded Filesystem - Serve files from Go's embed.FS
  • Gin Integration - Seamless integration with Gin web framework
  • Multiple Base Paths - Support for multiple embedded directories
  • Index Files - Automatic index file resolution for directories
  • Download Mode - Force download with Content-Disposition header
  • URL Redirects - HTTP 301 permanent redirects
  • Custom Handlers - Override default behavior for specific routes
Security Features
1. Path Security
  • Path Traversal Protection - Prevents ../ attacks
  • Null Byte Injection Prevention - Blocks null byte attacks
  • Dot File Blocking - Protects .env, .git, .htaccess
  • Max Path Depth - Limits directory traversal depth
  • Pattern Blocking - Blocks configurable path patterns
2. Rate Limiting
  • IP-based Limiting - Tracks unique files per IP
  • Sliding Window - Accurate rate calculation
  • Whitelist Support - Bypass for trusted IPs
  • Automatic Cleanup - Prevents memory leaks
  • Standard Headers - X-RateLimit-*, Retry-After
3. HTTP Security Headers
  • ETag Support - Efficient cache validation
  • Cache-Control - Fine-grained cache control
  • Content-Type Validation - MIME type filtering
  • Custom MIME Types - Override default detection
  • Expires Headers - HTTP/1.0 compatibility
4. Suspicious Access Detection
  • Pattern Recognition - Detects common attack patterns
  • Backup File Scanning - Identifies .bak, .old attempts
  • Config File Scanning - Detects config.php attempts
  • Admin Panel Scanning - Identifies /admin probes
  • Path Manipulation - Detects double slashes, backslashes
5. WAF/IDS/EDR Integration
  • Webhook Support - Real-time event streaming
  • CEF Format - Common Event Format for SIEM systems
  • Batch Processing - Efficient bulk event sending
  • Go Callbacks - Programmatic event handling
  • Async Processing - Non-blocking event delivery
  • Severity Filtering - Configurable event levels

Installation

go get github.com/nabbar/golib/static

Architecture

Request Flow
HTTP Request
     │
     ├──> [Rate Limiter]
     │         │
     │         ├──> Limit Exceeded? ──> 429 Too Many Requests
     │         └──> OK
     │
     ├──> [Path Security Validator]
     │         │
     │         ├──> Path Traversal? ──> 403 Forbidden + Event
     │         ├──> Dot File Access? ──> 403 Forbidden + Event
     │         ├──> Blocked Pattern? ──> 403 Forbidden + Event
     │         └──> OK
     │
     ├──> [Redirect Handler]
     │         │
     │         └──> Redirect? ──> 301 Permanent Redirect
     │
     ├──> [Custom Handler]
     │         │
     │         └──> Custom? ──> Execute Custom Handler
     │
     ├──> [Index File Resolution]
     │         │
     │         └──> Directory? ──> Serve Index File
     │
     ├──> [File Lookup]
     │         │
     │         ├──> Not Found? ──> 404 Not Found
     │         └──> Found
     │
     ├──> [MIME Type Validation]
     │         │
     │         ├──> Denied Type? ──> 403 Forbidden + Event
     │         └──> OK
     │
     ├──> [ETag Validation]
     │         │
     │         └──> Match? ──> 304 Not Modified
     │
     ├──> [Suspicious Access Detection]
     │         │
     │         └──> Suspicious? ──> Log + Notify
     │
     └──> [File Delivery]
           │
           └──> 200 OK + File Content + Cache Headers
Security Event Processing
Security Event
     │
     ├──> [Severity Filter]
     │         │
     │         └──> Below Min? ──> Drop
     │
     ├──> [Go Callbacks]
     │         │
     │         └──> async goroutine
     │
     └──> [Webhook Integration]
           │
           ├──> Batch Enabled?
           │         │
           │         ├──> Add to Batch
           │         │     │
           │         │     ├──> Batch Full? ──> Send Immediately
           │         │     └──> Start Timer ──> Send on Timeout
           │         │
           │         └──> Real-time
           │               │
           │               ├──> JSON Format ──> POST to Webhook
           │               └──> CEF Format ──> POST to SIEM
Thread Safety Model
┌─────────────────────────────────────────────────────┐
│             Static Handler (Lock-Free)              │
├─────────────────────────────────────────────────────┤
│                                                      │
│  Atomic Operations (libatm.Value, atomic.*)         │
│  ├─ Configuration (RateLimit, Security, Headers)    │
│  ├─ IP Tracking (libatm.MapTyped)                   │
│  ├─ Event Batching (atomic counters + map)          │
│  └─ Router State                                    │
│                                                      │
│  Embedded Filesystem (read-only, inherently safe)   │
│                                                      │
│  Context-based Configuration (libctx.Config)        │
│  ├─ Index files                                     │
│  ├─ Downloads                                       │
│  ├─ Redirects                                       │
│  └─ Custom handlers                                 │
│                                                      │
└─────────────────────────────────────────────────────┘

  No mutexes required!
  Concurrent reads and writes are safe by design.

Quick Start

Minimum Go Version

Go 1.21+ is required for:

  • embed.FS and //go:embed directive (Go 1.16)
  • Generics support for type-safe atomic wrappers (Go 1.18)
  • atomic.Int64/atomic.Uint64 types with methods (Go 1.19)
  • slices.Contains() from standard library (Go 1.21)
Basic Usage
package main

import (
    "context"
    "embed"
    
    "github.com/gin-gonic/gin"
    "github.com/nabbar/golib/static"
)

//go:embed public
var publicFS embed.FS

func main() {
    // Create static handler
    handler := static.New(context.Background(), publicFS, "public")
    
    // Configure security
    handler.SetPathSecurity(static.DefaultPathSecurityConfig())
    handler.SetRateLimit(static.DefaultRateLimitConfig())
    
    // Setup Gin router
    router := gin.Default()
    handler.RegisterRouter("/static", router.GET)
    
    router.Run(":8080")
}
With Security Integration
handler := static.New(ctx, fs, "assets")

// Path security
handler.SetPathSecurity(static.PathSecurityConfig{
    Enabled:       true,
    AllowDotFiles: false,
    MaxPathDepth:  10,
    BlockedPatterns: []string{".git", ".env"},
})

// Rate limiting
handler.SetRateLimit(static.RateLimitConfig{
    Enabled:     true,
    MaxRequests: 100,
    Window:      time.Minute,
})

// WAF integration
handler.SetSecurityBackend(static.SecurityConfig{
    Enabled:    true,
    WebhookURL: "https://waf.example.com/events",
    MinSeverity: "medium",
})
Advanced Configuration
// HTTP caching
handler.SetHeaders(static.HeadersConfig{
    EnableCacheControl: true,
    CacheMaxAge:        3600,
    CachePublic:        true,
    EnableETag:         true,
    DenyMimeTypes: []string{"application/x-executable"},
})

// Suspicious access detection
handler.SetSuspicious(static.SuspiciousConfig{
    Enabled: true,
    SuspiciousPatterns: []string{
        ".env", ".git", "wp-admin",
    },
})

// Index files
handler.SetIndex("", "/", "index.html")
handler.SetIndex("", "/docs", "docs/index.html")

// Downloads
handler.SetDownload("/files/document.pdf", true)

// Redirects
handler.SetRedirect("", "/old-path", "", "/new-path")

Performance

Test Results
Metric Value Notes
Test Coverage 82.6% 229/229 tests passing
Race Conditions 0 Verified with -race detector
Throughput 1,900-5,600 RPS Single file, no caching
Latency (p50) ~100µs File operation median
Latency (p99) <5ms Large file operations
Memory O(1) per request No allocation spikes
Benchmarks
Static File Operations
Name                        | N   | Min   | Median | Mean  | StdDev | Max
========================================================================================
File-Has [duration]         | 100 | 0s    | 0s     | 0s    | 0s     | 100µs
File-Info [duration]        | 100 | 0s    | 0s     | 0s    | 0s     | 100µs
File-Find [duration]        | 100 | 0s    | 0s     | 0s    | 0s     | 200µs
PathSecurity [duration]     | 100 | 0s    | 0s     | 0s    | 0s     | 100µs
RateLimit-Allow [duration]  | 100 | 0s    | 0s     | 0s    | 0s     | 200µs
RateLimit-Block [duration]  | 10  | 0s    | 0s     | 0s    | 0s     | 100µs
ETag-Generate [duration]    | 100 | 0s    | 0s     | 0s    | 0s     | 100µs
ETag-Validate [duration]    | 100 | 0s    | 0s     | 0s    | 0s     | 0s
Redirect [duration]         | 500 | 100µs | 100µs  | 200µs | 100µs  | 1.6ms
SpecificHandler [duration]  | 500 | 100µs | 100µs  | 100µs | 100µs  | 600µs
Throughput-RPS              | 1   | 1,938 | 5,692  | 3,815 | varies | 5,692
Performance Characteristics
  • Zero Mutex Overhead - All operations use atomic primitives
  • O(1) IP Lookup - Constant time rate limit checks
  • Lazy Initialization - Configuration loaded on demand
  • Efficient Batching - Reduces webhook overhead by 90%+
  • 304 Responses - Saves bandwidth with ETag validation

Use Cases

1. Single Page Application (SPA)
handler := static.New(ctx, embedFS, "dist")

// Security
handler.SetPathSecurity(static.DefaultPathSecurityConfig())

// Aggressive caching for immutable assets
handler.SetHeaders(static.HeadersConfig{
    EnableCacheControl: true,
    CacheMaxAge:        31536000, // 1 year
    CachePublic:        true,
    EnableETag:         true,
})

// Index file for all routes (SPA routing)
handler.SetIndex("", "/", "index.html")
2. API Documentation Server
handler := static.New(ctx, docsFS, "docs")

// Moderate caching
handler.SetHeaders(static.HeadersConfig{
    CacheMaxAge: 3600, // 1 hour
    EnableETag:  true,
})

// Rate limiting
handler.SetRateLimit(static.RateLimitConfig{
    MaxRequests: 1000,
    Window:      time.Minute,
})
3. CDN Origin Server
handler := static.New(ctx, assetsFS, "assets")

// Maximum caching for CDN
handler.SetHeaders(static.HeadersConfig{
    CacheMaxAge: 31536000, // 1 year
    CachePublic: true,
    EnableETag:  true,
})

// Relaxed rate limiting (CDN handles most traffic)
handler.SetRateLimit(static.RateLimitConfig{
    MaxRequests: 10000,
    Window:      time.Minute,
})
4. Enterprise Web Application
handler := static.New(ctx, appFS, "public")

// Full security stack
handler.SetPathSecurity(static.PathSecurityConfig{
    Enabled:         true,
    AllowDotFiles:   false,
    MaxPathDepth:    10,
    BlockedPatterns: []string{".git", ".svn", "node_modules"},
})

handler.SetRateLimit(static.RateLimitConfig{
    Enabled:     true,
    MaxRequests: 100,
    Window:      time.Minute,
})

handler.SetSuspicious(static.DefaultSuspiciousConfig())

// WAF/SIEM integration
handler.SetSecurityBackend(static.SecurityConfig{
    Enabled:      true,
    WebhookURL:   "https://siem.company.com/events",
    BatchSize:    100,
    BatchTimeout: 30 * time.Second,
    EnableCEFFormat: true,
})
5. Development Server
handler := static.New(ctx, devFS, "src")

// Minimal security for local dev
handler.SetPathSecurity(static.PathSecurityConfig{
    Enabled:       true,
    AllowDotFiles: false, // Still protect .env
})

// No caching for fast iteration
handler.SetHeaders(static.HeadersConfig{
    EnableCacheControl: false,
})

API Reference

Core Interface
type Static interface {
    StaticFileSystem
    StaticPathSecurity
    StaticRateLimit
    StaticHeaders
    StaticSuspicious
    StaticSecurityBackend
    StaticIndex
    StaticDownload
    StaticRedirect
    StaticSpecific
    StaticRouter
    StaticMonitor
}
Configuration Types
PathSecurityConfig
type PathSecurityConfig struct {
    Enabled         bool     // Enable path validation
    AllowDotFiles   bool     // Allow .env, .git, etc.
    MaxPathDepth    int      // Maximum depth (0 = unlimited)
    BlockedPatterns []string // Patterns to block
}
RateLimitConfig
type RateLimitConfig struct {
    Enabled         bool          // Enable rate limiting
    MaxRequests     int           // Max unique files per window
    Window          time.Duration // Time window
    CleanupInterval time.Duration // Cleanup frequency
    WhitelistIPs    []string      // Bypass IPs
    TrustedProxies  []string      // Trusted proxy IPs
}
HeadersConfig
type HeadersConfig struct {
    EnableCacheControl bool              // Enable Cache-Control
    CacheMaxAge        int               // Cache duration (seconds)
    CachePublic        bool              // Public or private cache
    EnableETag         bool              // Enable ETag
    EnableContentType  bool              // Enable MIME validation
    AllowedMimeTypes   []string          // Whitelist (empty = all)
    DenyMimeTypes      []string          // Blacklist
    CustomMimeTypes    map[string]string // Custom mappings
}
SecurityConfig
type SecurityConfig struct {
    Enabled         bool              // Enable security backend
    WebhookURL      string            // Webhook endpoint
    WebhookHeaders  map[string]string // Custom headers
    WebhookTimeout  time.Duration     // Request timeout
    WebhookAsync    bool              // Async sending
    MinSeverity     string            // Minimum severity level
    BatchSize       int               // Batch size (0 = real-time)
    BatchTimeout    time.Duration     // Batch flush interval
    EnableCEFFormat bool              // Use CEF format
    Callbacks       []SecuEvtCallback // Go callbacks
}
Error Codes
const (
    ErrorFileNotFound     // File not found in embedded FS
    ErrorFileOpen         // Cannot open file
    ErrorFileRead         // Cannot read file
    ErrorFiletemp         // Cannot create temp file
    ErrorParamEmpty       // Required parameter empty
    ErrorPathInvalid      // Invalid path
    ErrorPathTraversal    // Path traversal attempt
    ErrorPathDotFile      // Dot file access denied
    ErrorPathDepth        // Path depth exceeded
    ErrorPathBlocked      // Blocked pattern matched
    ErrorMimeTypeDenied   // MIME type not allowed
)
Security Event Types
const (
    EventTypePathTraversal  // Path traversal attack
    EventTypeRateLimit      // Rate limit exceeded
    EventTypeSuspicious     // Suspicious access pattern
    EventTypeMimeTypeDenied // MIME type denied
    EventTypeDotFile        // Dot file access attempt
    EventTypePatternBlocked // Blocked pattern matched
    EventTypePathDepth      // Path depth exceeded
)

Best Practices

✅ DO
// Use default configurations as starting point
handler.SetPathSecurity(static.DefaultPathSecurityConfig())
handler.SetRateLimit(static.DefaultRateLimitConfig())

// Enable ETag for bandwidth savings
handler.SetHeaders(static.HeadersConfig{
    EnableETag: true,
    CacheMaxAge: 3600,
})

// Use batch processing for high-volume security events
handler.SetSecurityBackend(static.SecurityConfig{
    Enabled: true,
    BatchSize: 100,
    BatchTimeout: 30 * time.Second,
})

// Whitelist localhost for development
handler.SetRateLimit(static.RateLimitConfig{
    WhitelistIPs: []string{"127.0.0.1", "::1"},
})

// Set appropriate cache duration per asset type
handler.SetHeaders(static.HeadersConfig{
    CacheMaxAge: 31536000, // 1 year for versioned assets
})
❌ DON'T
// Don't disable all security in production
handler.SetPathSecurity(static.PathSecurityConfig{
    Enabled: false, // ❌ Unsafe
})

// Don't allow dot files in production
handler.SetPathSecurity(static.PathSecurityConfig{
    AllowDotFiles: true, // ❌ Exposes .env, .git
})

// Don't set unlimited rate limit
handler.SetRateLimit(static.RateLimitConfig{
    MaxRequests: 0, // ❌ No protection
})

// Don't use sync webhooks in high-traffic scenarios
handler.SetSecurityBackend(static.SecurityConfig{
    WebhookAsync: false, // ❌ Blocks requests
})

// Don't forget cleanup interval
handler.SetRateLimit(static.RateLimitConfig{
    CleanupInterval: 0, // ❌ Memory leak
})
Security Recommendations
  1. Always enable path security - Even in development
  2. Use rate limiting - Protect against DoS attacks
  3. Enable suspicious detection - Identify attack patterns early
  4. Integrate with SIEM - Use webhook or CEF for monitoring
  5. Regular cleanup - Configure CleanupInterval for rate limiter
  6. Whitelist carefully - Only trusted IPs should bypass limits
  7. Block dangerous MIME types - Prevent executable uploads
  8. Use batch processing - Reduce security backend overhead
Performance Recommendations
  1. Enable ETag - Reduces bandwidth significantly
  2. Use CDN - Offload static file delivery
  3. Appropriate cache TTL - Balance freshness vs. performance
  4. Async webhooks - Non-blocking security event delivery
  5. Batch events - Reduce webhook call overhead
  6. Monitor throughput - Use built-in benchmarks

Testing

For comprehensive testing documentation, see TESTING.md.

Test Suite:

  • Total Tests: 229
  • Coverage: 82.6%
  • Race Detection: ✅ Zero data races
  • Execution Time: ~4.7s (standard), ~6.6s (with race)
# Run all tests
go test -v

# With race detector
CGO_ENABLED=1 go test -race

# With coverage
go test -cover -coverprofile=coverage.out

Contributing

Contributions are welcome! Please follow these guidelines:

Code Contributions
  • No AI-generated code in core implementation
  • AI assistance is acceptable for tests, documentation, and bug fixes
  • All contributions must pass existing tests
  • Add tests for new features
  • Follow existing code style
  • Document public APIs with GoDoc
Testing Requirements
  • Maintain >80% code coverage
  • Zero race conditions (go test -race)
  • All tests must pass
  • Add benchmarks for performance-critical code
Documentation
  • Update README.md for new features
  • Add examples to example_test.go
  • Document breaking changes
  • Keep TESTING.md current
Pull Request Process
  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Run tests: go test -race -cover ./...
  5. Update documentation
  6. Submit pull request with clear description

Future Enhancements

Planned Features
  • Advanced Rate Limiting

    • Token bucket algorithm
    • Distributed rate limiting (Redis integration)
    • Per-route rate limits
  • Enhanced Security

    • Content Security Policy (CSP) headers
    • Subresource Integrity (SRI) support
    • CORS configuration
  • Performance Optimization

    • Brotli compression support
    • HTTP/2 Server Push hints
    • Memory-mapped file serving for large files
  • Monitoring

    • Prometheus metrics endpoint
    • Detailed access logging
    • Performance tracing integration
  • Developer Experience

    • Hot reload support for development
    • Configuration validation
    • More detailed error messages

Suggestions and contributions are welcome via GitHub issues.


AI Transparency Notice

In accordance with Article 50.4 of the EU AI Act, AI assistance has been used for testing, documentation, and bug fixing under human supervision.


License

MIT License - See LICENSE file for details.

Copyright (c) 2022 Nicolas JUHEL


Resources

Documentation

Overview

Package static provides a secure, high-performance static file server for Gin framework with embedded filesystem support, comprehensive security features, and WAF/IDS/EDR integration.

Overview

The static package is designed to serve files from Go's embed.FS with enterprise-grade security features including:

  • Path traversal protection with configurable rules
  • IP-based rate limiting (DoS/scraping prevention)
  • Suspicious access pattern detection
  • MIME type validation and filtering
  • HTTP caching (ETag, Cache-Control)
  • Integration with external security systems (WAF/IDS/EDR)

All operations are thread-safe using atomic operations without mutexes for maximum performance and scalability.

Architecture

The package follows a layered architecture with clear separation of concerns:

┌─────────────────────────────────────────────────────────────┐
│                    Gin HTTP Request                          │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────┐
│                  Static Handler (Get)                        │
│  ┌────────────┬───────────────┬─────────────┬─────────────┐ │
│  │Rate Limit  │Path Security  │Headers      │Suspicious   │ │
│  │Check       │Validation     │Control      │Detection    │ │
│  └────────────┴───────────────┴─────────────┴─────────────┘ │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────┐
│              File Operations (embed.FS)                      │
│  ┌────────────┬───────────────┬─────────────┬─────────────┐ │
│  │Has()       │Find()         │Info()       │Temp()       │ │
│  └────────────┴───────────────┴─────────────┴─────────────┘ │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────┐
│              HTTP Response (SendFile)                        │
│  ┌────────────┬───────────────┬─────────────┬─────────────┐ │
│  │ETag        │Cache-Control  │Content-Type │Disposition  │ │
│  └────────────┴───────────────┴─────────────┴─────────────┘ │
└─────────────────────────────────────────────────────────────┘

Request Flow

A typical request flows through multiple security layers:

HTTP Request
     │
     ▼
[Rate Limit Check]
     │
     ├─── Rate exceeded? ──► 429 Too Many Requests
     │
     ▼
[Path Security Validation]
     │
     ├─── Path traversal? ──► 403 Forbidden
     ├─── Dot file? ────────► 403 Forbidden
     ├─── Blocked pattern? ─► 403 Forbidden
     │
     ▼
[Suspicious Access Detection]
     │
     ├─── Log suspicious patterns
     │
     ▼
[File Exists Check]
     │
     ├─── Not found? ───────► 404 Not Found
     │
     ▼
[ETag Validation]
     │
     ├─── Cached? ──────────► 304 Not Modified
     │
     ▼
[MIME Type Validation]
     │
     ├─── Denied type? ─────► 403 Forbidden
     │
     ▼
[Send File with Headers]
     │
     ▼
200 OK with caching headers

Security Features

The package implements defense-in-depth with multiple security layers:

## 1. Path Traversal Protection

Protects against directory traversal attacks:

  • Detects ".." sequences before path normalization
  • Validates against null byte injection
  • Enforces maximum path depth
  • Blocks access to dot files (.env, .git, etc.)
  • Pattern-based blocking (configurable)

Example:

handler.SetPathSecurity(static.PathSecurityConfig{
    Enabled:         true,
    AllowDotFiles:   false,
    MaxPathDepth:    10,
    BlockedPatterns: []string{".git", ".svn", "node_modules"},
})

## 2. Rate Limiting

IP-based rate limiting tracks unique file paths per IP:

  • Configurable request limits and time windows
  • IP whitelisting support
  • Trusted proxy detection
  • Automatic cache cleanup
  • Thread-safe atomic operations

Example:

handler.SetRateLimit(static.RateLimitConfig{
    Enabled:         true,
    MaxRequests:     100,
    Window:          time.Minute,
    CleanupInterval: 5 * time.Minute,
    WhitelistIPs:    []string{"127.0.0.1"},
})

## 3. Suspicious Access Detection

Monitors and logs suspicious file access patterns:

  • Configuration file access (.env, config.php)
  • Backup file enumeration (.bak, .old)
  • Admin panel scanning (wp-admin, phpmyadmin)
  • Database file requests (.sql, .db)
  • Logs both successful and failed attempts

## 4. MIME Type Validation

Controls which file types can be served:

  • MIME type detection by file extension
  • Whitelist/blacklist configuration
  • Custom MIME type mapping
  • Blocks dangerous file types (.exe, .sh)

## 5. HTTP Caching

Optimizes bandwidth and performance:

  • ETag generation and validation
  • Cache-Control headers (public/private)
  • 304 Not Modified responses
  • Configurable cache duration
  • Last-Modified support

Security Backend Integration

The package can report security events to external systems:

┌──────────────┐         ┌──────────────┐         ┌──────────────┐
│ Static       │         │ Security     │         │ External     │
│ Handler      │────────►│ Event        │────────►│ System       │
│              │         │ Processor    │         │ (WAF/IDS)    │
└──────────────┘         └──────────────┘         └──────────────┘
                                │
                                ├─────► Webhook (JSON/CEF)
                                │
                                └─────► Go Callbacks

Supported integrations:

  • Webhooks with custom headers (Authorization, etc.)
  • Common Event Format (CEF) for SIEM systems
  • Go callbacks for custom processing
  • Batch processing for efficiency
  • Configurable severity filtering

Thread Safety

All data structures use atomic operations without mutexes:

Configuration:  libatm.Value[*Config]        (atomic.Value wrapper)
IP Tracking:    libatm.MapTyped[string, *T]  (atomic map)
Counters:       atomic.Int64, atomic.Uint64  (standard atomic)
Event Batch:    atomic operations only       (no mutex)

This design ensures:

  • Zero contention under high load
  • Predictable performance
  • No deadlock risk
  • Lock-free scalability

Performance Considerations

The package is optimized for high-performance scenarios:

1. Atomic Operations: All state managed without mutexes 2. Lazy Initialization: Security features activated only when configured 3. Batch Processing: Multiple events sent together to reduce overhead 4. HTTP Caching: ETag reduces bandwidth and CPU usage 5. Embedded FS: No disk I/O for file access

Typical performance characteristics:

  • Request handling: <1ms per request (cached)
  • Rate limit check: ~100ns (atomic read)
  • Path validation: <10μs (string operations)
  • ETag generation: <1μs (hash calculation)

Dependencies

This package requires:

  • github.com/gin-gonic/gin - HTTP framework
  • github.com/nabbar/golib/atomic - Thread-safe atomic wrappers
  • github.com/nabbar/golib/context - Context-aware configuration
  • github.com/nabbar/golib/logger - Logging interface
  • github.com/nabbar/golib/errors - Error management
  • github.com/nabbar/golib/router - Router helpers
  • github.com/nabbar/golib/monitor - Health monitoring

Example Usage

Basic static file server:

package main

import (
    "context"
    "embed"
    "github.com/gin-gonic/gin"
    "github.com/nabbar/golib/static"
)

//go:embed assets/*
var content embed.FS

func main() {
    handler := static.New(context.Background(), content, "assets")
    router := gin.Default()
    handler.RegisterRouter("/static", router.GET)
    router.Run(":8080")
}

With security features:

handler := static.New(context.Background(), content, "assets")

// Path security
handler.SetPathSecurity(static.DefaultPathSecurityConfig())

// Rate limiting
handler.SetRateLimit(static.RateLimitConfig{
    Enabled:     true,
    MaxRequests: 100,
    Window:      time.Minute,
})

// HTTP caching
handler.SetHeaders(static.DefaultHeadersConfig())

// Security backend
handler.SetSecurityBackend(static.SecurityConfig{
    Enabled:    true,
    WebhookURL: "https://waf.example.com/events",
})

See example_test.go for more comprehensive examples.

Best Practices

  1. Always enable path security in production: handler.SetPathSecurity(static.DefaultPathSecurityConfig())

2. Configure rate limiting appropriate to your traffic:

  • API serving: 100-1000 requests/minute

  • Public websites: 1000-10000 requests/minute

    3. Use HTTP caching to reduce server load: handler.SetHeaders(static.DefaultHeadersConfig())

    4. Monitor security events in production: handler.SetSecurityBackend() with appropriate webhooks

    5. Whitelist known IPs (monitoring, health checks): config.WhitelistIPs = []string{"monitoring-ip"}

    6. Use custom MIME types for modern formats: config.CustomMimeTypes = map[string]string{".wasm": "application/wasm"}

    7. Enable suspicious access logging: handler.SetSuspicious(static.DefaultSuspiciousConfig())

Troubleshooting

Common issues and solutions:

403 Forbidden:

  • Check path security configuration
  • Verify file is not a dot file (if AllowDotFiles = false)
  • Check blocked patterns

429 Too Many Requests:

  • Increase rate limit (MaxRequests)
  • Add IP to whitelist
  • Increase time window

404 Not Found:

  • Verify file exists in embed.FS
  • Check embedRootDir parameter in New()
  • Use handler.Has() to verify file presence

Testing

The package includes comprehensive tests:

  • 229+ test cases
  • Thread safety verified with race detector
  • Concurrency stress tests
  • Benchmark tests
  • Security scenario tests

Run tests:

go test -v
go test -race  (with race detector)
go test -bench . (benchmarks)

License

Package static provides a secure, high-performance static file server for Gin framework with embedded filesystem support, rate limiting, path security, and WAF/IDS/EDR integration.

This package is designed to serve static files from an embedded filesystem (embed.FS) with advanced security features including:

  • Path traversal protection
  • IP-based rate limiting
  • Suspicious access detection
  • MIME type validation
  • HTTP caching (ETag, Cache-Control)
  • Integration with WAF/IDS/EDR systems

Thread Safety:

All operations are thread-safe and use atomic operations without mutexes for maximum performance and scalability.

Basic Usage:

package main

import (
    "context"
    "embed"
    "github.com/gin-gonic/gin"
    "github.com/nabbar/golib/static"
)

//go:embed assets/*
var content embed.FS

func main() {
    handler := static.New(context.Background(), content, "assets")
    router := gin.Default()
    handler.RegisterRouter("/static", router.GET)
    router.Run(":8080")
}

For more information about related packages:

  • github.com/nabbar/golib/logger - Logging interface
  • github.com/nabbar/golib/router - Router registration helpers
  • github.com/nabbar/golib/monitor - Health monitoring
Example (ApiAssets)

Example_apiAssets demonstrates serving assets for an API.

package main

import (
	"context"
	"embed"
	"fmt"
	"time"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Strict security
	handler.SetPathSecurity(static.PathSecurityConfig{
		Enabled:       true,
		AllowDotFiles: false,
		MaxPathDepth:  5,
	})

	// Conservative rate limiting
	handler.SetRateLimit(static.RateLimitConfig{
		Enabled:     true,
		MaxRequests: 100,
		Window:      time.Minute,
	})

	// Long cache duration
	handler.SetHeaders(static.HeadersConfig{
		EnableCacheControl: true,
		CacheMaxAge:        86400, // 24 hours
		EnableETag:         true,
	})

	fmt.Println("API assets configuration complete")
}
Output:

API assets configuration complete
Example (Basic)

Example_basic shows the simplest usage of the static package. This example serves files from an embedded filesystem with no security features.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	// Create a static file handler
	_ = static.New(context.Background(), exampleContent, "testdata")

	// The handler can now be registered with Gin router
	// router := gin.Default()
	// handler.RegisterRouter("/static", router.GET)
	// router.Run(":8080")

	// Files will be accessible at http://localhost:8080/static/*
	fmt.Println("Basic static file handler created")
}
Output:

Basic static file handler created
Example (Cdn)

Example_cdn demonstrates configuration optimized for CDN usage.

package main

import (
	"context"
	"embed"
	"fmt"
	"time"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Aggressive caching for CDN
	handler.SetHeaders(static.HeadersConfig{
		EnableCacheControl: true,
		CacheMaxAge:        31536000, // 1 year
		CachePublic:        true,     // Allow CDN caching
		EnableETag:         true,
	})

	// Relaxed rate limiting (CDN handles most requests)
	handler.SetRateLimit(static.RateLimitConfig{
		Enabled:     true,
		MaxRequests: 10000,
		Window:      time.Minute,
	})

	fmt.Println("CDN configuration complete")
}
Output:

CDN configuration complete
Example (Development)

Example_development demonstrates a minimal development configuration.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	// Minimal setup for local development
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Only enable basic security
	handler.SetPathSecurity(static.PathSecurityConfig{
		Enabled:       true,
		AllowDotFiles: false,
	})

	fmt.Println("Development configuration complete")
}
Output:

Development configuration complete
Example (DownloadFiles)

Example_downloadFiles demonstrates download configuration.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Mark files to be downloaded instead of displayed
	handler.SetDownload("/static/document.pdf", true)
	handler.SetDownload("/static/archive.zip", true)

	// Check if a file should be downloaded
	shouldDownload := handler.IsDownload("/static/document.pdf")
	fmt.Printf("Should download: %v\n", shouldDownload)
}
Output:

Should download: false
Example (FileOperations)

Example_fileOperations demonstrates file operations on embedded filesystem.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	_ = static.New(context.Background(), exampleContent, "testdata")

	// Check if file exists
	// exists := handler.Has("test.txt")

	// List all files
	// files, _ := handler.List("testdata")

	// Get file info
	// info, _ := handler.Info("test.txt")

	fmt.Println("File operations available")
}
Output:

File operations available
Example (HttpCaching)

Example_httpCaching demonstrates HTTP caching with ETag and Cache-Control.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Configure HTTP headers with default settings
	handler.SetHeaders(static.DefaultHeadersConfig())

	// Or customize
	handler.SetHeaders(static.HeadersConfig{
		EnableCacheControl: true,
		CacheMaxAge:        3600, // 1 hour
		CachePublic:        true, // Allow CDN caching
		EnableETag:         true, // Enable ETag validation
		EnableContentType:  true,
		CustomMimeTypes: map[string]string{
			".wasm": "application/wasm",
		},
	})

	fmt.Println("HTTP caching configured")
}
Output:

HTTP caching configured
Example (IndexFiles)

Example_indexFiles demonstrates index file configuration.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Set index file for root
	handler.SetIndex("", "/", "index.html")

	// Set index for specific routes
	handler.SetIndex("", "/docs", "docs/index.html")

	fmt.Println("Index files configured")
}
Output:

Index files configured
Example (MimeTypeValidation)

Example_mimeTypeValidation demonstrates MIME type filtering.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Block dangerous file types
	handler.SetHeaders(static.HeadersConfig{
		EnableContentType: true,
		DenyMimeTypes: []string{
			"application/x-executable",
			"application/x-msdownload",
			"application/x-sh",
		},
	})

	// Or whitelist only specific types
	handler.SetHeaders(static.HeadersConfig{
		EnableContentType: true,
		AllowedMimeTypes: []string{
			"text/html",
			"text/css",
			"application/javascript",
			"image/png",
			"image/jpeg",
		},
	})

	fmt.Println("MIME type validation configured")
}
Output:

MIME type validation configured
Example (PathSecurity)

Example_pathSecurity demonstrates path traversal protection.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Enable path security with default settings
	handler.SetPathSecurity(static.DefaultPathSecurityConfig())

	// Or customize the configuration
	handler.SetPathSecurity(static.PathSecurityConfig{
		Enabled:       true,
		AllowDotFiles: false, // Block .env, .git, etc.
		MaxPathDepth:  10,
		BlockedPatterns: []string{
			".git",
			".svn",
			"node_modules",
		},
	})

	// Check if a path is safe
	safe := handler.IsPathSafe("/static/test.txt")
	fmt.Printf("Path is safe: %v\n", safe)
}
Output:

Path is safe: true
Example (Production)

Example_production demonstrates a complete production-ready configuration.

package main

import (
	"context"
	"embed"
	"fmt"
	"time"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// 1. Path Security
	handler.SetPathSecurity(static.PathSecurityConfig{
		Enabled:       true,
		AllowDotFiles: false,
		MaxPathDepth:  10,
		BlockedPatterns: []string{
			".git", ".svn", ".env",
			"node_modules", "vendor",
		},
	})

	// 2. Rate Limiting
	handler.SetRateLimit(static.RateLimitConfig{
		Enabled:         true,
		MaxRequests:     1000,
		Window:          time.Minute,
		CleanupInterval: 5 * time.Minute,
		WhitelistIPs:    []string{"127.0.0.1"},
	})

	// 3. HTTP Caching
	handler.SetHeaders(static.HeadersConfig{
		EnableCacheControl: true,
		CacheMaxAge:        3600,
		CachePublic:        true,
		EnableETag:         true,
		EnableContentType:  true,
		DenyMimeTypes: []string{
			"application/x-executable",
		},
	})

	// 4. Suspicious Access Detection
	handler.SetSuspicious(static.SuspiciousConfig{
		Enabled:             true,
		LogSuccessfulAccess: true,
		SuspiciousPatterns:  []string{".env", ".git"},
	})

	// 5. Security Backend
	handler.SetSecurityBackend(static.SecurityConfig{
		Enabled:      true,
		WebhookURL:   "https://waf.example.com/events",
		WebhookAsync: true,
		MinSeverity:  "medium",
		BatchSize:    100,
		BatchTimeout: 30 * time.Second,
	})

	// 6. Index Files
	handler.SetIndex("", "/", "index.html")

	fmt.Println("Production configuration complete")
}
Output:

Production configuration complete
Example (RateLimit)

Example_rateLimit demonstrates IP-based rate limiting.

package main

import (
	"context"
	"embed"
	"fmt"
	"time"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Configure rate limiting
	handler.SetRateLimit(static.RateLimitConfig{
		Enabled:         true,
		MaxRequests:     100,             // Max 100 unique files
		Window:          time.Minute,     // Per minute
		CleanupInterval: 5 * time.Minute, // Cleanup every 5 minutes
		WhitelistIPs: []string{
			"127.0.0.1", // Localhost
			"::1",       // IPv6 localhost
		},
	})

	// Check if an IP is rate limited
	limited := handler.IsRateLimited("192.168.1.100")
	fmt.Printf("IP is rate limited: %v\n", limited)
}
Output:

IP is rate limited: false
Example (Redirects)

Example_redirects demonstrates URL redirection.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Configure redirects (HTTP 301)
	handler.SetRedirect("", "/old-path", "", "/new-path")
	handler.SetRedirect("", "/legacy", "", "/modern")

	fmt.Println("Redirects configured")
}
Output:

Redirects configured
Example (SecurityBackend)

Example_securityBackend demonstrates WAF/IDS/EDR integration.

package main

import (
	"context"
	"embed"
	"fmt"
	"time"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Configure security backend with webhook
	handler.SetSecurityBackend(static.SecurityConfig{
		Enabled:    true,
		WebhookURL: "https://waf.example.com/events",
		WebhookHeaders: map[string]string{
			"Authorization": "Bearer secret-token",
		},
		WebhookTimeout: 5 * time.Second,
		WebhookAsync:   true,     // Non-blocking
		MinSeverity:    "medium", // Only medium, high, critical
	})

	fmt.Println("Security backend configured")
}
Output:

Security backend configured
Example (SecurityBackendBatch)

Example_securityBackendBatch demonstrates batch event processing.

package main

import (
	"context"
	"embed"
	"fmt"
	"time"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Configure batch processing for efficiency
	handler.SetSecurityBackend(static.SecurityConfig{
		Enabled:      true,
		WebhookURL:   "https://siem.example.com/batch",
		BatchSize:    100,              // Send every 100 events
		BatchTimeout: 30 * time.Second, // Or every 30 seconds
		MinSeverity:  "low",            // All severity levels
	})

	fmt.Println("Batch security backend configured")
}
Output:

Batch security backend configured
Example (SecurityBackendCEF)

Example_securityBackendCEF demonstrates CEF format for SIEM systems.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Configure CEF format for SIEM compatibility
	handler.SetSecurityBackend(static.SecurityConfig{
		Enabled:         true,
		WebhookURL:      "https://siem.example.com/cef",
		EnableCEFFormat: true, // Common Event Format
		MinSeverity:     "high",
	})

	fmt.Println("CEF format configured")
}
Output:

CEF format configured
Example (SuspiciousDetection)

Example_suspiciousDetection demonstrates suspicious access pattern detection.

package main

import (
	"context"
	"embed"
	"fmt"

	"github.com/nabbar/golib/static"
)

//go:embed testdata
var exampleContent embed.FS

func main() {
	handler := static.New(context.Background(), exampleContent, "testdata")

	// Enable suspicious access detection
	handler.SetSuspicious(static.DefaultSuspiciousConfig())

	// Or customize
	handler.SetSuspicious(static.SuspiciousConfig{
		Enabled:             true,
		LogSuccessfulAccess: true, // Log even successful suspicious requests
		SuspiciousPatterns: []string{
			".env",
			".git",
			"wp-admin",
			"phpmyadmin",
		},
		SuspiciousExtensions: []string{
			".php",
			".exe",
		},
	})

	fmt.Println("Suspicious access detection enabled")
}
Output:

Suspicious access detection enabled

Index

Examples

Constants

View Source
const (
	// ErrorParamEmpty indicates that required parameters are empty or missing
	ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgStatic

	// ErrorFileInfo indicates failure to retrieve file information
	ErrorFileInfo

	// ErrorFileOpen indicates failure to open a file from the embedded filesystem
	ErrorFileOpen

	// ErrorFiletemp indicates failure to create a temporary file
	ErrorFiletemp

	// ErrorFileNotFound indicates the requested file does not exist
	ErrorFileNotFound

	// ErrorPathInvalid indicates an invalid or malformed path
	ErrorPathInvalid

	// ErrorPathTraversal indicates a path traversal attempt was detected
	ErrorPathTraversal

	// ErrorPathDotFile indicates an attempt to access a dot file (hidden file)
	ErrorPathDotFile

	// ErrorPathDepth indicates the path depth exceeds the configured maximum
	ErrorPathDepth

	// ErrorPathBlocked indicates the path matches a blocked pattern
	ErrorPathBlocked

	// ErrorMimeTypeDenied indicates the file's MIME type is not allowed
	ErrorMimeTypeDenied
)

Error codes for the static package. These errors use the github.com/nabbar/golib/errors package for error management.

Variables

This section is empty.

Functions

This section is empty.

Types

type HeadersConfig added in v1.19.0

type HeadersConfig struct {
	// EnableCacheControl activates HTTP cache control headers
	EnableCacheControl bool

	// CacheMaxAge is the cache duration in seconds (e.g., 3600 = 1 hour)
	CacheMaxAge int

	// CachePublic when true, cache is public (CDN), otherwise private (browser only)
	CachePublic bool

	// EnableETag activates ETag generation for cache validation
	EnableETag bool

	// EnableContentType activates Content-Type detection and validation
	EnableContentType bool

	// AllowedMimeTypes is a list of allowed MIME types (empty = all allowed)
	AllowedMimeTypes []string

	// DenyMimeTypes is a list of forbidden MIME types
	DenyMimeTypes []string

	// CustomMimeTypes overrides MIME detection (extension -> mime-type mapping)
	CustomMimeTypes map[string]string
}

HeadersConfig configures HTTP headers for caching and content-type validation.

This configuration allows fine-grained control over:

  • HTTP caching (Cache-Control, Expires, ETag)
  • Content-Type detection and validation
  • MIME type whitelisting/blacklisting

func DefaultHeadersConfig added in v1.19.0

func DefaultHeadersConfig() HeadersConfig

DefaultHeadersConfig returns a default HTTP headers configuration.

Default values:

  • EnableCacheControl: true
  • CacheMaxAge: 3600 seconds (1 hour)
  • CachePublic: true (allows CDN caching)
  • EnableETag: true
  • EnableContentType: true
  • AllowedMimeTypes: empty (all allowed by default)
  • DenyMimeTypes: executable types blocked
  • CustomMimeTypes: includes wasm and webp

type HeadersControl added in v1.19.0

type HeadersControl interface {
	// SetHeaders configures HTTP headers and caching behavior
	SetHeaders(cfg HeadersConfig)

	// GetHeaders returns the current headers configuration
	GetHeaders() HeadersConfig
}

HeadersControl interface provides HTTP caching and content-type validation.

It manages:

  • Cache-Control headers (public/private, max-age)
  • ETag generation and validation (304 Not Modified)
  • Content-Type detection and validation
  • MIME type whitelisting/blacklisting

See HeadersConfig for configuration options.

type PathSecurity added in v1.19.0

type PathSecurity interface {
	// SetPathSecurity configures path security validation rules
	SetPathSecurity(cfg PathSecurityConfig)

	// GetPathSecurity returns the current path security configuration
	GetPathSecurity() PathSecurityConfig

	// IsPathSafe validates if a requested path is safe to serve
	IsPathSafe(requestPath string) bool
}

PathSecurity interface provides protection against path traversal and other path-based security vulnerabilities.

It validates requested paths against various security rules including:

  • Path traversal attempts (../)
  • Dot file access (.env, .git)
  • Maximum path depth
  • Blocked patterns
  • Null byte injection

See PathSecurityConfig for configuration options.

type PathSecurityConfig added in v1.19.0

type PathSecurityConfig struct {
	// Enabled activates or deactivates strict path validation
	Enabled bool

	// AllowDotFiles permits access to files starting with "." (default: false)
	// When false, blocks access to .env, .git, .htaccess, etc.
	AllowDotFiles bool

	// MaxPathDepth is the maximum allowed path depth (0 = unlimited)
	MaxPathDepth int

	// BlockedPatterns are path patterns to block (e.g., []string{"wp-admin", ".git"})
	BlockedPatterns []string
}

PathSecurityConfig configures path validation and security rules.

This configuration protects against various path-based attacks including path traversal, dot file access, and access to sensitive directories.

func DefaultPathSecurityConfig added in v1.19.0

func DefaultPathSecurityConfig() PathSecurityConfig

DefaultPathSecurityConfig returns a secure default path security configuration.

Default values:

  • Enabled: true
  • AllowDotFiles: false (blocks .env, .git, etc.)
  • MaxPathDepth: 10
  • BlockedPatterns: [".git", ".svn", ".env", "node_modules"]

type RateLimit added in v1.19.0

type RateLimit interface {
	// SetRateLimit configures rate limiting parameters
	SetRateLimit(cfg RateLimitConfig)

	// GetRateLimit returns the current rate limit configuration
	GetRateLimit() RateLimitConfig

	// IsRateLimited checks if an IP address is currently rate limited
	IsRateLimited(ip string) bool

	// ResetRateLimit clears rate limit data for a specific IP address
	ResetRateLimit(ip string)
}

RateLimit interface provides IP-based rate limiting functionality to prevent scraping, enumeration attacks, and DoS attempts.

The rate limiting tracks unique file paths per IP address and enforces configurable limits within time windows. All operations are thread-safe using atomic operations.

See RateLimitConfig for configuration options.

type RateLimitConfig added in v1.19.0

type RateLimitConfig struct {
	// Enabled activates or deactivates rate limiting
	Enabled bool

	// MaxRequests is the maximum number of different files allowed per IP
	MaxRequests int

	// Window is the time duration for rate counting (e.g., 1 minute)
	Window time.Duration

	// CleanupInterval is the interval for automatic cache cleanup (e.g., 5 minutes)
	CleanupInterval time.Duration

	// WhitelistIPs is a list of IP addresses exempt from rate limiting (e.g., ["127.0.0.1", "::1"])
	WhitelistIPs []string

	// TrustedProxies is a list of trusted proxy IPs to extract real client IP
	TrustedProxies []string
}

RateLimitConfig configures IP-based rate limiting to prevent scraping and DoS attacks.

The rate limiting tracks unique file paths requested per IP address within a time window. This helps protect against malicious clients that attempt to enumerate or download all files from the static file handler.

Example usage:

handler.SetRateLimit(static.RateLimitConfig{
    Enabled:         true,
    MaxRequests:     100,
    Window:          time.Minute,
    CleanupInterval: 5 * time.Minute,
    WhitelistIPs:    []string{"127.0.0.1", "::1"},
})

The rate limiting is thread-safe and uses atomic operations without mutexes.

func DefaultRateLimitConfig added in v1.19.0

func DefaultRateLimitConfig() RateLimitConfig

DefaultRateLimitConfig returns a secure default rate limiting configuration.

Default values:

  • Enabled: true
  • MaxRequests: 100 unique files per window
  • Window: 1 minute
  • CleanupInterval: 5 minutes
  • WhitelistIPs: localhost (IPv4 and IPv6)
  • TrustedProxies: empty

type SecuEvtCallback added in v1.19.0

type SecuEvtCallback func(event secEvt)

SecuEvtCallback is a callback function to process security events. It receives security events and can be used for custom handling, logging, or integration with external monitoring systems. The event parameter is of private type secEvt which contains detailed information about the security incident.

type SecurityBackend added in v1.19.0

type SecurityBackend interface {
	// SetSecurityBackend configures integration with external security systems
	SetSecurityBackend(cfg SecurityConfig)

	// GetSecurityBackend returns the current security backend configuration
	GetSecurityBackend() SecurityConfig

	// AddSecurityCallback registers a Go callback function for security events
	AddSecurityCallback(callback SecuEvtCallback)
}

SecurityBackend interface provides integration with WAF (Web Application Firewall), IDS (Intrusion Detection System), and EDR (Endpoint Detection and Response) systems.

Security events are reported via:

  • Webhooks (JSON or CEF format)
  • Go callbacks for custom processing
  • Batch processing for efficiency

Supported event types include path traversal, rate limiting, suspicious access, and MIME type violations.

See SecurityConfig for configuration options.

type SecurityConfig added in v1.19.0

type SecurityConfig struct {
	// Enabled activates the security integration
	Enabled bool

	// WebhookURL is the URL to send security events to (WAF/SIEM/IDS endpoint)
	WebhookURL string

	// WebhookTimeout is the timeout for webhook HTTP requests
	WebhookTimeout time.Duration

	// WebhookHeaders are custom HTTP headers to include in webhook requests (e.g., Authorization)
	WebhookHeaders map[string]string

	// WebhookAsync when true, sends webhooks asynchronously (non-blocking)
	WebhookAsync bool

	// Callbacks is a list of Go callback functions for custom event processing
	Callbacks []SecuEvtCallback

	// MinSeverity is the minimum severity level to notify (low, medium, high, critical)
	MinSeverity string

	// BatchSize is the number of events to accumulate before sending a batch (0 = real-time)
	BatchSize int

	// BatchTimeout is the maximum duration before sending an incomplete batch
	BatchTimeout time.Duration

	// EnableCEFFormat enables CEF (Common Event Format) for SIEM compatibility
	// See: https://www.microfocus.com/documentation/arcsight/arcsight-smartconnectors/
	EnableCEFFormat bool
}

SecurityConfig configures the integration with WAF (Web Application Firewall), IDS (Intrusion Detection System), or EDR (Endpoint Detection and Response) systems.

This configuration allows the static file handler to report security events to external systems via webhooks or callbacks. Events can be sent individually or batched for efficiency.

Example usage:

handler.SetSecurityBackend(static.SecurityConfig{
    Enabled:        true,
    WebhookURL:     "https://waf.example.com/events",
    WebhookHeaders: map[string]string{"Authorization": "Bearer token"},
    WebhookAsync:   true,
    MinSeverity:    "medium",
    BatchSize:      100,
    BatchTimeout:   30 * time.Second,
})

func DefaultSecurityConfig added in v1.19.0

func DefaultSecurityConfig() SecurityConfig

DefaultSecurityConfig returns a default security backend configuration.

Default values:

  • Enabled: false (must be explicitly enabled)
  • WebhookTimeout: 5 seconds
  • WebhookAsync: true (non-blocking)
  • MinSeverity: "medium"
  • BatchSize: 0 (real-time, no batching)
  • BatchTimeout: 30 seconds
  • EnableCEFFormat: false (JSON format)

type SecurityEventType added in v1.19.0

type SecurityEventType string

SecurityEventType represents the type of security event that occurred. It is used to categorize security incidents for monitoring and analysis.

const (
	// EventTypePathTraversal indicates an attempt to access files outside the allowed directory
	EventTypePathTraversal SecurityEventType = "path_traversal"

	// EventTypeRateLimit indicates that an IP exceeded the allowed request rate
	EventTypeRateLimit SecurityEventType = "rate_limit_exceeded"

	// EventTypeSuspiciousAccess indicates suspicious file access patterns
	EventTypeSuspiciousAccess SecurityEventType = "suspicious_access"

	// EventTypeMimeTypeDenied indicates an attempt to access a file with a blocked MIME type
	EventTypeMimeTypeDenied SecurityEventType = "mime_type_denied"

	// EventTypeDotFileAccess indicates an attempt to access hidden files (starting with .)
	EventTypeDotFileAccess SecurityEventType = "dot_file_access"

	// EventTypePatternBlocked indicates an attempt to access a path matching a blocked pattern
	EventTypePatternBlocked SecurityEventType = "pattern_blocked"

	// EventTypePathDepth indicates a path exceeding the maximum allowed depth
	EventTypePathDepth SecurityEventType = "path_depth_exceeded"
)

type Static

type Static interface {
	// Has checks if a file exists in the embedded filesystem.
	Has(pathFile string) bool

	// List returns all files under a root path.
	List(rootPath string) ([]string, error)

	// Find opens a file and returns a ReadCloser.
	// The caller is responsible for closing the returned ReadCloser.
	Find(pathFile string) (io.ReadCloser, error)

	// Info returns file information (size, mod time, etc.).
	Info(pathFile string) (os.FileInfo, error)

	// Temp creates a temporary file copy with progress tracking.
	// Useful for large files. See github.com/nabbar/golib/file/progress.
	Temp(pathFile string) (libfpg.Progress, error)

	// Map iterates over all files in the embedded filesystem.
	// The provided function is called for each file.
	Map(func(pathFile string, inf os.FileInfo) error) error

	// UseTempForFileSize sets the size threshold for using temporary files.
	// Files larger than this size will be served via Temp() method.
	UseTempForFileSize(size int64)

	// Monitor returns health monitoring information.
	// See github.com/nabbar/golib/monitor/types for details.
	Monitor(ctx context.Context, cfg montps.Config, vrs libver.Version) (montps.Monitor, error)

	// Get is the main Gin handler function for serving files.
	// It handles all security checks, caching, and file serving.
	Get(c *ginsdk.Context)

	// SendFile sends a file to the client with appropriate headers.
	// This is typically called by Get() but can be used directly.
	SendFile(c *ginsdk.Context, filename string, size int64, isDownload bool, buf io.ReadCloser)

	// Embed router registration interface
	StaticRegister

	// Embed file serving configuration interfaces
	StaticIndex
	StaticDownload
	StaticRedirect
	StaticSpecific

	// Embed security interfaces
	RateLimit
	PathSecurity
	SuspiciousDetection
	HeadersControl
	SecurityBackend
}

Static is the main interface for the static file handler.

It combines all sub-interfaces and provides core file operations. All operations are thread-safe using atomic operations.

The Static handler serves files from an embedded filesystem (embed.FS) with comprehensive security features and HTTP caching support.

See the package documentation for usage examples.

func New added in v1.8.6

func New(ctx context.Context, content embed.FS, embedRootDir ...string) Static

New creates a new Static file handler instance.

Parameters:

  • ctx: Context for lifecycle management
  • content: Embedded filesystem containing static files
  • embedRootDir: Optional root directory paths within the embed.FS

The handler is initialized with:

  • Default logger
  • No security features enabled (must be configured)
  • No rate limiting (must be configured)
  • No index files (must be configured)

Thread Safety:

All internal data structures use atomic operations for thread-safe access without mutexes, ensuring high performance under concurrent load.

Example:

//go:embed assets/*
var content embed.FS

handler := static.New(context.Background(), content, "assets")
handler.SetPathSecurity(static.DefaultPathSecurityConfig())
handler.SetRateLimit(static.RateLimitConfig{
    Enabled:     true,
    MaxRequests: 100,
    Window:      time.Minute,
})

type StaticDownload added in v1.19.0

type StaticDownload interface {
	// SetDownload marks a file to be served as an attachment download.
	SetDownload(pathFile string, flag bool)

	// IsDownload checks if a file is configured to be downloaded.
	IsDownload(pathFile string) bool
}

StaticDownload interface configures files to be served as downloads (with Content-Disposition: attachment header).

This forces the browser to download the file rather than displaying it inline.

type StaticIndex added in v1.19.0

type StaticIndex interface {
	// SetIndex configures an index file for a specific route and group.
	// When a directory is requested, this file will be served instead.
	SetIndex(group, route, pathFile string)

	// GetIndex returns the configured index file for a route and group.
	GetIndex(group, route string) string

	// IsIndex checks if a file is configured as an index file.
	IsIndex(pathFile string) bool

	// IsIndexForRoute checks if a file is the index for a specific route.
	IsIndexForRoute(pathFile, group, route string) bool
}

StaticIndex interface provides index file configuration for directory requests.

Index files (e.g., index.html) are automatically served when a directory is requested, similar to Apache's DirectoryIndex or nginx's index directive.

type StaticRedirect added in v1.19.0

type StaticRedirect interface {
	// SetRedirect configures a redirect from source to destination route.
	// Returns HTTP 301 Permanent Redirect.
	SetRedirect(srcGroup, srcRoute, dstGroup, dstRoute string)

	// GetRedirect returns the destination for a source route.
	GetRedirect(srcGroup, srcRoute string) string

	// IsRedirect checks if a route is configured as a redirect.
	IsRedirect(group, route string) bool
}

StaticRedirect interface provides URL redirection configuration.

This allows redirecting from one path to another, useful for maintaining backward compatibility or organizing file structure.

type StaticRegister added in v1.19.0

type StaticRegister interface {
	// RegisterRouter registers the static handler on a route using the provided register function.
	// The route parameter specifies the URL path (e.g., "/static").
	// Additional middleware can be provided via router parameter.
	RegisterRouter(route string, register librtr.RegisterRouter, router ...ginsdk.HandlerFunc)

	// RegisterRouterInGroup registers the static handler in a router group.
	// This allows organizing routes under common prefixes or middleware.
	RegisterRouterInGroup(route, group string, register librtr.RegisterRouterInGroup, router ...ginsdk.HandlerFunc)

	// RegisterLogger sets the logger instance for the static handler.
	// See github.com/nabbar/golib/logger for logger implementation.
	RegisterLogger(log liblog.Logger)
}

StaticRegister interface provides methods for registering the static file handler with Gin routers and configuring logging.

This interface integrates with github.com/nabbar/golib/router for flexible route registration in both root and group contexts.

type StaticSpecific added in v1.19.0

type StaticSpecific interface {
	// SetSpecific registers a custom handler for a specific route.
	SetSpecific(group, route string, router ginsdk.HandlerFunc)

	// GetSpecific returns the custom handler for a route, if configured.
	GetSpecific(group, route string) ginsdk.HandlerFunc
}

StaticSpecific interface allows overriding the default static file handler with custom handlers for specific routes.

This is useful for adding special processing for certain paths while maintaining the default behavior for others.

type SuspiciousConfig added in v1.19.0

type SuspiciousConfig struct {
	// Enabled activates or deactivates suspicious access detection
	Enabled bool

	// LogSuccessfulAccess also logs suspicious accesses that succeed (200 OK)
	LogSuccessfulAccess bool

	// SuspiciousPatterns are path patterns considered suspicious
	SuspiciousPatterns []string

	// SuspiciousExtensions are file extensions considered suspicious
	SuspiciousExtensions []string
}

SuspiciousConfig configures the detection and logging of suspicious file access patterns.

This feature helps identify potential security threats by monitoring access to files that are commonly targeted in attacks (e.g., .env files, backup files, configuration files).

Example usage:

handler.SetSuspicious(static.SuspiciousConfig{
    Enabled:             true,
    LogSuccessfulAccess: true,
    SuspiciousPatterns:  []string{".env", ".git", "wp-admin"},
    SuspiciousExtensions: []string{".php", ".exe"},
})

func DefaultSuspiciousConfig added in v1.19.0

func DefaultSuspiciousConfig() SuspiciousConfig

DefaultSuspiciousConfig returns a default suspicious access detection configuration.

Default patterns include:

  • Configuration files (.env, .git, wp-config, etc.)
  • Backup files (.bak, .old, .swp, etc.)
  • Admin panels (wp-admin, phpmyadmin, etc.)
  • Sensitive paths (etc/passwd, windows/system32)
  • Database files (.sql, .db)
  • Executable extensions (.php, .exe, .sh)

type SuspiciousDetection added in v1.19.0

type SuspiciousDetection interface {
	// SetSuspicious configures suspicious access detection rules
	SetSuspicious(cfg SuspiciousConfig)

	// GetSuspicious returns the current suspicious detection configuration
	GetSuspicious() SuspiciousConfig
}

SuspiciousDetection interface provides detection and logging of suspicious file access patterns that may indicate security threats.

It monitors access to files commonly targeted in attacks such as:

  • Configuration files (.env, config.php)
  • Backup files (.bak, .old)
  • Admin panels (wp-admin, phpmyadmin)
  • Database files (.sql, .db)

See SuspiciousConfig for configuration options.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL