Skip to content

Comments

Add ts.run_plugin() Lua API for dynamic remap plugin execution#7

Draft
Copilot wants to merge 5 commits intomasterfrom
copilot/add-run-plugin-functionality
Draft

Add ts.run_plugin() Lua API for dynamic remap plugin execution#7
Copilot wants to merge 5 commits intomasterfrom
copilot/add-run-plugin-functionality

Conversation

Copy link

Copilot AI commented Feb 9, 2026

Implements ts.run_plugin() Lua API enabling conditional plugin loading at runtime, matching header_rewrite's run-plugin operator functionality.

Implementation

New files:

  • ts_lua_run_plugin.{h,cc} - Core API implementation
    • Plugin loading via PluginFactory::getRemapPlugin() with ElevateAccess
    • Caching by plugin name + arguments to prevent config conflicts
    • Argument parsing with std::quoted for quoted string support

Integration:

  • ts_lua_common.h - Added loaded_plugins linked list to ts_lua_instance_conf
  • ts_lua_util.cc - Registered API in ts_lua_inject_ts_api()
  • ts_lua.cc - PluginFactory initialization in TSRemapInit(), cleanup in TSRemapDeleteInstance()
  • CMakeLists.txt - Added to build

Memory Management

  • Plugin instances managed by PluginFactory (process lifetime)
  • RemapPluginInst::done() called for reference counting
  • URLs from TSRemapRequestInfo::{mapFromUrl,mapToUrl} freed after sync plugin init
  • Plugin name/args strings freed in instance cleanup

API

function do_remap()
    if ts.client_request.header["X-Feature-Flag"] == "enabled" then
        if not ts.run_plugin("rate_limit.so", "--limit=100 --error=429") then
            ts.error("Rate limit plugin failed")
        end
    end
    return 0
end

Parameters:

  • plugin_name (string, required): Plugin path/name
  • args (string, optional): Plugin arguments

Returns: boolean success/failure

Constraints: Remap context only (validates rri != nullptr)

Original prompt

Add run-plugin functionality to Lua plugin

Summary

Add a ts.run_plugin() Lua API function that allows dynamically loading and executing remap plugins at runtime, similar to the run-plugin operator added to the header_rewrite plugin in PR apache#11320.

Background

PR apache#11320 added a run-plugin operator to the header_rewrite plugin that allows conditionally loading and running other plugins. This feature is useful for scenarios where you want to enable/disable plugins based on request conditions.

Example use case from header_rewrite:

cond %{REMAP_PSEUDO_HOOK} [AND]
cond %{CLIENT-HEADER:X-Leif} ="yes"
     run-plugin rate_limit.so "--limit=300 --error=429"

Objective

Implement similar functionality for the Lua plugin, allowing Lua scripts to dynamically load and execute remap plugins.

Implementation Details

1. Create plugins/lua/ts_lua_run_plugin.cc

This file should implement:

  • ts_lua_run_plugin(lua_State *L) - Main Lua C function that handles the API call
  • ts_lua_load_plugin() - Loads a plugin using the plugin factory
  • ts_lua_find_loaded_plugin() - Finds already loaded plugins to avoid reloading
  • ts_lua_inject_run_plugin_api() - Registers the API with Lua

Key implementation requirements:

  • Parse plugin name and arguments from Lua stack
  • Use the same plugin_factory.getRemapPlugin() approach as header_rewrite
  • Handle privilege elevation when loading plugins (use ElevateAccess)
  • Parse quoted arguments similar to header_rewrite implementation
  • Cache loaded plugins in the instance configuration
  • Only allow execution in remap context (check rri != nullptr)
  • Execute plugin's doRemap() function with transaction and remap info

2. Create plugins/lua/ts_lua_run_plugin.h

Header file defining:

  • ts_lua_loaded_plugin structure to track loaded plugins
  • Function declarations for the implementation

3. Update plugins/lua/ts_lua_common.h

Add to the ts_lua_instance_conf structure:

struct ts_lua_loaded_plugin_t *loaded_plugins;

4. Update Lua API initialization

Find where the Lua ts table is initialized and add:

ts_lua_inject_run_plugin_api(L);

This is likely in a file like ts_lua_client_request.c or similar where other ts.* APIs are registered.

5. Update build system

Add ts_lua_run_plugin.cc to the appropriate CMakeLists.txt or Makefile for the lua plugin.

6. Add includes

The implementation will need these includes:

#include "swoc/swoc_file.h"
#include "records/RecCore.h"
#include <sstream>
#include <iomanip>

And reference to the plugin factory:

extern PluginFactory plugin_factory;

API Specification

Lua Function Signature

boolean ts.run_plugin(string plugin_name, string args)

Parameters:

  • plugin_name (required): Name or path of the plugin to load (e.g., "rate_limit.so")
  • args (optional): String of arguments to pass to the plugin (e.g., "--limit=300 --error=429")

Returns:

  • true if the plugin was loaded and executed successfully
  • false if loading or execution failed

Errors:

  • Logs error and returns false if not called in remap context
  • Logs error and returns false if plugin name is empty or invalid
  • Logs error and returns false if plugin fails to load

Example Usage

function do_remap()
    local client_header = ts.client_request.header["X-Rate-Limit"]
    
    if client_header == "yes" then
        -- Conditionally load and run the rate_limit plugin
        local success = ts.run_plugin("rate_limit.so", "--limit=300 --error=429")
        
        if success then
            ts.debug("Successfully ran rate_limit plugin")
        else
            ts.error("Failed to run rate_limit plugin")
        end
    end
    
    return 0
end

Reference Implementation

Base the implementation on the OperatorRunPlugin class from:

  • plugins/header_rewrite/operators.cc lines 1273-1342
  • plugins/header_rewrite/operators.h (OperatorRunPlugin class definition)

Key patterns to follow:

  1. Plugin loading with privilege escalation
  2. Argument parsing with std::quoted for quoted strings
  3. Plugin caching to avoid reloading
  4. Error handling and logging

Testing Considerations

  • Test with valid and invalid plugin names
  • Test with and without arguments
  • Test calling outside remap context (should fail gracefully)
  • Test with plugins that have quoted arguments
  • Test loading the same plugin multiple times (should reuse cached instance)

Notes

  • This feature only works in remap context (when TSRemapRequestInfo is available)
  • Loaded plugins are cached per instance configuration
  • Security: Uses the same privilege elevation mechanism as header_rewrite
  • Compatible with existing plugin factory infrastructure

This pull request was created from Copilot chat.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Add run-plugin functionality to Lua plugin Add ts.run_plugin() Lua API for dynamic remap plugin execution Feb 9, 2026
Copilot AI requested a review from shukitchan February 9, 2026 20:18
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