Skip to content

feat(http): add Lua script handler - #856

Merged
ithewei merged 12 commits into
masterfrom
http-lua-handler
Jul 28, 2026
Merged

feat(http): add Lua script handler#856
ithewei merged 12 commits into
masterfrom
http-lua-handler

Conversation

@ithewei

@ithewei ithewei commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Summary

  • add optional WITH_LUA HTTP Lua handler support with minimal ctx and hv bindings
  • add generic HttpScriptHandler and HttpService::Script directory mapping for .lua scripts
  • support method-specific Lua handlers such as get/post with fallback to handle
  • add tests, example script updates, and Chinese documentation

Tests

  • make libhv WITH_LUA=yes
  • DYLD_LIBRARY_PATH=$(pwd)/lib ./bin/http_lua_handler_test

Copilot AI review requested due to automatic review settings July 28, 2026 12:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds optional Lua scripting support to libhv’s HTTP server so requests can be handled by .lua scripts via a generic HttpScriptHandler (backed by HttpLuaHandler), including directory-to-route script mapping through HttpService::Script.

Changes:

  • Introduces HttpScriptHandler / HttpLuaHandler to execute Lua scripts with a minimal ctx API and basic hv host helpers.
  • Adds HttpService::Script() for mapping URL prefixes to a script directory with per-script handler caching.
  • Updates build/test infrastructure (Makefile + CMake + unittest runner), adds a new unit test, example script, and CN documentation.

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
unittest/http_lua_handler_test.cpp Adds unit tests covering Lua handler responses, method dispatch preference, script-dir mapping, and traversal blocking.
unittest/CMakeLists.txt Builds the new Lua unittest when WITH_LUA is enabled.
scripts/unittest.sh Executes the Lua unittest when present.
Makefile.vars Adds Lua detection/link flags for Makefile builds.
Makefile.in Includes Makefile.vars and wires WITH_LUA flags into compile/link.
Makefile Installs Lua handler headers when enabled and builds the new unittest binary under WITH_LUA.
http/server/HttpService.h Adds HttpService::Script() API under WITH_LUA; simplifies http_handler copy/assign.
http/server/HttpService.cpp Implements HttpService::Script() with per-script handler caching.
http/server/HttpScriptHandler.h Declares generic script handler API and options.
http/server/HttpScriptHandler.cpp Implements script type dispatch (currently .luaHttpLuaHandler).
http/server/HttpLuaHandler.h Declares Lua-backed handler with reload-on-change and error tracking.
http/server/HttpLuaHandler.cpp Implements Lua VM lifecycle, ctx bindings, JSON conversion, and method-specific dispatch.
hconfig.h.in Adds WITH_LUA config define for generated config headers.
examples/scripts/hello.lua Provides a sample Lua script demonstrating get/post/handle handlers.
examples/http_server_test.cpp Demonstrates registering Lua script routes and script directory mapping under WITH_LUA.
docs/PLAN.md Notes “http lua handler” as a planned/available capability.
docs/cn/README.md Links to the new CN documentation page for the Lua handler.
docs/cn/HttpLuaHandler.md Documents build, usage, directory mapping, exposed APIs, and hot reload behavior.
config.mk Adds WITH_LUA default and updates config date.
config.ini Adds WITH_LUA option documentation/config entry.
CMakeLists.txt Adds WITH_LUA option and links Lua when enabled.
.gitignore Ignores agent-related directories/files.
Comments suppressed due to low confidence (1)

http/server/HttpScriptHandler.cpp:50

  • Lazy initialization of state_->lua_handler is not thread-safe. Use std::call_once (together with the std::once_flag in State) to ensure only one thread initializes the Lua handler.
        if (!state_->lua_handler) {
            HttpLuaHandlerOptions lua_options;
            lua_options.reload_on_change = options_.reload_on_change;
            state_->lua_handler = std::make_shared<HttpLuaHandler>(filepath_.c_str(), lua_options);
        }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +5 to +9
