- handler/static.go: add sync.RWMutex to StaticHandler; protect Handle
with RLock and all setters with Lock to prevent data races
- http2/server.go: delete empty connection slice keys from pool map to
prevent memory leak under high client churn
- loadbalance/slow_start.go: recreate stopCh in Start() to support
Start-Stop-Start cycles; guard double-close in Stop()
- resolver/resolver.go: recreate stopCh in Start() to support restart
- logging/logging.go: save *os.File handles from getOutput so Close()
actually closes log files; exclude os.Stdout/os.Stderr from closing
- ssl/session_tickets.go: protect started/rotateTimer access in
scheduleRotation with mu; support Start-Stop-Start cycles
- ssl/ssl.go: cache parsed default certificate to avoid re-parsing on
every TLS handshake for OCSP stapling
- compression: move sync.Pool.New initialization into constructors to
eliminate lazy-init race in Get()
- ssl/ocsp: copy response fields under RLock before releasing, preventing
race with concurrent writers in refreshAll
- server: change proxiesMu from sync.Mutex to sync.RWMutex; protect
getProxyCacheStats and purge handlers with RLock to prevent races
with proxy registration
- lua/api_timer: fix double-decrement race in Cancel vs executeTimer
by using timer.Stop() result to determine who decrements active
- lua/api_socket_tcp: fix nil pointer race in ConnectAsync by checking
currentOp under lock before Connect returns
Replace manual PEM text scanning with pem.Decode(). Returns proper
DER-encoded bytes instead of raw PEM text, fixing potential TLS
handshake failures with certificate chains.
Remove unused findMarker and matchMarker helpers.
refreshAll() was a no-op — it checked which entries needed refreshing
but never called fetchOCSP. Now it:
- Stores cert/issuer pairs when registering certificates
- Actually fetches fresh OCSP responses for stale/expired entries
- Updates error counts and marks entries as failed after max retries
The previous code used defer resp.Body.Close() inside a for loop,
causing all response bodies to remain open until the function returned.
Extract the per-attempt logic into singleOCSPAttempt so each response
body is closed immediately after processing.
Use 198.18.0.1 (IANA reserved benchmark address) instead of
127.0.0.1:9999 to ensure reliable connection failure in tests.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Apply modern Go patterns across the codebase:
- Replace `interface{}` with `any` (Go 1.18+)
- Use `for range n` instead of `for i := 0; i < n; i++` (Go 1.22+)
- Replace `sort.Slice` with `slices.Sort` from slices package
- Simplify sync.WaitGroup patterns with errgroup where appropriate
- Add Makefile targets for modernize analyzer
Total: 84 files updated, net reduction of 79 lines
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- ConsistentHash: reuse main hash ring in SelectExcludingByKey instead of
rebuilding per call, reducing memory allocation from 369KB to 1.8KB (99.5%)
- RateLimiter: replace single RWMutex with 16-segment sharded locks to
reduce lock contention in high-concurrency scenarios
- TLS SessionTickets: add warning log when KeyFile is empty to alert
users about session invalidation after restart
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 所有 *_bench_test.go 文件从 for i := 0; i < b.N; i++ 改为 for b.Loop()
- 部分测试文件从 for i := 0; i < N; ... 改为 for range N 或 for i := range N
- 涵盖模块: cache, handler, http2, http3, loadbalance, logging, lua,
middleware/accesslog, middleware/bodylimit, middleware/rewrite,
middleware/security, netutil, resolver, server, ssl, stream
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Conflict: sendfile.go (!linux build tag) was incorrectly modified to
include linuxSendfile and getSocketFd functions which already exist
in sendfile_linux.go.
Resolution: Keep HEAD version (simple fallback returning ENOTSUP) as
Linux implementation is properly separated in sendfile_linux.go.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>