Files
golib/httpserver/doc.go
nabbar fa8adbe7c8 Package Socket:
- config Server: change time duration to golib duration to simplify
  marshal string form
- adjust test following update of config server
- fix test in socket package to use BDD framework & gherkin form
- adjust documentation & test

Package HTTPServer:
- Fix bug in PortUse & PortNotUse
- Move function PortUse & PortNotUse as alone function
- Add test & documentation
- Unify test & documentation following other packages
2025-12-23 16:27:47 +01:00

655 lines
24 KiB
Go

/*
* MIT License
*
* Copyright (c) 2025 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
// Package httpserver provides production-grade HTTP/HTTPS server management with comprehensive
// lifecycle control, configuration validation, TLS support, and integrated monitoring.
//
// # Overview
//
// This package offers a robust abstraction layer for managing HTTP and HTTPS servers in Go
// applications, emphasizing production readiness through comprehensive lifecycle management,
// declarative configuration with validation, optional TLS/SSL support, handler management,
// and built-in monitoring capabilities.
//
// The package is designed for scenarios requiring multiple server instances, dynamic
// configuration updates, graceful shutdowns, and centralized management through the pool
// subpackage. It extends the standard library's http.Server with additional features while
// maintaining compatibility with existing http.Handler implementations.
//
// # Design Philosophy
//
// The httpserver package follows these core design principles:
//
// 1. Configuration-Driven Architecture: Servers are defined through declarative configuration
// structures that are validated before use, enabling early detection of configuration errors
// and supporting externalized configuration from files, environment variables, or databases.
//
// 2. Lifecycle Management: Complete control over server start, stop, and restart operations
// with context-aware cancellation and graceful shutdown support. Servers can be started,
// stopped, and restarted programmatically with proper resource cleanup.
//
// 3. Thread-Safe Operations: All operations use atomic values and proper synchronization
// primitives, ensuring safe concurrent access from multiple goroutines without external
// locking requirements.
//
// 4. Production-Ready Features: Built-in monitoring integration, structured logging with
// field context, error handling with typed error codes, port conflict detection, and health
// checking capabilities.
//
// 5. Composable Design: The pool subpackage enables orchestration of multiple server instances
// as a unified entity, supporting filtering, batch operations, and aggregated monitoring.
//
// # Key Features
//
// Complete Lifecycle Control:
// - Context-aware Start, Stop, and Restart operations
// - Automatic resource cleanup and graceful shutdown
// - Uptime tracking and running state queries
// - Error tracking and recovery mechanisms
//
// Configuration Management:
// - Declarative configuration with struct tag validation
// - Deep cloning for safe configuration copies
// - Dynamic configuration updates with SetConfig
// - TLS/HTTPS configuration with certificate management
//
// Handler Management:
// - Dynamic handler registration via function callbacks
// - Multiple named handlers per server instance
// - Handler key-based routing for multi-handler scenarios
// - Fallback BadHandler for misconfigured servers
//
// TLS/HTTPS Support:
// - Integrated certificate management
// - Optional and mandatory TLS modes
// - Default TLS configuration inheritance
// - Automatic TLS detection and configuration
//
// Monitoring and Health Checking:
// - Built-in health check endpoints
// - Integration with monitor package
// - Server metrics and status information
// - Unique monitoring identifiers per server
//
// Pool Management (via pool subpackage):
// - Coordinate multiple server instances
// - Unified start/stop/restart operations
// - Advanced filtering by name, address, or URL
// - Configuration-based pool creation
//
// Thread-Safe Operations:
// - Atomic value storage for handlers and state
// - Concurrent access without explicit locking
// - Safe handler replacement during operation
// - Context-based synchronization
//
// Port Management:
// - Automatic port availability checking
// - Conflict detection before binding
// - Retry logic for port conflicts
// - Support for all interface binding (0.0.0.0)
//
// # Architecture
//
// The package consists of three main components working together:
//
// ┌────────────────────────────────────┐
// │ Application Layer │
// │ (HTTP Handlers & Routes) │
// └─────────────────┬──────────────────┘
// │
// ┌─────────▼─────────┐
// │ httpserver │
// │ Package API │
// └─────────┬─────────┘
// │
// ┌─────────────┼──────────────┐
// │ │ │
// ┌───▼───┐ ┌────▼────┐ ┌───▼────┐
// │Server │ │ Pool │ │ Types │
// │ │ │ │ │ │
// │Config │◄───┤ Manager │ │Handler │
// │Run │ │ Filter │ │Fields │
// │Monitor│ │ Clone │ │Const │
// └───┬───┘ └────┬────┘ └────────┘
// │ │
// └──────┬──────┘
// │
// ┌──────▼──────┐
// │ Go stdlib │
// │ http.Server │
// └─────────────┘
//
// Component Responsibilities:
//
// - Server: Core HTTP server implementation with lifecycle management
// - Config: Declarative configuration with validation and cloning
// - Pool: Multi-server orchestration and batch operations
// - Types: Shared type definitions and constants
// - Monitor: Health checking and metrics collection
// - Handler: Dynamic handler registration and management
//
// Data Flow:
// 1. Configuration is created and validated
// 2. Handlers are registered via function callbacks
// 3. Server instance is created from configuration
// 4. Start operation binds to port and begins serving
// 5. Handlers process incoming HTTP requests
// 6. Monitoring tracks health and metrics
// 7. Stop operation gracefully shuts down with timeout
//
// # Thread Safety Architecture
//
// The package uses multiple synchronization mechanisms for thread safety:
//
// Component | Mechanism | Concurrency Model
// --------------------|---------------------|----------------------------------
// Server State | atomic.Value | Lock-free reads, atomic writes
// Handler Registry | atomic.Value | Lock-free handler swapping
// Logger | atomic.Value | Thread-safe logging
// Runner | atomic.Value | Lifecycle synchronization
// Config Storage | context.Config | Context-based atomic storage
// Pool Map | sync.RWMutex | Multiple readers, exclusive writes
//
// All public methods are safe for concurrent use from multiple goroutines without
// external synchronization. Internal state updates use atomic operations to prevent
// data races.
//
// # Basic Usage
//
// Creating and starting a simple HTTP server:
//
// cfg := httpserver.Config{
// Name: "api-server",
// Listen: "127.0.0.1:8080",
// Expose: "http://localhost:8080",
// }
//
// cfg.RegisterHandlerFunc(func() map[string]http.Handler {
// mux := http.NewServeMux()
// mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
// w.WriteHeader(http.StatusOK)
// w.Write([]byte("OK"))
// })
// return map[string]http.Handler{"": mux}
// })
//
// if err := cfg.Validate(); err != nil {
// log.Fatal(err)
// }
//
// srv, err := httpserver.New(cfg, nil)
// if err != nil {
// log.Fatal(err)
// }
//
// ctx := context.Background()
// if err := srv.Start(ctx); err != nil {
// log.Fatal(err)
// }
// defer srv.Stop(ctx)
//
// # Configuration
//
// The Config structure defines all server parameters:
//
// type Config struct {
// Name string // Server identifier (required)
// Listen string // Bind address host:port (required)
// Expose string // Public URL (required)
// HandlerKey string // Handler map key (optional)
// Disabled bool // Disable flag for maintenance
// Monitor moncfg.Config // Monitoring configuration
// TLSMandatory bool // Require valid TLS
// TLS libtls.Config // TLS/certificate configuration
// ReadTimeout libdur.Duration // Request read timeout
// ReadHeaderTimeout libdur.Duration // Header read timeout
// WriteTimeout libdur.Duration // Response write timeout
// MaxHeaderBytes int // Maximum header size
// // ... HTTP/2 configuration fields ...
// }
//
// Configuration Validation:
//
// All configurations must pass validation before server creation:
// - Name: Must be non-empty string
// - Listen: Must be valid hostname:port format
// - Expose: Must be valid URL with scheme
// - TLS: Must be valid if TLSMandatory is true
//
// Configuration Methods:
// - Validate(): Comprehensive validation with detailed errors
// - Clone(): Deep copy of configuration
// - RegisterHandlerFunc(): Set handler function
// - SetDefaultTLS(): Set default TLS provider
// - SetContext(): Set parent context provider
// - Server(): Create server instance from config
//
// # Handler Management
//
// Handlers are registered via callback functions returning handler maps:
//
// handlerFunc := func() map[string]http.Handler {
// return map[string]http.Handler{
// "": defaultHandler, // Default handler
// "api": apiHandler, // Named handler for API
// "admin": adminHandler, // Named handler for admin
// }
// }
//
// cfg.RegisterHandlerFunc(handlerFunc)
//
// Handler Keys:
//
// The HandlerKey configuration field selects which handler from the map to use:
// - Empty string or "": Uses default handler
// - "api": Uses handler registered with "api" key
// - Custom keys: Application-specific handler selection
//
// Multiple servers can share the same handler function but use different keys
// to serve different handlers on different ports.
//
// # TLS/HTTPS Configuration
//
// Servers support optional and mandatory TLS/SSL:
//
// cfg := httpserver.Config{
// Name: "secure-api",
// Listen: "0.0.0.0:8443",
// Expose: "https://api.example.com",
// TLSMandatory: true,
// TLS: libtls.Config{
// CertPEM: "/path/to/cert.pem",
// KeyPEM: "/path/to/key.pem",
// // Additional TLS options...
// },
// }
//
// TLS Modes:
//
// - TLSMandatory = false: TLS is optional, server starts without certificates
// - TLSMandatory = true: Valid TLS config required, server fails to start without it
//
// TLS Configuration Inheritance:
//
// Servers can inherit from a default TLS configuration:
//
// cfg.SetDefaultTLS(func() libtls.TLSConfig {
// return defaultTLSConfig
// })
// cfg.TLS.InheritDefault = true
//
// # Lifecycle Management
//
// Servers implement the libsrv.Runner interface for lifecycle control:
//
// // Start server
// err := srv.Start(ctx)
// if err != nil {
// log.Fatal(err)
// }
//
// // Check if running
// if srv.IsRunning() {
// log.Println("Server is running")
// }
//
// // Get uptime
// uptime := srv.Uptime()
// log.Printf("Server uptime: %v", uptime)
//
// // Stop gracefully
// ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
// defer cancel()
// err = srv.Stop(ctx)
//
// // Restart (stop then start)
// err = srv.Restart(ctx)
//
// Graceful Shutdown:
//
// The Stop method performs graceful shutdown:
// 1. Stops accepting new connections
// 2. Waits for active requests to complete (up to timeout)
// 3. Closes server resources and listeners
// 4. Returns error if shutdown exceeds timeout
//
// # Server Information
//
// Servers provide read-only access to configuration and state:
//
// name := srv.GetName() // Server identifier
// bind := srv.GetBindable() // Listen address
// expose := srv.GetExpose() // Public URL
// disabled := srv.IsDisable() // Disabled flag
// hasTLS := srv.IsTLS() // TLS enabled check
// cfg := srv.GetConfig() // Full configuration
//
// # Monitoring and Health Checking
//
// Servers integrate with the monitor package for health checks and metrics:
//
// // Get monitoring identifier
// monitorName := srv.MonitorName()
//
// // Get monitor with health checks and metrics
// monitor, err := srv.Monitor(versionInfo)
// if err != nil {
// log.Printf("Monitor error: %v", err)
// }
//
// Health checks verify:
// - Server is running (runner state check)
// - Port is bound and accepting connections
// - No fatal errors in server operation
// - TCP connection can be established to bind address
//
// Monitor provides:
// - Health check status and last error
// - Server configuration and runtime information
// - Uptime and running state
// - Custom metrics from monitoring configuration
//
// # Port Management
//
// The package includes port conflict detection and resolution:
//
// // Check if port is available
// err := httpserver.PortNotUse(ctx, "127.0.0.1:8080")
// if err == nil {
// // Port is available
// }
//
// // Check if port is in use
// err = httpserver.PortInUse(ctx, "127.0.0.1:8080")
// if err == nil {
// // Port is in use
// }
//
// Automatic Port Conflict Handling:
//
// Servers automatically check for port conflicts before binding:
// - Retries up to 5 times with delays
// - Returns ErrorPortUse if port remains unavailable
// - Configurable retry count via RunIfPortInUse
//
// # Error Handling
//
// The package defines typed errors with diagnostic codes:
//
// Error Code | Description
// -----------------------|------------------------------------------
// ErrorParamEmpty | Required parameter missing
// ErrorInvalidInstance | Invalid server instance
// ErrorHTTP2Configure | HTTP/2 configuration failed
// ErrorServerValidate | Configuration validation failed
// ErrorServerStart | Server failed to start or listen
// ErrorInvalidAddress | Bind address format invalid
// ErrorPortUse | Port is already in use
//
// Error checking:
//
// if err := srv.Start(ctx); err != nil {
// var liberr errors.Error
// if errors.As(err, &liberr) {
// switch liberr.Code() {
// case httpserver.ErrorPortUse:
// log.Println("Port already in use")
// case httpserver.ErrorServerValidate:
// log.Println("Invalid configuration")
// default:
// log.Printf("Server error: %v", err)
// }
// }
// }
//
// # Performance Characteristics
//
// Server Operations:
//
// Operation | Time | Memory | Notes
// ------------------------|--------------|-----------|------------------------
// Config Validation | ~100ns | O(1) | Field validation only
// Server Creation | <1ms | ~5KB | Includes initialization
// Start Server | 1-5ms | ~10KB | Port binding overhead
// Stop Server (graceful) | <5s | O(1) | Default timeout
// Handler Execution | Variable | Variable | Depends on handler
// Info Methods | <100ns | O(1) | Atomic reads
// Configuration Update | <1ms | O(1) | Validation + atomic swap
//
// Throughput:
// - HTTP Requests: Limited by Go's http.Server (~50k+ req/s typical)
// - HTTPS/TLS: ~20-30k req/s depending on cipher suite and hardware
// - Overhead: Minimal (<1% vs standard http.Server)
//
// Memory Usage:
// - Single Server: ~10-15KB baseline + handler memory
// - With Monitoring: +5KB per server
// - Pool Overhead: ~1KB per server in pool
//
// Scalability:
// - Supports hundreds of server instances per process
// - Linear memory growth with server count
// - No global locks on request path
//
// # Use Cases
//
// ## Microservices Architecture
//
// Run multiple API versions simultaneously:
//
// // API v1 on port 8080
// cfgV1 := httpserver.Config{
// Name: "api-v1",
// Listen: "0.0.0.0:8080",
// Expose: "http://api.example.com/v1",
// HandlerKey: "v1",
// }
//
// // API v2 on port 8081
// cfgV2 := httpserver.Config{
// Name: "api-v2",
// Listen: "0.0.0.0:8081",
// Expose: "http://api.example.com/v2",
// HandlerKey: "v2",
// }
//
// ## Multi-Tenant Systems
//
// Dedicated server per tenant with isolated configuration:
//
// for _, tenant := range tenants {
// cfg := httpserver.Config{
// Name: tenant.ID,
// Listen: fmt.Sprintf("0.0.0.0:%d", tenant.Port),
// Expose: tenant.Domain,
// TLS: tenant.TLSConfig,
// }
// srv, _ := httpserver.New(cfg, nil)
// srv.Start(ctx)
// }
//
// ## Development and Testing
//
// Dynamic server creation for integration tests:
//
// func TestAPI(t *testing.T) {
// port := getFreePort()
// cfg := httpserver.Config{
// Name: "test-server",
// Listen: fmt.Sprintf("127.0.0.1:%d", port),
// Expose: fmt.Sprintf("http://localhost:%d", port),
// }
// cfg.RegisterHandlerFunc(testHandler)
// srv, _ := httpserver.New(cfg, nil)
// srv.Start(context.Background())
// defer srv.Stop(context.Background())
// // Run tests...
// }
//
// ## API Gateway
//
// Route traffic to multiple backend servers:
//
// pool := pool.New(nil, gatewayHandler)
// for _, backend := range backends {
// cfg := httpserver.Config{
// Name: backend.Name,
// Listen: backend.Address,
// Expose: backend.URL,
// }
// pool.StoreNew(cfg, nil)
// }
// pool.Start(ctx)
//
// ## Production Deployments
//
// Graceful shutdown during rolling updates:
//
// // Handle SIGTERM for graceful shutdown
// sigChan := make(chan os.Signal, 1)
// signal.Notify(sigChan, syscall.SIGTERM)
// go func() {
// <-sigChan
// ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
// defer cancel()
// if err := srv.Stop(ctx); err != nil {
// log.Printf("Shutdown error: %v", err)
// }
// }()
//
// # Limitations
//
// 1. Handler Replacement During Operation: Handlers can be replaced while the server
// is running, but active requests continue using the previous handler. New requests
// use the updated handler. This may cause inconsistent behavior during handler updates.
//
// 2. TLS Certificate Rotation: Updating TLS certificates requires server restart.
// The SetConfig method does not apply TLS changes to running servers.
//
// 3. Port Binding Limitations: Cannot bind to privileged ports (<1024) without
// appropriate system permissions (CAP_NET_BIND_SERVICE on Linux or root access).
//
// 4. Listen Address Changes: Changing the Listen address via SetConfig requires
// a server restart to take effect. The new address is not applied to running servers.
//
// 5. HTTP/2 Configuration: HTTP/2 settings cannot be changed after server creation
// without recreating the server instance.
//
// 6. Concurrent Stop Calls: Multiple concurrent Stop calls may result in redundant
// shutdown attempts. Use external synchronization if multiple goroutines may call Stop.
//
// 7. Context Cancellation: Server operations respect context cancellation, but
// forcefully cancelled contexts (e.g., exceeded deadline during graceful shutdown)
// may result in abrupt connection termination.
//
// 8. Monitoring Overhead: Each server maintains monitoring state. For deployments
// with hundreds of servers, consider disabling monitoring for non-critical instances.
//
// # Best Practices
//
// DO:
// - Always validate configuration before creating servers
// - Use context.WithTimeout for Stop operations to prevent hanging
// - Register handlers before calling New() when possible
// - Use defer srv.Stop(ctx) to ensure cleanup
// - Check IsRunning() before calling Stop to avoid errors
// - Set appropriate timeouts (ReadTimeout, WriteTimeout, IdleTimeout)
// - Use the pool subpackage for managing multiple servers
// - Monitor server health in production deployments
// - Use unique server names for debugging and monitoring
//
// DON'T:
// - Don't create servers without validating configuration
// - Don't ignore errors from Start, Stop, or SetConfig
// - Don't assume port availability without checking
// - Don't call Stop without context timeout
// - Don't modify Config after passing to New() (use Clone first)
// - Don't rely on handler updates to active connections
// - Don't bind to 0.0.0.0 without considering security implications
// - Don't start servers in goroutines without proper error handling
//
// # Integration with Standard Library
//
// The package integrates seamlessly with Go's standard library:
//
// Standard Library | Integration Point
// -------------------------|------------------------------------------
// net/http.Server | Wrapped and managed by this package
// net/http.Handler | Compatible with all standard handlers
// context.Context | Used throughout for cancellation
// net.Listener | Managed internally for binding
// crypto/tls | TLS configuration via certificates package
//
// # Related Packages
//
// This package works with other golib packages:
//
// - github.com/nabbar/golib/httpserver/pool: Multi-server orchestration
// - github.com/nabbar/golib/httpserver/types: Shared type definitions
// - github.com/nabbar/golib/certificates: TLS/SSL certificate management
// - github.com/nabbar/golib/monitor: Health checking and metrics
// - github.com/nabbar/golib/logger: Structured logging integration
// - github.com/nabbar/golib/runner: Lifecycle management primitives
// - github.com/nabbar/golib/context: Typed context storage
//
// External Dependencies:
//
// - github.com/go-playground/validator/v10: Configuration validation
// - golang.org/x/net/http2: HTTP/2 support
//
// # Testing
//
// The package includes comprehensive testing using Ginkgo v2 and Gomega:
//
// - Configuration validation tests
// - Server lifecycle tests (start, stop, restart)
// - Handler management tests
// - Monitoring integration tests
// - Concurrency and race detection tests
// - Integration tests with actual HTTP servers
//
// Run tests:
//
// go test -v ./...
// go test -race -v ./...
// go test -cover -v ./...
//
// For detailed testing documentation, see TESTING.md in the package directory.
//
// # Examples
//
// See example_test.go for comprehensive usage examples covering:
// - Basic HTTP server creation and lifecycle
// - HTTPS server with TLS configuration
// - Multiple handlers with handler keys
// - Server pool management
// - Dynamic configuration updates
// - Graceful shutdown patterns
// - Monitoring integration
// - Error handling strategies
package httpserver