#include "HttpScriptHandler.h"
#include "hpath.h"
#include "hstring.h"
#include <string.h>
#endif
Comment on lines +11 to +13
struct HttpScriptHandler::State {
HttpLuaHandlerPtr lua_handler;
};
Comment thread http/server/HttpLuaHandler.cpp
Comment thread CMakeLists.txt
Copilot AI review requested due to automatic review settings July 28, 2026 13:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 23 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (5)

Makefile.vars:13

  • Lua autodetection via pkg-config currently checks only for a "lua" package, and the fallback prefix probe won’t match common layouts like /usr/include/lua5.4/lua.h (e.g., Debian/Ubuntu). This can leave LUA_CFLAGS empty and break WITH_LUA builds even when liblua5.x-dev is installed. Consider probing common pkg-config names and include layouts.
LUA_PKG_CONFIG ?= $(shell if command -v $(PKG_CONFIG) >/dev/null 2>&1 && $(PKG_CONFIG) --exists lua; then echo lua; fi)
LUA_PREFIX ?= $(shell for dir in /opt/homebrew/opt/lua /usr/local/opt/lua /usr; do if [ -f "$$dir/include/lua/lua.h" ] || [ -f "$$dir/include/lua.h" ]; then echo $$dir; break; fi; done)
LUA_INCLUDE_DIR ?= $(shell if [ -n "$(LUA_PREFIX)" ]; then for dir in "$(LUA_PREFIX)/include/lua" "$(LUA_PREFIX)/include/lua5.5" "$(LUA_PREFIX)/include/lua5.4" "$(LUA_PREFIX)/include/lua5.3" "$(LUA_PREFIX)/include"; do if [ -f "$$dir/lua.h" ]; then echo $$dir; break; fi; done; fi)

CMakeLists.txt:194

  • When WITH_LUA is ON, CMake currently defines WITH_LUA even if find_package(Lua) fails, and then falls back to linking "lua" without adding include directories. This can lead to confusing build failures at compile time (missing lua.h) instead of a clear configure-time error. Prefer making Lua a REQUIRED dependency when WITH_LUA is enabled.
if(WITH_LUA)
    add_definitions(-DWITH_LUA)
    find_package(Lua)
    if(LUA_FOUND)
        include_directories(${LUA_INCLUDE_DIR})
        set(LIBS ${LIBS} ${LUA_LIBRARIES})
    else()
        set(LIBS ${LIBS} lua)
    endif()
endif()

http/server/HttpService.cpp:164

  • HttpService::Script caches a new HttpScriptHandler for every distinct URL-derived script path, even when the script file doesn’t exist. A client can hit many random URLs under the mapped prefix and grow the in-memory scripts map without bound, and missing scripts will later return 500 from the handler. It’s safer to verify the target script exists before inserting into the cache and return 404 for missing scripts.
        std::string script = HPath::join(root, name);
        if (HPath::suffixname(script).empty()) {
            script += ".lua";
        }

http/server/HttpLuaHandler.cpp:386

  • On Lua runtime errors (lua_pcall failure), the handler writes the raw Lua error string into the HTTP response body. This can expose internal details (file paths, stack traces, host error strings) to remote clients. Consider returning a generic message to the client while keeping the detailed error in logs/lastError().
        setErrorLocked(error);
        hloge("call lua script %s failed: %s", filepath_.c_str(), error.c_str());
        ctx->response->status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
        ctx->response->String(error);
        return HTTP_STATUS_INTERNAL_SERVER_ERROR;

http/server/HttpLuaHandler.cpp:418

  • When initial load/reload fails, the handler returns last_error_ directly in the response body. This can leak filesystem and host error details to clients. Consider returning a generic 500 message and keep last_error_ for logs/diagnostics via lastError().
    if (!reloadIfNeeded()) {
        std::lock_guard<std::mutex> lock(mutex_);
        ctx->response->status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
        ctx->response->String(last_error_);
        return HTTP_STATUS_INTERNAL_SERVER_ERROR;

@ithewei
ithewei merged commit 3d61ceb into master Jul 28, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants