mirror of
				https://github.com/apache/httpd.git
				synced 2025-10-30 08:05:39 +03:00 
			
		
		
		
	git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1479253 13f79535-47bb-0310-9956-ffa450edef68
		
			
				
	
	
		
			586 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
			
		
		
	
	
			586 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
| <?xml version='1.0' encoding='UTF-8' ?>
 | |
| <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
 | |
| <?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
 | |
| 
 | |
| <!-- $LastChangedRevision$ -->
 | |
| 
 | |
| <!--
 | |
|  Licensed to the Apache Software Foundation (ASF) under one or more
 | |
|  contributor license agreements.  See the NOTICE file distributed with
 | |
|  this work for additional information regarding copyright ownership.
 | |
|  The ASF licenses this file to You under the Apache License, Version 2.0
 | |
|  (the "License"); you may not use this file except in compliance with
 | |
|  the License.  You may obtain a copy of the License at
 | |
| 
 | |
|      http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
|  Unless required by applicable law or agreed to in writing, software
 | |
|  distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  See the License for the specific language governing permissions and
 | |
|  limitations under the License.
 | |
| -->
 | |
| 
 | |
| <manualpage metafile="lua.xml.meta">
 | |
| <parentdocument href="./">Developer</parentdocument>
 | |
| 
 | |
|   <title>Creating hooks and scripts with mod_lua</title>
 | |
| 
 | |
| <summary>
 | |
| <p>This document expands on the <module>mod_lua</module> documentation and explores
 | |
|  additional ways of using mod_lua for writing hooks and scripts.</p>
 | |
| </summary>
 | |
| 
 | |
| <seealso><a href="../mod/mod_lua.html">mod_lua</a></seealso>
 | |
| <seealso><a href="modguide.html">Developing modules for Apache 2.4</a></seealso>
 | |
| <seealso><a href="request.html">Request Processing in Apache 2.4</a></seealso>
 | |
| <seealso><a href="hooks.html">Apache 2.x Hook Functions</a></seealso>
 | |
| 
 | |
| <section id="introduction"><title>Introduction</title>
 | |
| <section id="what"><title>What is mod_lua</title>
 | |
| <p>
 | |
| Stuff about what <module>mod_lua</module> is goes here.
 | |
| </p>
 | |
| </section>
 | |
| <section id="contents"><title>What we will be discussing in this document</title>
 | |
| <p>
 | |
| This document will discuss several cases where <module>mod_lua</module> 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>
 | |
| 
 | |
| </section>
 | |
| 
 | |
| <section id="prerequisites"><title>Prerequisites</title>
 | |
| <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>
 | |
| 
 | |
| 
 | |
| </section>
 | |
| </section>
 | |
| 
 | |
| <section id="enabling"><title>Optimizing mod_lua for production servers</title>
 | |
| 
 | |
| <section><title>Setting a scope for Lua states</title>
 | |
| <p>
 | |
| Setting the right <directive module="mod_lua">LuaScope</directive> 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 entirity 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>
 | |
| <highlight language="config">
 | |
| LuaScope once
 | |
| LuaScope thread
 | |
| LuaScope server 5 40
 | |
| </highlight>
 | |
| <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>
 | |
| </section>
 | |
| 
 | |
| <section><title>Using code caching</title>
 | |
| <p>
 | |
| By default, <module>mod_lua</module> 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 <directive module="mod_lua">LuaCodeCache</directive> 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 peformance, 
 | |
| 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>
 | |
| </section>
 | |
| 
 | |
| <section><title>Keeping the scope clean</title>
 | |
| <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>
 | |
| <highlight language="lua">
 | |
| --[[ This is good practice ]]--
 | |
| require "string"
 | |
| require "someLibrary"
 | |
| local masterTable = {}
 | |
| local constant = "Foo bar baz"
 | |
| 
 | |
| function handle(r)
 | |
|     do_stuff()
 | |
| end
 | |
| </highlight>
 | |
| <highlight language="lua">
 | |
| --[[ This is bad practice ]]--
 | |
| require "string"
 | |
| 
 | |
| function handle(r)
 | |
|     require "someLibrary"
 | |
|     local masterTable = {}
 | |
|     local constant = "Foo bar baz"
 | |
|     do_stuff()
 | |
| end
 | |
| </highlight>
 | |
| </section>
 | |
| 
 | |
| </section>
 | |
| 
 | |
| <section id="basic_remap"><title>Example 1: A basic remapping module</title>
 | |
| <p>
 | |
