510 Commits

Author SHA1 Message Date
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
xfy
bb1fe6853f chore: add MIT license
💘 Generated with Crush

Assisted-by: mimo-v2.5 via Crush <crush@charm.land>
2026-05-06 17:35:46 +08:00
xfy
c90dd10962 chore(ci): remove GitHub Actions workflow files
💘 Generated with Crush

Assisted-by: mimo-v2.5 via Crush <crush@charm.land>
2026-05-06 10:20:43 +08:00
xfy
1e01d4829d chore: release v0.2.2
Update version to 0.2.2 and add comprehensive CHANGELOG entry
covering 130+ commits since v0.2.1: autoindex module, nginx config
converter, ETag/304 support, layered caching, stale cache fallback,
slow start load balancing, performance optimizations, and more.

💘 Generated with Crush

Assisted-by: mimo-v2.5-pro via Crush <crush@charm.land>
v0.2.2
2026-04-30 16:56:14 +08:00
xfy
26d62c9fcd refactor(handler): improve autoindex code quality
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>
2026-04-30 16:23:34 +08:00
xfy
5f470993ff perf(handler): use RWMutex for FileInfoCache
- 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>
2026-04-30 16:15:39 +08:00
xfy
3c96f12f74 feat(cache): store ContentType in FileEntry for cache hits
- 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>
2026-04-30 16:13:42 +08:00
xfy
23fdcf89ae perf(handler): use cached ETag to avoid regeneration on cache hits
- 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>
2026-04-30 16:03:59 +08:00
xfy
5593a729b8 perf(compression): use bytes operations to avoid string allocation
- Replace strings.ToLower(string(...)) with bytes.ToLower
- Reduces memory allocation in hot path for Accept-Encoding checks

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 15:59:42 +08:00
xfy
73ef3a938b perf(handler): add FileInfo cache to handleTryFiles and handleInternalRedirect
- 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>
2026-04-30 15:56:42 +08:00
xfy
3b608be0de refactor(handler): improve autoindex code quality
- 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>
2026-04-30 15:21:10 +08:00
xfy
b62a3f12da feat(handler): add autoindex module for directory listing
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>
2026-04-30 15:11:34 +08:00
xfy
e32e96ee81 feat(config): change gzip_static default to true
Enable pre-compressed file serving by default for better performance.
This aligns with the common practice of serving .gz/.br files when available.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 14:24:23 +08:00
xfy
8cc3fdef6f perf(handler): optimize static file serving performance
- Add pathPrefixLen for zero-allocation path stripping
- Precompute ETag in FileCache.Set, reuse on cache hits
- Add MIME LRU cache with O(1) operations using container/list
- Remove sharded cache (eager LRU was slower than single-lock)
- Add FileInfo cache to reduce os.Stat calls (TTL-only strategy)
- Adjust test expectations for normalized root path format

Benchmark results: Lookup 12.7µs → 10.6µs (16% improvement)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 14:17:56 +08:00
xfy
d269940d8b style: fix formatting issues
- Add missing newlines at end of files
- Fix indentation in ssl.go
- Remove extra blank lines

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 13:42:53 +08:00
xfy
b1e1547e36 fix(lint): resolve errcheck and goconst issues
- 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>
2026-04-30 13:41:15 +08:00