summaryrefslogtreecommitdiffstats
path: root/docs/manual/developer/lua.html.en.utf8
diff options
context:
space:
mode:
authorJoe Orton <jorton@apache.org>2020-08-19 09:31:23 +0200
committerJoe Orton <jorton@apache.org>2020-08-19 09:31:23 +0200
commit7f6aec2cf7fb0caaa93dc98e25968d58b60107fd (patch)
tree2218e4fdf202d9781910e0218b690acbdc92a0d5 /docs/manual/developer/lua.html.en.utf8
parentFollow up to r1880368 by adjusting en.xml to match lang-targets.xml. (diff)
downloadapache2-7f6aec2cf7fb0caaa93dc98e25968d58b60107fd.tar.xz
apache2-7f6aec2cf7fb0caaa93dc98e25968d58b60107fd.zip
Follow up to r1880368 and r1880980:
Complete move to .en.utf8 suffixes in two steps: 1. From fresh checkout, renamed all existing files: $ for f in *.html.en */*.html.en; do svn mv $f $f.utf8; done 2. Ran "./build.sh all" which also regenerates the typemaps. [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1880982 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'docs/manual/developer/lua.html.en.utf8')
-rw-r--r--docs/manual/developer/lua.html.en.utf8590
1 files changed, 590 insertions, 0 deletions
diff --git a/docs/manual/developer/lua.html.en.utf8 b/docs/manual/developer/lua.html.en.utf8
new file mode 100644
index 0000000000..9f9637f02a
--- /dev/null
+++ b/docs/manual/developer/lua.html.en.utf8
@@ -0,0 +1,590 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
+<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
+<!--
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ This file is generated from xml source: DO NOT EDIT
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ -->
+<title>Creating hooks and scripts with mod_lua - Apache HTTP Server Version 2.5</title>
+<link href="../style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" />
+<link href="../style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" />
+<link href="../style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="../style/css/prettify.css" />
+<script src="../style/scripts/prettify.min.js" type="text/javascript">
+</script>
+
+<link href="../images/favicon.ico" rel="shortcut icon" /></head>
+<body id="manual-page"><div id="page-header">
+<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/quickreference.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p>
+<p class="apache">Apache HTTP Server Version 2.5</p>
+<img alt="" src="../images/feather.png" /></div>
+<div class="up"><a href="./"><img title="&lt;-" alt="&lt;-" src="../images/left.gif" /></a></div>
+<div id="path">
+<a href="http://www.apache.org/">Apache</a> &gt; <a href="http://httpd.apache.org/">HTTP Server</a> &gt; <a href="http://httpd.apache.org/docs/">Documentation</a> &gt; <a href="../">Version 2.5</a> &gt; <a href="./">Developer</a></div><div id="page-content"><div id="preamble"><h1>Creating hooks and scripts with mod_lua</h1>
+<div class="toplang">
+<p><span>Available Languages: </span><a href="../en/developer/lua.html" title="English">&nbsp;en&nbsp;</a></p>
+</div>
+
+<p>This document expands on the <code class="module"><a href="../mod/mod_lua.html">mod_lua</a></code> documentation and explores
+ additional ways of using mod_lua for writing hooks and scripts.</p>
+</div>
+<div id="quickview"><ul id="toc"><li><img alt="" src="../images/down.gif" /> <a href="#introduction">Introduction</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#enabling">Optimizing mod_lua for production servers</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#basic_remap">Example 1: A basic remapping module</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#mass_vhost">Example 2: Mass virtual hosting</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#basic_auth">Example 3: A basic authorization hook</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#authz">Example 4: Authorization using LuaAuthzProvider</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#loadbalancing">Example 5: A rudimentary load balancer</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#map_handler">Example 6: Overlays using LuaMapHandler</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#mod_status_lua">Example 6: Basic Lua scripts</a></li>
+</ul><h3>See also</h3><ul class="seealso"><li><a href="../mod/mod_lua.html">mod_lua</a></li><li><a href="modguide.html">Developing modules for Apache 2.4</a></li><li><a href="request.html">Request Processing in Apache 2.4</a></li><li><a href="hooks.html">Apache 2.x Hook Functions</a></li><li><a href="#comments_section">Comments</a></li></ul></div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="introduction" id="introduction">Introduction</a> <a title="Permanent link" href="#introduction" class="permalink">&para;</a></h2>
+<h3><a name="what" id="what">What is mod_lua</a></h3>
+<p>
+Stuff about what <code class="module"><a href="../mod/mod_lua.html">mod_lua</a></code> is goes here.
+</p>
+
+<h3><a name="contents" id="contents">What we will be discussing in this document</a></h3>
+<p>
+This document will discuss several cases where <code class="module"><a href="../mod/mod_lua.html">mod_lua</a></code> can be used
+to either ease up a phase of the request processing or create more transparency in
+the logic behind a decision made in a phase.
+</p>
+
+
+
+<h3><a name="prerequisites" id="prerequisites">Prerequisites</a></h3>
+<p>
+First and foremost, you are expected to have a basic knowledge of how the Lua
+programming language works. In most cases, we will try to be as pedagogical
+as possible and link to documents describing the functions used in the
+examples, but there are also many cases where it is necessary to either
+just assume that "it works" or do some digging yourself into what the hows
+and whys of various function calls.
+</p>
+
+
+
+</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="enabling" id="enabling">Optimizing mod_lua for production servers</a> <a title="Permanent link" href="#enabling" class="permalink">&para;</a></h2>
+
+<h3>Setting a scope for Lua states</h3>
+<p>
+Setting the right <code class="directive"><a href="../mod/mod_lua.html#luascope">LuaScope</a></code> setting
+for your Lua scripts can be essential to your server's
+performance. By default, the scope is set to <code>once</code>, which means
+that every call to a Lua script will spawn a new Lua state that handles that
+script and is destroyed immediately after. This option keeps the memory
+footprint of mod_lua low, but also affects the processing speed of a request.
+If you have the memory to spare, you can set the scope to <code>thread</code>,
+which will make mod_lua spawn a Lua state that lasts the entirety of a thread's
+lifetime, speeding up request processing by 2-3 times. Since mod_lua will create
+a state for each script, this may be an expensive move, memory-wise, so to
+compromise between speed and memory usage, you can choose the <code>server</code>
+option to create a pool of Lua states to be used. Each request for a Lua script or
+a hook function will then acquire a state from the pool and release it back when it's
+done using it, allowing you to still gain a significant performance increase, while
+keeping your memory footprint low. Some examples of possible settings are:
+</p>
+<pre class="prettyprint lang-config">LuaScope once
+LuaScope thread
+LuaScope server 5 40</pre>
+
+<p>
+As a general rule of thumb: If your server has none to low usage, use <code>once</code>
+or <code>request</code>, if your server has low to medium usage, use the <code>server</code>
+pool, and if it has high usage, use the <code>thread</code> setting. As your server's
+load increases, so will the number of states being actively used, and having your scope
+set to <code>once/request/conn</code> will stop being beneficial to your memory footprint.
+</p>
+<p>
+<strong>Note:</strong> The <code>min</code> and <code>max</code> settings for the
+<code>server</code> scope denotes the minimum and maximum states to keep in a pool per
+server <em>process</em>, so keep this below your <code>ThreadsPerChild</code> limit.
+</p>
+
+
+<h3>Using code caching</h3>
+<p>
+By default, <code class="module"><a href="../mod/mod_lua.html">mod_lua</a></code> stats each Lua script to determine whether a reload
+(and thus, a re-interpretation and re-compilation) of a script is required. This is managed
+through the <code class="directive"><a href="../mod/mod_lua.html#luacodecache">LuaCodeCache</a></code> directive. If you are running
+your scripts on a production server, and you do not need to update them regularly, it may be
+advantageous to set this directive to the <code>forever</code> value, which will cause mod_lua
+to skip the stat process and always reuse the compiled byte-code from the first access to the
+script, thus speeding up the processing. For Lua hooks, this can prove to increase performance,
+while for scripts handled by the <code>lua-script</code> handler, the increase in performance
+may be negligible, as files httpd will stat the files regardless.
+</p>
+
+
+<h3>Keeping the scope clean</h3>
+<p>
+For maximum performance, it is generally recommended that any initialization of libraries,
+constants and master tables be kept outside the handle's scope:
+</p>
+<pre class="prettyprint lang-lua">--[[ This is good practice ]]--
+require "string"
+require "someLibrary"
+local masterTable = {}
+local constant = "Foo bar baz"
+
+function handle(r)
+ do_stuff()
+end</pre>
+
+<pre class="prettyprint lang-lua">--[[ This is bad practice ]]--
+require "string"
+
+function handle(r)
+ require "someLibrary"
+ local masterTable = {}
+ local constant = "Foo bar baz"
+ do_stuff()
+end</pre>
+
+
+
+</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="basic_remap" id="basic_remap">Example 1: A basic remapping module</a> <a title="Permanent link" href="#basic_remap" class="permalink">&para;</a></h2>
+<p>
+ These first examples show how mod_lua can be used to rewrite URIs in the same
+ way that one could do using <code class="directive"><a href="../mod/mod_alias.html#alias">Alias</a></code> or
+ <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code>, but with more clarity
+ on how the decision-making takes place, as well as allowing for more complex
+ decisions than would otherwise be allowed with said directives.
+</p>
+
+<pre class="prettyprint lang-config">LuaHookTranslateName /path/too/foo.lua remap</pre>
+
+
+
+
+<pre class="prettyprint lang-lua">--[[
+ Simple remap example.
+ This example will rewrite /foo/test.bar to the physical file
+ /internal/test, somewhat like how mod_alias works.
+]]--
+
+function remap(r)
+ -- Test if the URI matches our criteria
+ local barFile = r.uri:match("/foo/([a-zA-Z0-9]+)%.bar")
+ if barFile then
+ r.filename = "/internal/" .. barFile
+ end
+ return apache2.OK
+end</pre>
+
+
+
+
+
+<pre class="prettyprint lang-lua">--[[
+ Advanced remap example.
+ This example will evaluate some conditions, and based on that,
+ remap a file to one of two destinations, using a rewrite map.
+ This is similar to mixing AliasMatch and ProxyPass, but
+ without them clashing in any way. Assuming we are on example.com, then:
+
+ http://example.com/photos/test.png will be rewritten as /uploads/www/test.png
+ http://example.com/ext/foo.html will be proxied to http://www.external.com/foo.html
+ URIs that do not match, will be served by their respective default handlers
+]]--
+
+local map = {
+ photos = {
+ source = [[^/photos/(.+)\.png$]],
+ destination = [[/uploads/www/$1.png]],
+ proxy = false
+ },
+ externals = {
+ source = [[^/ext/(.*)$]],
+ destination = [[http://www.external.com/$1]],
+ proxy = true
+ }
+}
+
+function interpolateString(s,v)
+ return s:gsub("%$(%d+)", function(a) return v[tonumber(a)] end)
+end
+
+function remap(r)
+ -- browse through the rewrite map
+ for key, entry in pairs(map) do
+ -- Match source regex against URI
+ local match = r:regex(entry.source, r.uri) then
+ if match and match[0] then
+ r.filename = interpolateString(entry.destination, match)
+ -- Is this a proxied remap?
+ if entry.proxy then
+ r.handler = "proxy-server" -- tell mod_proxy to handle this
+ r.proxyreq = apache2.PROXYREQ_REVERSE -- We'll want to do a reverse proxy
+ r.filename = "proxy:" .. r.filename -- Add the proxy scheme to the destination
+ end
+ return apache2.OK
+ end
+ end
+ return apache2.DECLINED
+end</pre>
+
+
+
+<p>
+bla bla
+</p>
+</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="mass_vhost" id="mass_vhost">Example 2: Mass virtual hosting</a> <a title="Permanent link" href="#mass_vhost" class="permalink">&para;</a></h2>
+<p>
+ As with simple and advanced rewriting, you can use mod_lua for dynamically
+ assigning a hostname to a specific document root, much like
+ <code class="module"><a href="../mod/mod_vhost_alias.html">mod_vhost_alias</a></code> does, but with more control over what goes
+ where. This could be as simple as a table holding the information about which
+ host goes into which folder, or more advanced, using a database holding the
+ document roots of each hostname.
+</p>
+
+<pre class="prettyprint lang-config">LuaHookTranslateName /path/too/foo.lua mass_vhost</pre>
+
+
+
+
+<pre class="prettyprint lang-lua">--[[
+ Simple mass vhost script
+ This example will check a map for a virtual host and rewrite filename and
+ document root accordingly.
+]]--
+
+local vhosts = {
+ { domain = "example.com", home = "/www/example.com" },
+ { domain = "example.org", home = "/nfs/ext1/example.org" }
+}
+
+function mass_vhost(r)
+ -- Match against our hostname
+ for key, entry in pairs(vhosts) do
+ -- match against either host or *.host:
+ if apache2.strcmp_match(r.hostname, entry.domain) or
+ apache2.strcmp_match(r.hostname, "*." .. entry.domain) then
+ -- If it matches, rewrite filename and set document root
+ local filename = r.filename:sub(r.document_root:len()+1)
+ r.filename = entry.home .. filename
+ apahce2.set_document_root(entry.home)
+ return apache2.OK
+ end
+ end
+ return apache2.DECLINED
+end</pre>
+
+
+
+
+
+<pre class="prettyprint lang-lua">--[[
+ Advanced mass virtual hosting
+ This example will query a database for vhost entries and save them for
+ 60 seconds before checking for updates. For best performance, such scripts
+ should generally be run with LuaScope set to 'thread' or 'server'
+]]--
+
+local cached_vhosts = {}
+local timeout = 60
+
+-- Function for querying the database for saved vhost entries
+function query_vhosts(r)
+ local host = r.hostname
+ if not cached_vhosts[host] or (cached_vhosts[host] and cached_vhosts[host].updated &lt; os.time() - timeout) then
+ local db,err = ap.dbopen(r,"mod_dbd")
+ local _host = db:escape(r,host)
+ local res, err = db:query(r, ("SELECT `destination` FROM `vhosts` WHERE `hostname` = '%s' LIMIT 1"):format(_host) )
+ if res and #res == 1 then
+ cached_vhosts[host] = { updated = os.time(), destination = res[1][1] }
+ else
+ cached_vhosts[host] = { updated = os.time(), destination = nil } -- don't re-query whenever there's no result, wait a while.
+ end
+ db:close()
+ end
+ if cached_vhosts[host] then
+ return cached_vhosts[host].destination
+ else
+ return nil
+ end
+end
+
+function mass_vhost(r)
+ -- Check whether the hostname is in our database
+ local destination = query_vhosts(r)
+ if destination then
+ -- If found, rewrite and change document root
+ local filename = r.filename:sub(r.document_root:len()+1)
+ r.filename = destination .. filename
+ ap.set_document_root(r,destination)
+ return apache2.OK
+ end
+ return apache2.DECLINED
+end</pre>
+
+
+
+<p>
+
+</p>
+</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="basic_auth" id="basic_auth">Example 3: A basic authorization hook</a> <a title="Permanent link" href="#basic_auth" class="permalink">&para;</a></h2>
+<p>
+ With the authorization hooks, you can add custom auth phases to your request
+ processing, allowing you to either add new requirements that were not previously
+ supported by httpd, or tweaking existing ones to accommodate your needs.
+</p>
+<pre class="prettyprint lang-config">LuaHookAuthChecker /path/too/foo.lua check_auth</pre>
+
+
+
+<pre class="prettyprint lang-lua">--[[
+ A simple authentication hook that checks a table containing usernames and
+ passwords of two accounts.
+]]--
+local accounts = {
+ bob = 'somePassword',
+ jane = 'Iloveponies'
+}
+
+-- Function for parsing the Authorization header into a username and a password
+function parse_auth(str)
+ local user,pass = nil, nil
+ if str and str:len() &gt; 0 then
+ str = apache2.base64_decode(auth):sub(7));
+ user, pass = auth:match("([^:]+)%:([^:]+)")
+ end
+ return user, pass
+end
+
+-- The authentication hook
+function check_auth(r)
+ local user, pass = parse_auth(r.headers_in['Authorization'])
+ local authenticated = false
+ if user and pass then
+ if accounts[user] and accounts[user] == pass then
+ authenticated = true
+ r.user = user
+ end
+ end
+ r.headers_out["WWW-Authenticate"] = 'Basic realm="Super secret zone"'
+ if not authenticated then
+ return 401
+ else
+ return apache2.OK
+ end
+end</pre>
+
+
+
+
+
+<pre class="prettyprint lang-lua">--[[
+ An advanced authentication checker with a database backend,
+ caching account entries for 1 minute
+]]--
+
+local timeout = 60 -- Set account info to be refreshed every minute
+local accounts = {}
+
+-- Function for parsing the Authorization header into a username and a password
+function parse_auth(str)
+ local user,pass = nil, nil
+ if str and str:len() &gt; 0 then
+ str = apache2.base64_decode(auth):sub(7));
+ user, pass = auth:match("([^:]+)%:([^:]+)")
+ end
+ return user, pass
+end
+
+-- Function for querying the database for the account's password (stored as a salted SHA-1 hash)
+function fetch_password(user)
+ if not accounts[user] or (accounts[user] and accounts[user].updated &lt; os.time() - timeout) then
+ local db = apache2.dbopen(r, "mod_dbd")
+ local usr = db:escape(user)
+ local res, err = db:query( ("SELECT `password` FROM `accounts` WHERE `user` = '%s' LIMIT 1"):format(usr) )
+ if res and #res == 1 then
+ accounts[user] = { updated = os.time(), password = res[1][1] }
+ else
+ accounts[user] = nil
+ end
+ db:close()
+ end
+ if accounts[user] then
+ return accounts[user].password
+ else
+ return nil
+ end
+end
+
+-- The authentication hook
+function check_auth(r)
+ local user, pass = parse_auth(r.headers_in['Authorization'])
+ local authenticated = false
+ if user and pass then
+ pass = apache2.sha1("addSomeSalt" .. pass)
+ local stored_pass = fetch_password(user)
+ if stored_pass and pass == stored_pass then
+ authenticated = true
+ r.user = user
+ end
+ end
+ r.headers_out["WWW-Authenticate"] = 'Basic realm="Super secret zone"'
+ if not authenticated then
+ return 401
+ else
+ return apache2.OK
+ end
+end</pre>
+
+
+
+
+</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="authz" id="authz">Example 4: Authorization using LuaAuthzProvider</a> <a title="Permanent link" href="#authz" class="permalink">&para;</a></h2>
+<p>
+ If you require even more advanced control over your authorization phases,
+ you can add custom authz providers to help you manage your server. The
+ example below shows you how you can split a single htpasswd file into
+ groups with different permissions:
+</p>
+<pre class="prettyprint lang-config">LuaAuthzProvider rights /path/to/lua/script.lua rights_handler
+&lt;Directory "/www/private"&gt;
+ Require rights member
+&lt;/Directory&gt;
+&lt;Directory "/www/admin"&gt;
+ Require rights admin
+&lt;/Directory&gt;</pre>
+
+
+<pre class="prettyprint lang-lua">--[[
+ This script has two user groups; members and admins, and whichever
+ is referred to by the "Require rights" directive is checked to see
+ if the authenticated user belongs to this group.
+]]--
+
+local members = { "rbowen", "humbedooh", "igalic", "covener" }
+local admins = { "humbedooh" }
+
+function rights_handler(r, what)
+ if r.user == nil then
+ return apache2.AUTHZ_AUTHZ_DENIED_NO_USER
+ end
+ if what == "member" then
+ for k, v in pairs(members) do
+ if r.user == v then
+ return apache2.AUTHZ_GRANTED
+ end
+ end
+ elseif what == "admin" then
+ for k, v in pairs(admins) do
+ if r.user == v then
+ return apache2.AUTHZ_GRANTED
+ end
+ end
+ end
+ return apache2.AUTHZ_DENIED
+end</pre>
+
+</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="loadbalancing" id="loadbalancing">Example 5: A rudimentary load balancer</a> <a title="Permanent link" href="#loadbalancing" class="permalink">&para;</a></h2>
+<p>
+ This is an example of how you can create a load balancing mechanism.
+ In this example, we will be setting/getting the number of requests served
+ by each backend using IVM variables, and preferring the backend with least
+ requests served in total:
+</p>
+<pre class="prettyprint lang-config">LuaHookTranslateName /path/to/script.lua proxy_handler</pre>
+
+
+<pre class="prettyprint lang-lua">--[[
+ This script uses a basic IVM table to determine where to
+ send the request.
+]]--
+
+local backends = {
+ "http://backend1.foo.com/",
+ "http://backend2.foo.com/",
+ "http://backend3.foo.com/"
+}
+
+function pick_backend(r)
+ local chosen_backend = 1 -- default to backend1
+ local lowest_count = nil
+ for i = 1, #backends, 1 do -- Loop through all backends
+ local count = r:ivm_get("proxy_request_count_" .. i)
+ if not count then -- If this backend hasn't been used at all, prefer it
+ chosen_backend = i
+ lowest_count = 0
+ break
+ end
+ if not lowest_count or lowest_count &gt; count then -- If this backend has had less requests, pick it for now
+ chosen_backend = i
+ lowest_count = count
+ end
+ end
+ lowest_count = lowest_count + 1
+ r:ivm_set("proxy_request_count_" .. chosen_backend, lowest_count)
+ return chosen_backend
+end
+
+function proxy_handler(r)
+ local backend = pick_backend(r) -- Pick a backend based on no. of requests served
+ r.handler = "proxy-server"
+ r.proxyreq = apache2.PROXYREQ_REVERSE
+ r.filename = "proxy:" .. backends[backend] .. r.uri
+ return apache2.DECLINED -- let the proxy handler do this instead
+end</pre>
+
+</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="map_handler" id="map_handler">Example 6: Overlays using LuaMapHandler</a> <a title="Permanent link" href="#map_handler" class="permalink">&para;</a></h2>
+<p>
+Coming soon!
+</p>
+<pre class="prettyprint lang-config">LuaMapHandler ^/portal/([a-z]+)/ /path/to/lua/script.lua handle_$1</pre>
+
+</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="section">
+<h2><a name="mod_status_lua" id="mod_status_lua">Example 6: Basic Lua scripts</a> <a title="Permanent link" href="#mod_status_lua" class="permalink">&para;</a></h2>
+<p>
+Also coming soon
+</p>
+</div></div>
+<div class="bottomlang">
+<p><span>Available Languages: </span><a href="../en/developer/lua.html" title="English">&nbsp;en&nbsp;</a></p>
+</div><div class="top"><a href="#page-header"><img src="../images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&amp;A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Freenode, or sent to our <a href="https://httpd.apache.org/lists.html">mailing lists</a>.</div>
+<script type="text/javascript"><!--//--><![CDATA[//><!--
+var comments_shortname = 'httpd';
+var comments_identifier = 'http://httpd.apache.org/docs/trunk/developer/lua.html';
+(function(w, d) {
+ if (w.location.hostname.toLowerCase() == "httpd.apache.org") {
+ d.write('<div id="comments_thread"><\/div>');
+ var s = d.createElement('script');
+ s.type = 'text/javascript';
+ s.async = true;
+ s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier;
+ (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s);
+ }
+ else {
+ d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>');
+ }
+})(window, document);
+//--><!]]></script></div><div id="footer">
+<p class="apache">Copyright 2020 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p>
+<p class="menu"><a href="../mod/">Modules</a> | <a href="../mod/quickreference.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="../glossary.html">Glossary</a> | <a href="../sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!--
+if (typeof(prettyPrint) !== 'undefined') {
+ prettyPrint();
+}
+//--><!]]></script>
+</body></html> \ No newline at end of file