FileInfoCache.Get previously acquired TWO locks on every cache hit:
1. RLock → check existence + TTL
2. Release RLock → Lock → MoveToFront (LRU update) → Unlock
The MoveToFront on every hit forced a read-to-write lock upgrade,
creating contention under concurrent reads.
Apply approximate LRU: skip MoveToFront on Get (read) path entirely.
LRU position is only updated in Set (write) path. This is the same
pattern already used by internal/cache/file_cache.go.
Result: Get fast path reduced from 2 lock acquisitions to 1 RLock.
TTL-expired entries still use double-check locking for safe removal.
Extract duplicate path processing logic from handleTryFiles,
handleInternalRedirect, and handleStandard into two new methods:
- stripPathPrefix(): zero-allocation path prefix stripping
- buildFilePath(): build full file path supporting alias/root modes
This reduces code duplication and makes the path handling logic
easier to maintain.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Extract duplicate generateETag function from handler/static.go and
cache/file_cache.go into internal/utils/etag.go. Both functions were
identical, using strconv.AppendInt for zero-allocation ETag generation.
- Create utils.GenerateETag(modTime, size) as the unified implementation
- Update handler/static.go to call utils.GenerateETag
- Update cache/file_cache.go to call utils.GenerateETag
- Remove unused strconv import from static.go
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Use fmt.Fprintf directly on buffer instead of buf.WriteString(fmt.Sprintf(...)),
handle dir.Close error in defer, use blank identifier for unused parameter,
use range-over-int, and remove trailing blank line.
💘 Generated with Crush
Assisted-by: GLM 5.1 via Crush <crush@charm.land>
- Change FileInfoCache.mu from sync.Mutex to sync.RWMutex
- Get method uses RLock for concurrent read access
- Stats method uses RLock for read-only operation
- Double-check pattern for lock upgrades (TTL expiry, LRU move)
This improves concurrent read performance for the FileInfo cache,
which is read-heavy in static file serving scenarios.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add ContentType field to FileEntry struct
- Update Set method signature to accept contentType parameter
- Use cached ContentType in static.go cache hit branches
- Update all test files to use new Set signature
This avoids redundant MIME type detection on cache hits,
reducing lock contention in mimeutil.DetectContentType.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Use entry.ETag instead of generateETag() in cache hit branches
- Add 304 response check before returning cached data
- Reduces ETag computation overhead for cached files
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Check fileInfoCache before os.Stat in handleTryFiles
- Check fileInfoCache before os.Stat in handleInternalRedirect
- Reduces system calls for try_files scenarios
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Replace custom escape functions with stdlib html.EscapeString and url.PathEscape
- Fix benchmark test file naming using fmt.Sprintf
- Add CSP security header for HTML output
- Add empty directory test case
- Remove obsolete escape function tests
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add nginx-like autoindex functionality with three output formats:
- HTML: styled directory listing with sortable columns
- JSON: structured API-friendly output
- XML: machine-readable format
Configuration options:
- auto_index: enable/disable directory listing
- auto_index_format: output format (html/json/xml)
- auto_index_localtime: use local time instead of GMT
- auto_index_exact_size: show exact bytes vs human-readable
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add nolint comments for sync.Pool.Get() type assertions (pool always returns valid pointers)
- Extract TLS version strings to constants in sslutil/tlsconfig.go
- Extract expires directive strings to constants in handler/static.go
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When root is configured as a relative path (e.g., "./lib/site/"),
filepath.Join normalizes it to "lib/site/" but the original value
was stored in h.root. This caused strings.TrimPrefix in serveFile
to fail, resulting in incorrect path calculations for GzipStatic.
The bug caused every request to attempt opening a non-existent
precompressed file path like "lib/site/lib/site/index.html.gz",
adding an extra failed os.Stat call per request and reducing
performance by ~50%.
Fix by normalizing root with filepath.Clean in NewStaticHandler
and SetRoot to ensure TrimPrefix works correctly.
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>
Create sendfile_common.go for shared constants and functions:
- MinSendfileSize constant
- getNetConn helper
- copyFile fallback function
Platform-specific files now only contain platform implementations.
Eliminates ~50 lines of duplicate code between Linux and non-Linux.
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>