|     These first examples show how mod_lua can be used to rewrite URIs in the same 
 | |
|     way that one could do using <directive module="mod_alias">Alias</directive> or 
 | |
|     <directive module="mod_rewrite">RewriteRule</directive>, 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>
 | |
| 
 | |
| <highlight language="config">
 | |
| LuaHookTranslateName /path/too/foo.lua remap
 | |
| </highlight>
 | |
| 
 | |
| 
 | |
| <!-- BEGIN EXAMPLE CODE -->
 | |
| <highlight language="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
 | |
| </highlight>
 | |
| <!-- END EXAMPLE CODE -->
 | |
| 
 | |
| 
 | |
| <!-- BEGIN EXAMPLE CODE -->
 | |
| <highlight language="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 = apache2.regex(r, 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
 | |
| </highlight>
 | |
| <!-- END EXAMPLE CODE -->
 | |
| 
 | |
| <p>
 | |
| bla bla
 | |
| </p>
 | |
| </section>
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| <section id="mass_vhost"><title>Example 2: Mass virtual hosting</title>
 | |
| <p>
 | |
|     As with simple and advanced rewriting, you can use mod_lua for dynamically 
 | |
|     assigning a hostname to a specific document root, much like 
 | |
|     <module>mod_vhost_alias</module> 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>
 | |
| 
 | |
| <highlight language="config">
 | |
| LuaHookTranslateName /path/too/foo.lua mass_vhost
 | |
| </highlight>
 | |
| 
 | |
| 
 | |
| <!-- BEGIN EXAMPLE CODE -->
 | |
| <highlight language="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
 | |
| </highlight>
 | |
| <!-- END EXAMPLE CODE -->
 | |
| 
 | |
| 
 | |
| <!-- BEGIN EXAMPLE CODE -->
 | |
| <highlight language="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 < 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
 | |
| </highlight>
 | |
| <!-- END EXAMPLE CODE -->
 | |
| 
 | |
| <p>
 | |
| 
 | |
| </p>
 | |
| </section>
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| <section id="basic_auth"><title>Example 3: A basic authorization hook</title>
 | |
| <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>
 | |
| <highlight language="config">
 | |
| LuaHookAuthChecker /path/too/foo.lua check_auth
 | |
| </highlight>
 | |
| 
 | |
| <!-- BEGIN EXAMPLE CODE -->
 | |
| <highlight language="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() > 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
 | |
| </highlight>
 | |
| <!-- END EXAMPLE CODE -->
 | |
| 
 | |
| 
 | |
| <!-- BEGIN EXAMPLE CODE -->
 | |
| <highlight language="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() > 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 < 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
 | |
| </highlight>
 | |
| <!-- END EXAMPLE CODE -->
 | |
| 
 | |
| 
 | |
| </section>
 | |
| 
 | |
| <section id="authz"><title>Example 4: Authorization using LuaAuthzProvider</title>
 | |
| <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>
 | |
| <highlight language="config">
 | |
| LuaAuthzProvider rights /path/to/lua/script.lua rights_handler
 | |
| <Directory /www/private>
 | |
|     Require rights member
 | |
| </Directory>
 | |
| <Directory /www/admin>
 | |
|     Require rights admin
 | |
| </Directory>
 | |
| </highlight>
 | |
| 
 | |
| <highlight language="lua">
 | |
| --[[ 
 | |
|      This script has two user groups; members and admins, and whichever 
 | |
|      is refered 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
 | |
| </highlight>
 | |
| </section>
 | |
| 
 | |
| 
 | |
| <section id="loadbalancing"><title>Example 5: A rudimentary load balancer</title>
 | |
| <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>
 | |
| <highlight language="config">
 | |
| LuaHookTranslateName /path/to/script.lua proxy_handler
 | |
| </highlight>
 | |
| 
 | |
| <highlight language="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 > 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
 | |
| </highlight>
 | |
| </section>
 | |
| 
 | |
| <section id="map_handler"><title>Example 6: Overlays using LuaMapHandler</title>
 | |
| <p>
 | |
| Coming soon!
 | |
| </p>
 | |
| <highlight language="config">
 | |
| LuaMapHandler ^/portal/([a-z]+)/   /path/to/lua/script.lua handle_$1
 | |
| </highlight>
 | |
| </section>
 | |
| 
 | |
| <section id="mod_status_lua"><title>Example 6: Basic Lua scripts</title>
 | |
| <p>
 | |
| Also coming soon
 | |
| </p>
 | |
| </section>
 | |
| 
 | |
| 
 | |
| </manualpage>
 |