316 lines
18 KiB
Markdown
316 lines
18 KiB
Markdown
|
|
# Middleware Chain Diagram
|
||
|
|
|
||
|
|
## Middleware Execution Order
|
||
|
|
|
||
|
|
```
|
||
|
|
HTTP Request
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌────────────────────────────────────────────────────────────┐
|
||
|
|
│ MIDDLEWARE CHAIN │
|
||
|
|
│ │
|
||
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
||
|
|
│ │ 1. Recovery Middleware │ │
|
||
|
|
│ │ - Catches panics │ │
|
||
|
|
│ │ - Logs stack trace │ │
|
||
|
|
│ │ - Returns 500 error │ │
|
||
|
|
│ └──────────────────────────────────────────────────────┘ │
|
||
|
|
│ │ │
|
||
|
|
│ ▼ │
|
||
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
||
|
|
│ │ 2. Logger Middleware │ │
|
||
|
|
│ │ - Logs request method, path, IP │ │
|
||
|
|
│ │ - Measures request duration │ │
|
||
|
|
│ │ - Logs response status │ │
|
||
|
|
│ └──────────────────────────────────────────────────────┘ │
|
||
|
|
│ │ │
|
||
|
|
│ ▼ │
|
||
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
||
|
|
│ │ 3. SecurityHeaders Middleware │ │
|
||
|
|
│ │ - Sets CSP header │ │
|
||
|
|
│ │ - Sets X-Frame-Options │ │
|
||
|
|
│ │ - Sets X-Content-Type-Options │ │
|
||
|
|
│ │ - Sets Referrer-Policy │ │
|
||
|
|
│ └──────────────────────────────────────────────────────┘ │
|
||
|
|
│ │ │
|
||
|
|
│ ▼ │
|
||
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
||
|
|
│ │ 4. PreferencesMiddleware │ │
|
||
|
|
│ │ - Reads preference cookies │ │
|
||
|
|
│ │ - Migrates old values │ │
|
||
|
|
│ │ - Stores in request context │ │
|
||
|
|
│ └──────────────────────────────────────────────────────┘ │
|
||
|
|
│ │ │
|
||
|
|
└───────────────────────────┼────────────────────────────────┘
|
||
|
|
▼
|
||
|
|
┌───────────────┐
|
||
|
|
│ Router │
|
||
|
|
│ (ServeMux) │
|
||
|
|
└───────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌───────────────┐
|
||
|
|
│ Handler │
|
||
|
|
└───────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
## Detailed Flow
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
||
|
|
│ Request Processing Flow │
|
||
|
|
└─────────────────────────────────────────────────────────────────┘
|
||
|
|
|
||
|
|
Client Request: GET /?lang=es
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
╔═══════════════════════════════════════════════════════════╗
|
||
|
|
║ RECOVERY MIDDLEWARE ║
|
||
|
|
╠═══════════════════════════════════════════════════════════╣
|
||
|
|
║ defer func() { ║
|
||
|
|
║ if err := recover(); err != nil { ║
|
||
|
|
║ log error + stack trace ║
|
||
|
|
║ http.Error(w, "Internal Server Error", 500) ║
|
||
|
|
║ } ║
|
||
|
|
║ }() ║
|
||
|
|
║ ║
|
||
|
|
║ next.ServeHTTP(w, r) ────────────────┐ ║
|
||
|
|
╚════════════════════════════════════════│══════════════════╝
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
╔═══════════════════════════════════════════════════════════╗
|
||
|
|
║ LOGGER MIDDLEWARE ║
|
||
|
|
╠═══════════════════════════════════════════════════════════╣
|
||
|
|
║ start := time.Now() ║
|
||
|
|
║ log.Printf("[%s] %s %s", r.Method, r.URL.Path, r.RemoteAddr) ║
|
||
|
|
║ ║
|
||
|
|
║ wrapped := responseWriter wrapper ║
|
||
|
|
║ next.ServeHTTP(wrapped, r) ──────────┐ ║
|
||
|
|
║ │ ║
|
||
|
|
║ duration := time.Since(start) │ ║
|
||
|
|
║ log.Printf("Completed in %v (status: %d)", duration, status) ║
|
||
|
|
╚═════════════════════════════════════════│════════════════╝
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
╔═══════════════════════════════════════════════════════════╗
|
||
|
|
║ SECURITY HEADERS MIDDLEWARE ║
|
||
|
|
╠═══════════════════════════════════════════════════════════╣
|
||
|
|
║ w.Header().Set("Content-Security-Policy", CSP_POLICY) ║
|
||
|
|
║ w.Header().Set("X-Frame-Options", "DENY") ║
|
||
|
|
║ w.Header().Set("X-Content-Type-Options", "nosniff") ║
|
||
|
|
║ w.Header().Set("Referrer-Policy", "strict-origin") ║
|
||
|
|
║ ║
|
||
|
|
║ next.ServeHTTP(w, r) ────────────────┐ ║
|
||
|
|
╚════════════════════════════════════════│══════════════════╝
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
╔═══════════════════════════════════════════════════════════╗
|
||
|
|
║ PREFERENCES MIDDLEWARE ║
|
||
|
|
╠═══════════════════════════════════════════════════════════╣
|
||
|
|
║ // Read cookies ║
|
||
|
|
║ prefs := &Preferences{ ║
|
||
|
|
║ CVLength: getCookie(r, "cv-length", "short"), ║
|
||
|
|
║ CVIcons: getCookie(r, "cv-icons", "show"), ║
|
||
|
|
║ CVLanguage: getCookie(r, "cv-language", "en"), ║
|
||
|
|
║ CVTheme: getCookie(r, "cv-theme", "default"), ║
|
||
|
|
║ ColorTheme: getCookie(r, "color-theme", "light"), ║
|
||
|
|
║ } ║
|
||
|
|
║ ║
|
||
|
|
║ // Migrate old values ║
|
||
|
|
║ if prefs.CVLength == "extended" { ║
|
||
|
|
║ prefs.CVLength = "long" ║
|
||
|
|
║ } ║
|
||
|
|
║ ║
|
||
|
|
║ // Store in context ║
|
||
|
|
║ ctx := context.WithValue(r.Context(), PreferencesKey, prefs) ║
|
||
|
|
║ next.ServeHTTP(w, r.WithContext(ctx)) ───┐ ║
|
||
|
|
╚═════════════════════════════════════════════│════════════╝
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌──────────────────┐
|
||
|
|
│ ROUTER HANDLER │
|
||
|
|
│ │
|
||
|
|
│ Matches route │
|
||
|
|
│ Calls handler │
|
||
|
|
└──────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌──────────────────┐
|
||
|
|
│ HANDLER FUNC │
|
||
|
|
│ │
|
||
|
|
│ Processes req │
|
||
|
|
│ Returns resp │
|
||
|
|
└──────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
## Route-Specific Middleware
|
||
|
|
|
||
|
|
```
|
||
|
|
┌────────────────────────────────────────────────────────────────┐
|
||
|
|
│ Route-Specific Middleware Example │
|
||
|
|
│ (PDF Export Endpoint) │
|
||
|
|
└────────────────────────────────────────────────────────────────┘
|
||
|
|
|
||
|
|
Global Middleware Chain (all routes)
|
||
|
|
│
|
||
|
|
├─ Recovery
|
||
|
|
├─ Logger
|
||
|
|
├─ SecurityHeaders
|
||
|
|
└─ PreferencesMiddleware
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────────┐
|
||
|
|
│ Router (ServeMux) │
|
||
|
|
│ │
|
||
|
|
│ /export/pdf → pdfHandler (protected) │
|
||
|
|
│ │ │
|
||
|
|
│ ▼ │
|
||
|
|
│ ┌───────────────────────────┐ │
|
||
|
|
│ │ Route-Specific Chain │ │
|
||
|
|
│ │ │ │
|
||
|
|
│ │ 1. OriginChecker │ │
|
||
|
|
│ │ └─ Verify same origin│ │
|
||
|
|
│ │ │ │
|
||
|
|
│ │ 2. RateLimiter │ │
|
||
|
|
│ │ └─ 3 req/min per IP │ │
|
||
|
|
│ │ │ │
|
||
|
|
│ │ 3. ExportPDF Handler │ │
|
||
|
|
│ │ └─ Generate PDF │ │
|
||
|
|
│ └───────────────────────────┘ │
|
||
|
|
└─────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
## Middleware Wrapping Pattern
|
||
|
|
|
||
|
|
```go
|
||
|
|
// Middleware function signature
|
||
|
|
type Middleware func(http.Handler) http.Handler
|
||
|
|
|
||
|
|
// Wrapping example
|
||
|
|
handler := routes.Setup(cvHandler, healthHandler)
|
||
|
|
// Returns:
|
||
|
|
// Recovery(
|
||
|
|
// Logger(
|
||
|
|
// SecurityHeaders(
|
||
|
|
// PreferencesMiddleware(mux)
|
||
|
|
// )
|
||
|
|
// )
|
||
|
|
// )
|
||
|
|
|
||
|
|
// Execution flow (unwraps from outside to inside):
|
||
|
|
Request
|
||
|
|
↓ enters Recovery
|
||
|
|
↓ enters Logger
|
||
|
|
↓ enters SecurityHeaders
|
||
|
|
↓ enters PreferencesMiddleware
|
||
|
|
↓ enters mux/handler
|
||
|
|
↓ handler processes
|
||
|
|
↑ exits PreferencesMiddleware
|
||
|
|
↑ exits SecurityHeaders
|
||
|
|
↑ exits Logger (logs duration)
|
||
|
|
↑ exits Recovery
|
||
|
|
↑
|
||
|
|
Response
|
||
|
|
```
|
||
|
|
|
||
|
|
## Context Flow
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────────┐
|
||
|
|
│ Context Values Through Middleware │
|
||
|
|
└─────────────────────────────────────────────────────────────┘
|
||
|
|
|
||
|
|
Initial Request Context
|
||
|
|
│
|
||
|
|
├─ Empty context.Background()
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
PreferencesMiddleware
|
||
|
|
│
|
||
|
|
├─ Reads cookies
|
||
|
|
├─ Creates Preferences struct
|
||
|
|
└─ Adds to context
|
||
|
|
│
|
||
|
|
└─→ ctx = context.WithValue(r.Context(), PreferencesKey, prefs)
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌──────────────────────────────────────┐
|
||
|
|
│ Modified Request Context │
|
||
|
|
│ │
|
||
|
|
│ PreferencesKey → &Preferences{ │
|
||
|
|
│ CVLength: "long", │
|
||
|
|
│ CVIcons: "show", │
|
||
|
|
│ CVLanguage: "es", │
|
||
|
|
│ CVTheme: "default", │
|
||
|
|
│ ColorTheme: "light", │
|
||
|
|
│ } │
|
||
|
|
└──────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
Handler receives request with enriched context
|
||
|
|
│
|
||
|
|
├─→ prefs := middleware.GetPreferences(r)
|
||
|
|
│ // Retrieves from context
|
||
|
|
│
|
||
|
|
└─→ lang := middleware.GetLanguage(r)
|
||
|
|
// Helper that calls GetPreferences
|
||
|
|
```
|
||
|
|
|
||
|
|
## Error Handling in Middleware
|
||
|
|
|
||
|
|
```
|
||
|
|
┌────────────────────────────────────────────────────────────┐
|
||
|
|
│ Error Handling Flow │
|
||
|
|
└────────────────────────────────────────────────────────────┘
|
||
|
|
|
||
|
|
Recovery Middleware
|
||
|
|
│
|
||
|
|
│ Normal Flow:
|
||
|
|
│ ┌─────────────────────────────────────┐
|
||
|
|
│ │ next.ServeHTTP(w, r) │
|
||
|
|
│ │ ↓ │
|
||
|
|
│ │ Handler processes successfully │
|
||
|
|
│ │ ↓ │
|
||
|
|
│ │ Returns response │
|
||
|
|
│ └─────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
│ Panic Flow:
|
||
|
|
│ ┌─────────────────────────────────────┐
|
||
|
|
│ │ next.ServeHTTP(w, r) │
|
||
|
|
│ │ ↓ │
|
||
|
|
│ │ Handler panics! │
|
||
|
|
│ │ ↓ │
|
||
|
|
│ │ defer recover() catches it │
|
||
|
|
│ │ ↓ │
|
||
|
|
│ │ log.Printf("PANIC: %v\\n%s", │
|
||
|
|
│ │ err, debug.Stack()) │
|
||
|
|
│ │ ↓ │
|
||
|
|
│ │ http.Error(w, "Internal Error", 500)│
|
||
|
|
│ └─────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
Response to client
|
||
|
|
```
|
||
|
|
|
||
|
|
## Performance Characteristics
|
||
|
|
|
||
|
|
```
|
||
|
|
Middleware Performance Impact (per request):
|
||
|
|
|
||
|
|
Recovery: ~10 ns (defer overhead)
|
||
|
|
Logger: ~100 μs (time measurements, string formatting)
|
||
|
|
SecurityHeaders: ~50 ns (header setting)
|
||
|
|
Preferences: ~200 μs (cookie parsing, context creation)
|
||
|
|
|
||
|
|
Total overhead: ~350 μs per request
|
||
|
|
Handler time: ~1-5 ms (template rendering)
|
||
|
|
|
||
|
|
Total request: ~1.5-5.5 ms
|
||
|
|
```
|
||
|
|
|
||
|
|
## Related Diagrams
|
||
|
|
|
||
|
|
- [System Architecture](./01-system-architecture.md) - Overall system design
|
||
|
|
- [Request Flow](./02-request-flow.md) - Complete HTTP request lifecycle
|
||
|
|
- [Error Handling](./06-error-handling-flow.md) - Error propagation
|