Add typed ConflictError for path conflicts, change register functions
to return errors, handle conflicts as warnings and fatal errors as
startup failures. Remove all 20 instances of ignored Add* return values.
Server.running was a plain bool accessed from multiple goroutines
(start/stop/signal handlers). Convert to atomic.Bool with
Store/Load to make all accesses safe for concurrent use.
Updates all test files to use the new atomic API.
- Server.connCount and Target.conns now use atomic.AddInt64/LoadInt64
instead of non-atomic ++ and --, fixing data races under concurrency
- UDP sessions now store a reference to their target and decrement
target.conns in close(), preventing monotonically increasing counts
that would break least_conn load balancing over time
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.
Previously the error was silently swallowed, causing the proxy to
fall back to default TLS settings (no custom CA, no mTLS, no SNI)
without any indication. Now the error is logged at ERROR level.
Copy the request before spawning the background goroutine. The
fasthttp.RequestCtx is recycled after the handler returns, so passing
it to a goroutine causes data corruption under high concurrency.
The caller now AcquireRequest+CopyTo before go(), and the goroutine
releases it. backgroundRefresh no longer accepts ctx directly.
Remove all example code, installation commands, configuration samples,
Lua script examples, Docker deployment, benchmark data, and troubleshooting
sections. Keep only core feature descriptions, architecture overview, and
dependency list.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add t.Parallel() to 110 test functions across 3 test files:
- internal/loadbalance/balancer_test.go (42 tests)
- internal/config/validate_test.go (21 tests)
- internal/server/status_test.go (47 tests)
This reduces total test time from ~3 minutes to ~34 seconds (5.4x faster).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The method is registered to Lua via instance.cfgEncodeSortKeys pattern,
which the linter cannot detect.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Align struct fields and constants in gjson/config.go
- Add missing newline at EOF in gjson/decode.go
- Remove trailing blank line in gjson/encode.go
- Remove extra blank line in internal/lua/coroutine.go
- Use modern for range syntax in internal/lua/pool.go
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add nolint comments for type assertion errcheck in gjson/encode.go
(switch case guarantees type safety)
- Handle fasthttp.Serve errors in benchmark mock backends
- Rename error variables to avoid shadowing in server.go
- Use underscore for unused loop variables
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remove unused disk cache, tiered cache, purge, and config loader code.
Add HashPathWithMethod and MatchPattern helpers for future cache purge API.
Update test to use new mock backend API with ResponseBody field.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove unused benchmark/tools package
- Make ValidAlgorithms private (validAlgorithms) in loadbalance
- Remove dead code (_ = result) in lua/api_socket_tcp.go
- Fix code formatting with goimports
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add configurable key sorting for JSON object encoding. When enabled,
object keys are sorted alphabetically for deterministic output.
Default is disabled for better performance.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add glua.OpenPackage for require support and preload gjson module
to make JSON encoding/decoding available in Lua scripts.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add gjson package providing high-performance JSON encoding/decoding
for gopher-lua with lua-cjson API compatibility. Uses goccy/go-json
as the underlying JSON engine.
Features:
- Full lua-cjson API compatibility for OpenResty migration
- Sparse array detection and handling
- Maximum nesting depth control for encode/decode
- Number precision control
- Independent configuration instances via gjson.new()
- gjson.null sentinel for JSON null values
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
EnableFileWatch was false by default (Go bool zero value) when
global_settings was not configured. Now defaults to true to enable
Lua script hot reload without server restart.
Also fix indentation in init.go default value settings.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add registerLuaRoutes method for router-based route registration
and call it in startMultiServerMode to fix Lua routes not working
when multiple servers are configured.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add call to registerLuaRoutesWithLocationEngine between proxy and static
route registration, ensuring correct routing order: proxy -> lua -> static.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add two new functions to router.go:
- registerLuaRoutesWithLocationEngine: registers Lua scripts with Route
config to LocationEngine with support for exact/prefix/regex matching
- wrapRoutedHandler: wraps route handlers with basic middleware chain
(accesslog + errorintercept)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Scripts with Route config are handled by LocationEngine, so skip them
in buildLuaMiddlewares to avoid duplicate processing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Create LuaRouteHandler that implements fasthttp.RequestHandler interface,
allowing Lua scripts to be registered as standalone route handlers.
Handles ngx.exit/ngx.redirect as normal exits, not errors.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add route-based matching support for Lua scripts as an alternative to
phase-based execution. Scripts can now be matched by path patterns.
Fields added:
- Route: path/pattern for route matching (mutually exclusive with Phase)
- RouteType: matching type (exact, prefix, prefix_priority, regex, regex_caseless)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add LStatePoolInitialSize and LStatePoolMaxSize config fields
- Set pool defaults to 100 initial / 1000 max (matching MaxConcurrentCoroutines)
- Fix middleware to return 500 on coroutine init failure instead of continuing
- Pass pool config from server init to Lua engine with zero-value fallbacks
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the single LState + coroutine model with an LState pool to
eliminate concurrent map read/write issues in gopher-lua. Each request
now gets a completely independent LState with its own Global table.
Key changes:
- Add LStatePool for managing pooled LState instances
- Remove shared Engine.L and coroutine-based execution
- Simplify coroutine.go: remove yield handling, use direct PCall
- Remove ngxRegisterMu lock (no longer needed with isolated LStates)
- Update config.go: add LStatePoolInitialSize/MaxSize settings
- Update tests to work with the new architecture
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace unsupported shorthand fields (content_by_lua, etc.) with actual
scripts list format and global_settings structure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
Enhance parseCIDR in utils/ipallowlist.go to support single IP addresses
(without CIDR prefix) and ensure IP is in canonical form. This matches
the functionality previously in access.go.
- Add ParseCIDR as public function supporting CIDR and single IP
- Update access.go to use utils.ParseCIDR instead of local implementation
- Remove duplicate parseCIDR function from access.go
- Update tests to use utils.ParseCIDR
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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 static handler configuration logic from
registerStaticHandlersWithLocationEngine and registerStaticHandlers
into a new configureStaticHandler method.
- Create configureStaticHandler() to handle alias, cache, gzip,
symlink, internal, expires, and autoIndex configuration
- Both registration functions now call the shared configuration method
- Registration logic remains separate (LocationEngine vs Router)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Create setupTestLogger() helper to reduce duplicate logger initialization
in test files. Replace 20+ occurrences of logging.NewAppLogger calls.
- Create testutil.go with setupTestLogger() function
- Update app_test.go to use the new helper
- Remove unused logging import from app_test.go
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace three duplicate ValidateNonNegative* functions with a single
generic implementation using Go 1.18+ generics.
- Add SignedInteger type constraint for generic support
- Create ValidateNonNegative[T SignedInteger] as unified function
- Depprecate ValidateNonNegativeInt64 and ValidateNonNegativeDuration
- Both deprecated functions now call the generic version
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Extract duplicate b2s/s2b functions from proxy/utils.go into
internal/utils/bytes.go. These are zero-allocation unsafe conversions
for byte slice <-> string conversion.
- Create utils.B2s() and utils.S2b() as unified implementations
- Update proxy/utils.go to call utils functions
- Add safety documentation about shared memory warning
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>
Replace hardcoded "1.0.0" with version.Version to show the actual
build version injected via -ldflags.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
In startMultiServerMode, status and pprof handlers were not registered,
causing /_status and /debug/pprof endpoints to return 404. Now these
handlers are registered on the server with default: true, consistent
with startVHostMode behavior. Also fixed cache API registration to
use default server instead of first server.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The registerStaticHandlers function (used in multi-server mode) was missing
AutoIndex and Internal configuration that registerStaticHandlersWithLocationEngine
already had. This caused auto_index to not work in multi-server mode.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add comprehensive documentation file designed for AI agents to understand
and use Lolly HTTP server. Covers configuration structure, static file
serving, reverse proxy, SSL/TLS, security, Lua scripting, and common
deployment patterns.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add code statistics: 174 source files, 158 test files, ~136K lines
- Document proxy cache and Lua script extension features
- Expand internal directory structure with detailed file descriptions
- Update Go version requirement to 1.26
- Add cache purge API documentation
- Enhance hot upgrade docs with Unix Socket inheritance support
- Update status endpoint with cache hit rate and upstream health
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add `set_forwarded_host` and `set_forwarded_proto` options to control
whether the proxy automatically sets these headers. This fixes issues
with upstream servers that validate X-Forwarded-Host against known hosts.
Changes:
- Add SetForwardedHost/SetForwardedProto fields to ProxyHeaders struct
- Modify SetForwardedHeaders and WriteForwardedHeaders function signatures
- Update modifyRequestHeaders to read config and pass control parameters
- Update WebSocket call chain to support new config
- Add unit tests for new functionality
- Update default config generation (-g) to include new options
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>