675 Commits

Author SHA1 Message Date
xfy
38bb743781 fix(server): handle LocationEngine registration errors properly
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.
2026-06-03 10:12:09 +08:00
xfy
ac66ea5534 fix(server): use atomic.Bool for Server.running to eliminate data race
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.
2026-06-03 01:19:23 +08:00
xfy
0359d4c477 fix(stream): use atomic operations for counters and fix UDP conns leak
- 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
2026-06-03 01:16:37 +08:00
xfy
eb404f98a2 fix(ssl): implement OCSP refreshAll to actually refresh stale responses
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
2026-06-03 01:14:09 +08:00
xfy
3b84d62971 fix(ssl): extract OCSP HTTP request loop into singleOCSPAttempt
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.
2026-06-03 01:11:07 +08:00
xfy
f6c1ee8180 fix(proxy): log error when upstream TLS config creation fails
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.
2026-06-03 01:09:40 +08:00
xfy
2c3cc1ba38 fix(proxy): prevent use-after-recycle in background cache refresh
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.
2026-06-03 01:08:50 +08:00
xfy
c2dd4fa9a3 fix(resolver): prevent double-close panic in DNSResolver.Stop()
Use atomic Swap instead of Load+close+Store to eliminate the race
window where concurrent Stop() calls could both pass the check.
2026-06-03 01:07:54 +08:00
xfy
ba0b3c55bb fix(loadbalance): prevent double-close panic in SlowStartManager.Stop()
Use atomic Swap instead of Load+close to prevent concurrent Stop()
calls from both passing the check and closing the channel twice.
2026-06-03 01:07:22 +08:00
xfy
332b96031b docs: simplify README.md to focus on project introduction
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>
2026-05-09 18:22:30 +08:00
xfy
b2ae4472d7 refactor(gjson): remove nolint comment from cfgEncodeSortKeys
The nolint:unused comment added in c47ab16 is no longer needed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 18:14:41 +08:00
xfy
b6018ff9c9 test: add t.Parallel() to enable parallel test execution
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>
2026-05-09 17:57:23 +08:00
xfy
c47ab1617f fix(gjson): add nolint comment for cfgEncodeSortKeys method
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>
2026-05-09 17:38:09 +08:00
xfy
c37364b309 style: format code and modernize loop syntax
- 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>
2026-05-09 17:34:59 +08:00
xfy
8643a0aff9 refactor: improve error handling and fix linter warnings
- 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>
2026-05-09 17:32:06 +08:00
xfy
c157be1ce5 refactor(cache): remove unused disk/tiered cache and add helper functions
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>
2026-05-09 17:26:19 +08:00
xfy
25d93c25fa refactor: remove unused code and fix formatting
- 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>
2026-05-09 16:58:45 +08:00
xfy
ce80352e79 feat(gjson): add encode_sort_keys option for stable JSON output
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>
2026-05-09 16:09:49 +08:00
xfy
62be8bc557 feat(lua): enable package library and preload gjson module
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>
2026-05-09 15:51:26 +08:00
xfy
376b9fd33c feat(gjson): add Lua JSON encoding/decoding library
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>
2026-05-09 15:44:31 +08:00
xfy
81df41b817 docs: update code statistics and simplify README structure
- Update stats: 234 source files, 242 test files, ~189K lines, 81.3% coverage
- Remove GeoIP filter from feature list
- Simplify directory structure section
- Remove redundant diagrams and detailed module breakdowns
- Streamline monitoring and deployment sections

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 15:36:39 +08:00
xfy
9c091e528b docs(lua): add route script documentation and examples
- Add route script vs middleware script distinction
- Document route_type options (exact, prefix, regex, etc.)
- Add practical examples: status, health, echo, ip, json, redirect
- Document enable_file_watch for hot reload support

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 13:57:33 +08:00
xfy
986ebdf207 fix(lua): enable file watch by default for hot reload
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>
2026-05-09 13:45:55 +08:00
xfy
8f3c304837 fix(lua): register Lua routes in multi-server mode
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>
2026-05-09 13:41:26 +08:00
xfy
a5b5a085cc feat(lua): add Lua route registration in server startup
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>
2026-05-09 11:44:39 +08:00
xfy
669f9c975b feat(lua): add registerLuaRoutesWithLocationEngine for Lua route handling
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>
2026-05-09 11:42:06 +08:00
xfy
dff88449d5 feat(lua): skip routed scripts in middleware builder
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>
2026-05-09 11:38:40 +08:00
xfy
fb655829e1 feat(lua): add LuaRouteHandler for route-based script execution
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>
2026-05-09 11:37:42 +08:00
xfy
2fb8880ab5 feat(config): add route validation for Lua scripts
Add validation for route-based Lua script configuration:
- Check route and phase mutual exclusion
- Validate route_type enum values (exact, prefix, prefix_priority, regex, regex_caseless)
- Validate regex patterns for regex/regex_caseless types

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 11:37:31 +08:00
xfy
ceb71cd9cc feat(config): add Route and RouteType fields to LuaScriptConfig
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>
2026-05-09 11:36:13 +08:00
xfy
f3f92c7922 feat(lua): add LState pool configuration and fix coroutine error handling
- 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>
2026-05-09 11:13:23 +08:00
xfy
6c7cf73c87 refactor(lua): replace single LState with LState pool architecture
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>
2026-05-09 10:38:10 +08:00
xfy
2a532f8c28 docs(lua): update config format to match implementation
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>
2026-05-09 09:49:33 +08:00
xfy
8d3c9e0f6f chore: ignore .crush file
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:40:34 +08:00
xfy
5090bd4cbe fix(ssl): use reserved IP for connection failure test
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>
2026-05-09 08:20:10 +08:00
xfy
edc135ae5f refactor(utils): enhance ParseCIDR to support single IP
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>
2026-05-08 18:20:09 +08:00
xfy
70d6488fc6 refactor(handler): extract path processing methods
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>
2026-05-08 18:14:51 +08:00
xfy
5d9ef8e611 refactor(server): extract static handler configuration
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>
2026-05-08 18:10:52 +08:00
xfy
454a1be9e1 refactor(app): add test logger helper function
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>
2026-05-08 18:06:55 +08:00
xfy
f72c9f78db refactor(config): genericize non-negative validators
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>
2026-05-08 18:06:44 +08:00
xfy
a28c7ebcf1 refactor(utils): add unified b2s/s2b conversion functions
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>
2026-05-08 18:06:25 +08:00
xfy
3b2360162c refactor(utils): add unified ETag generation function
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>
2026-05-08 18:06:13 +08:00
xfy
8c96c4384f fix(status): use version package instead of hardcoded version
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>
2026-05-07 17:46:32 +08:00
xfy
9c46c8bab8 fix(server): register status and pprof handlers in multi-server mode
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>
2026-05-07 17:44:57 +08:00
xfy
03c27c8d95 fix(static): add missing AutoIndex and Internal settings in registerStaticHandlers
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>
2026-05-07 16:32:41 +08:00
xfy
4b48fd71e6 docs: add llms.txt for AI agent usage guide
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>
2026-05-07 14:54:21 +08:00
xfy
6e6659e6df chore(deps): bump fasthttp to 1.71.0 and compress to 1.18.6
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 14:39:03 +08:00
xfy
2dcc139dd5 docs: update README with comprehensive project structure and features
- 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>
2026-05-07 14:03:42 +08:00
xfy
144e101c09 feat(proxy): add configurable X-Forwarded-Host and X-Forwarded-Proto headers
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>
2026-05-07 13:28:28 +08:00
xfy
c02008cc6a chore(build): remove tmpdir workaround from Makefile
💘 Generated with Crush

Assisted-by: mimo-v2.5 via Crush <crush@charm.land>
2026-05-06 17:43:13 +08:00