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 ¶
- 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 ¶
MIT License - Copyright (c) 2022 Nicolas JUHEL ¶
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 ¶
- Constants
- type HeadersConfig
- type HeadersControl
- type PathSecurity
- type PathSecurityConfig
- type RateLimit
- type RateLimitConfig
- type SecuEvtCallback
- type SecurityBackend
- type SecurityConfig
- type SecurityEventType
- type Static
- type StaticDownload
- type StaticIndex
- type StaticRedirect
- type StaticRegister
- type StaticSpecific
- type SuspiciousConfig
- type SuspiciousDetection
Examples ¶
- Package (ApiAssets)
- Package (Basic)
- Package (Cdn)
- Package (Development)
- Package (DownloadFiles)
- Package (FileOperations)
- Package (HttpCaching)
- Package (IndexFiles)
- Package (MimeTypeValidation)
- Package (PathSecurity)
- Package (Production)
- Package (RateLimit)
- Package (Redirects)
- Package (SecurityBackend)
- Package (SecurityBackendBatch)
- Package (SecurityBackendCEF)
- Package (SuspiciousDetection)
Constants ¶
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
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.