Spec-Zone.ru › Apache HTTP Server

Модуль Apache mod_lua

Описание: Обеспечивает Lua-хуки для различных частей обработки запроса httpd
Статус: Расширение
Идентификатор модуля: lua_module
Файл исходного кода: mod_lua.c
Совместимость: 2.3 и выше

Резюме

Этот модуль позволяет расширить сервер с помощью скриптов, написанных на языке программирования Lua. Точки расширения (хуки), доступные с mod_lua, включают многие хуки, доступные нативно скомпилированным модулям Apache HTTP Server, таким как отображение запросов на файлы, генерация динамических ответов, контроль доступа, аутентификация и авторизация

Дополнительную информацию о языке программирования Lua можно найти на сайте Lua.

Предупреждение

Этот модуль обладает большой властью над httpd, что является как сильной стороной, так и потенциальным риском безопасности. Не рекомендуется использовать этот модуль на сервере, который совместно используется с пользователями, которым вы не доверяете, так как он может быть использован для изменения внутренней работы httpd.

Базовая конфигурация

Основная директива загрузки модуля:

LoadModule lua_module modules/mod_lua.so

mod_lua предоставляет обработчик с именем lua-script, который можно использовать с директивой SetHandler или AddHandler:

<Files "*.lua">
    SetHandler lua-script
</Files>

Это заставит mod_lua обрабатывать запросы на файлы, заканчивающиеся на .lua, вызывая функцию handle этого файла.

Для большей гибкости см. LuaMapHandler.

Написание обработчиков

В API Apache HTTP Server обработчик — это особый вид хука, отвечающий за генерацию ответа. Примерами модулей, включающих обработчик, являются mod_proxy, mod_cgi, и mod_status.

mod_lua всегда пытается вызвать функцию Lua для обработчика, а не просто вычислить тело скрипта в стиле CGI. Функция обработчика выглядит примерно так:

example.lua
-- example handler require "string" --[[ This is the default method name for Lua handlers, see the optional function-name in the LuaMapHandler directive to choose a different entry point. --]] function handle(r) r.content_type = "text/plain" if r.method == 'GET' then r:puts("Hello Lua World!\n") for k, v in pairs( r:parseargs() ) do r:puts( string.format("%s: %s\n", k, v) ) end elseif r.method == 'POST' then r:puts("Hello Lua World!\n") for k, v in pairs( r:parsebody() ) do r:puts( string.format("%s: %s\n", k, v) ) end elseif r.method == 'PUT' then -- use our own Error contents r:puts("Unsupported HTTP method " .. r.method) r.status = 405 return apache2.OK else -- use the ErrorDocument return 501 end return apache2.OK end

Эта функция обработчика просто выводит uri или аргументы в формате формы в текстовую страницу.

Это означает (и на самом деле поощряет), что в одном скрипте может быть несколько обработчиков (или хуков, или фильтров).

Написание поставщиков авторизации

mod_authz_core предоставляет высокоуровневый интерфейс к авторизации, который намного проще в использовании, чем использование соответствующих хуков напрямую. Первый аргумент директивы Require указывает имя ответственного поставщика авторизации. Для любой строки Require, mod_authz_core вызовет поставщика авторизации с указанным именем, передавая остальную часть строки в качестве параметров. Затем поставщик проверит авторизацию и передаст результат как возвращаемое значение.

Поставщик авторизации обычно вызывается до аутентификации. Если ему нужно знать имя аутентифицированного пользователя (или если пользователь вообще будет аутентифицирован), поставщик должен вернуть apache2.AUTHZ_DENIED_NO_USER. Это заставит процесс аутентификации продолжиться и вызовет поставщика авторизации во второй раз.

Следующая функция поставщика авторизации принимает два аргумента: один IP-адрес и одно имя пользователя. Она позволит получить доступ с указанного IP-адреса без аутентификации или если аутентифицированный пользователь совпадает со вторым аргументом:

authz_provider.lua
require 'apache2' function authz_check_foo(r, ip, user) if r.useragent_ip == ip then return apache2.AUTHZ_GRANTED elseif r.user == nil then return apache2.AUTHZ_DENIED_NO_USER elseif r.user == user then return apache2.AUTHZ_GRANTED else return apache2.AUTHZ_DENIED end end

Следующая конфигурация регистрирует эту функцию как поставщика foo и настраивает ее для URL /:

LuaAuthzProvider foo authz_provider.lua authz_check_foo
<Location "/">
  Require foo 10.1.2.3 john_doe
</Location>

Написание хуков

Функции хуков — это способ, которым модули (и скрипты Lua) участвуют в обработке запросов. Каждый тип хука, предоставляемый сервером, предназначен для определенной цели, например, для сопоставления запросов с файловой системой, выполнения контроля доступа или установки типов MIME:

Фаза хука Директива mod_lua Описание
Быстрый обработчик LuaQuickHandler Это первый хук, который будет вызван после того, как запрос будет сопоставлен с хостом или виртуальным хостом
Преобразовать имя до перевода LuaHookPreTranslateName Эта фаза преобразует запрашиваемый URI в имя файла в системе до декодирования. Модули, такие как mod_proxy, могут работать на этой фазе.
Преобразовать имя LuaHookTranslateName Эта фаза преобразует запрашиваемый URI в имя файла в системе. Модули, такие как mod_alias и mod_rewrite, работают на этой фазе.
Сопоставить со хранилищем LuaHookMapToStorage На этой фазе файлы сопоставляются с их физическим, кэшированным или внешним/проксированным хранилищем. Она может использоваться модулями проксирования или кэширования
Проверка доступа LuaHookAccessChecker На этой фазе проверяется, имеет ли клиент доступ к ресурсу. Эта фаза выполняется до аутентификации пользователя, поэтому будьте осторожны.
Проверка идентификатора пользователя LuaHookCheckUserID На этой фазе проверяется согласованный идентификатор пользователя
Проверка авторизации LuaHookAuthChecker или LuaAuthzProvider На этой фазе пользователь авторизуется на основе согласованных учетных данных, таких как идентификатор пользователя, сертификат клиента и т.д.
Проверка типа LuaHookTypeChecker На этой фазе проверяется запрашиваемый файл и назначается тип контента и обработчик
Фиксирование LuaHookFixups Это заключительная фаза «исправления всего» перед запуском обработчиков контента. Все последние изменения в запросе должны быть внесены здесь.
Обработчик контента fx. .lua файлы или через LuaMapHandler Здесь обрабатывается контент. Файлы читаются, анализируются, некоторые выполняются, и результат отправляется клиенту
Ведение журнала LuaHookLog После обработки запроса он входит в несколько фаз ведения журнала, которые записывают запрос в журнал ошибок или журнал доступа. Mod_lua может подключиться к началу этого процесса и управлять выводом данных в журнале.

Функции хуков передают объект запроса в качестве единственного аргумента (за исключением LuaAuthzProvider, которому также передаются аргументы из директивы Require). Они могут возвращать любое значение, в зависимости от хука, но чаще всего они возвращают OK, DONE или DECLINED, что можно записать на Lua как apache2.OK, apache2.DONE, или apache2.DECLINED, или же HTTP-код состояния.

translate_name.lua
-- example hook that rewrites the URI to a filesystem path. require 'apache2' function translate_name(r) if r.uri == "/translate-name" then r.filename = r.document_root .. "/find_me.txt" return apache2.OK end -- we don't care about this URL, give another module a chance return apache2.DECLINED end
translate_name2.lua
--[[ example hook that rewrites one URI to another URI. It returns a apache2.DECLINED to give other URL mappers a chance to work on the substitution, including the core translate_name hook which maps based on the DocumentRoot. Note: Use the early/late flags in the directive to make it run before or after mod_alias. --]] require 'apache2' function translate_name(r) if r.uri == "/translate-name" then r.uri = "/find_me.txt" return apache2.DECLINED end return apache2.DECLINED end

Структуры данных

request_rec

Переменная request_rec отображается как userdata. Она имеет metatable, что позволяет выполнять с ней полезные действия. В основном, она содержит те же поля, что и структура request_rec, многие из которых можно как читать, так и записывать. (Содержимое полей таблицы можно изменить, но сами поля нельзя установить в другие таблицы.)

Имя Тип Lua Запись Описание
allowoverrides строка нет Параметры AllowOverride, примененные к текущему запросу.
ap_auth_type строка нет Если был выполнен контроль аутентификации, это поле содержит тип аутентификации (например, basic)
args строка да Аргументы строки запроса, извлеченные из запроса (например, foo=bar&name=johnsmith)
assbackwards логическое значение нет Устанавливается в значение true, если это запрос в стиле HTTP/0.9 (например, GET /foo (без заголовков))
auth_name строка нет Имя области, используемой для авторизации (при необходимости).
banner строка нет Баннер сервера, например, Apache HTTP Server/2.4.3 openssl/0.9.8c
basic_auth_pw строка нет Пароль базовой аутентификации, переданный с этим запросом, если таковой есть
canonical_filename строка нет Каноническое имя файла запроса
content_encoding строка нет Кодировка содержимого текущего запроса
content_type строка да Тип содержимого текущего запроса, определенный на фазе type_check (например, image/gif или text/html)
context_prefix строка нет
context_document_root строка нет
document_root строка нет Корень документа хоста
err_headers_out таблица нет Среда MIME-заголовков для ответа, выводимая даже при ошибках и сохраняемая при внутренних переадресациях. Доступна в виде таблицы lua для итерации r:err_headers_out_table().
filename строка да Имя файла, которому сопоставлен запрос, например, /www/example.com/foo.txt. Его можно изменить на фазах pre-translate-name, translate-name или map-to-storage запроса, чтобы предоставить обработчик по умолчанию (или обработчики скриптов) другой файл, чем тот, который был запрошен.
handler строка да Имя обработчика, который должен обработать этот запрос, например, lua-script (если он должен обрабатываться mod_lua). Обычно устанавливается директивами AddHandler или SetHandler, но также может быть установлено mod_lua, чтобы позволить другому обработчику обработать конкретный запрос, который иначе не обрабатывался бы им.
headers_in таблица да Среда MIME-заголовков запроса. Она содержит заголовки, такие как Host, User-Agent, Referer и так далее. Доступна в виде таблицы lua для итерации r:headers_in_table().
headers_out таблица да Среда MIME-заголовков для ответа. Доступна в виде таблицы lua для итерации r:headers_out_table().
hostname строка нет Имя хоста, установленное заголовком Host: или полным URI.
is_https логическое значение нет Является ли этот запрос HTTPS
is_initial_req логическое значение нет Является ли этот запрос начальным или подзапросом
limit_req_body число нет Предельное значение размера тела запроса для этого запроса, или 0, если ограничений нет.
log_id строка нет Идентификатор для идентификации запроса в журналах доступа и ошибок.
method строка нет Метод запроса, например, GET или POST.
notes таблица да Список заметок, которые можно передавать от одного модуля к другому. Доступна в виде таблицы lua для итерации r:notes_table().
options строка нет Директива Options, примененная к текущему запросу.
path_info строка нет PATH_INFO, извлеченный из этого запроса.
port число нет Порт сервера, используемый запросом.
protocol строка нет Используемый протокол, например, HTTP/1.1
proxyreq строка да Указывает, является ли это запросом прокси. Это значение обычно устанавливается на фазе post_read_request/pre_translate_name/translate_name запроса.
range строка нет Содержимое заголовка Range:
remaining число нет Количество байт, оставшихся для чтения из тела запроса.
server_built строка нет Время сборки исполняемого файла сервера.
server_name строка нет Имя сервера для этого запроса.
some_auth_required логическое значение нет Требовалась ли/требовалась ли авторизация для этого запроса.
subprocess_env таблица да Переменные среды, установленные для этого запроса. Доступна в виде таблицы lua для итерации r:subprocess_env_table().
started число нет Время (пере)запуска сервера в секундах с начала эпохи (1 января 1970 г.)
status число да (Текущий) код HTTP-ответа для этого запроса, например, 200 или 404.
the_request строка нет Строка запроса, отправленная клиентом, например, GET /foo/bar HTTP/1.1.
unparsed_uri строка нет Необработанный URI запроса
uri строка да URI после обработки httpd
user строка да Если контроль аутентификации был выполнен, то здесь указывается имя аутентифицированного пользователя.
useragent_ip строка нет IP пользователя, совершившего запрос

Встроенные функции

Объект request_rec имеет (по крайней мере) следующие методы:

r:flush()   -- flushes the output buffer.
            -- Returns true if the flush was successful, false otherwise.

while we_have_stuff_to_send do
    r:puts("Bla bla bla\n") -- print something to client
    r:flush() -- flush the buffer (send to client)
    r.usleep(500000) -- fake processing time for 0.5 sec. and repeat
end
r:add_output_filter(filter_name) -- add an output filter:

r:add_output_filter("fooFilter") -- add the fooFilter to the output stream
r:sendfile(filename) -- sends an entire file to the client, using sendfile if supported by the current platform:

if use_sendfile_thing then
    r:sendfile("/var/www/large_file.img")
end
r:parseargs() -- returns two tables; one standard key/value table for regular GET data, 
              -- and one for multi-value data (fx. foo=1&foo=2&foo=3):

local GET, GETMULTI = r:parseargs()
r:puts("Your name is: " .. GET['name'] or "Unknown")
r:parsebody([sizeLimit]) -- parse the request body as a POST and return two lua tables,
                         -- just like r:parseargs().
                         -- An optional number may be passed to specify the maximum number 
                         -- of bytes to parse. Default is 8192 bytes:
                 
local POST, POSTMULTI = r:parsebody(1024*1024)
r:puts("Your name is: " .. POST['name'] or "Unknown")
r:puts("hello", " world", "!") -- print to response body, self explanatory
r:write("a single string") -- print to response body, self explanatory
r:escape_html("<html>test</html>") -- Escapes HTML code and returns the escaped result
r:base64_encode(string) -- Encodes a string using the Base64 encoding standard:

local encoded = r:base64_encode("This is a test") -- returns VGhpcyBpcyBhIHRlc3Q=
r:base64_decode(string) -- Decodes a Base64-encoded string:

local decoded = r:base64_decode("VGhpcyBpcyBhIHRlc3Q=") -- returns 'This is a test'
r:md5(string) -- Calculates and returns the MD5 digest of a string (binary safe):

local hash = r:md5("This is a test") -- returns ce114e4501d2f4e2dcea3e17b546f339
r:sha1(string) -- Calculates and returns the SHA1 digest of a string (binary safe):

local hash = r:sha1("This is a test") -- returns a54d88e06612d820bc3be72877c74f257b561b19
r:escape(string) -- URL-Escapes a string:

local url = "http://foo.bar/1 2 3 & 4 + 5"
local escaped = r:escape(url) -- returns 'http%3a%2f%2ffoo.bar%2f1+2+3+%26+4+%2b+5'
r:unescape(string) -- Unescapes an URL-escaped string:

local url = "http%3a%2f%2ffoo.bar%2f1+2+3+%26+4+%2b+5"
local unescaped = r:unescape(url) -- returns 'http://foo.bar/1 2 3 & 4 + 5'
r:construct_url(string) -- Constructs an URL from an URI

local url = r:construct_url(r.uri)
r.mpm_query(number) -- Queries the server for MPM information using ap_mpm_query:

local mpm = r.mpm_query(14)
if mpm == 1 then
    r:puts("This server uses the Event MPM")
end
r:expr(string) -- Evaluates an expr string.

if r:expr("%{HTTP_HOST} =~ /^www/") then
    r:puts("This host name starts with www")
end
r:scoreboard_process(a) -- Queries the server for information about the process at position a:

local process = r:scoreboard_process(1)
r:puts("Server 1 has PID " .. process.pid)
r:scoreboard_worker(a, b) -- Queries for information about the worker thread, b, in process a:

local thread = r:scoreboard_worker(1, 1)
r:puts("Server 1's thread 1 has thread ID " .. thread.tid .. " and is in " .. thread.status .. " status")
r:clock() -- Returns the current time with microsecond precision
r:requestbody(filename) -- Reads and returns the request body of a request.
                -- If 'filename' is specified, it instead saves the
                -- contents to that file:
                
local input = r:requestbody()
r:puts("You sent the following request body to me:\n")
r:puts(input)
r:add_input_filter(filter_name) -- Adds 'filter_name' as an input filter
r.module_info(module_name) -- Queries the server for information about a module

local mod = r.module_info("mod_lua.c")
if mod then
    for k, v in pairs(mod.commands) do
       r:puts( ("%s: %s\n"):format(k,v)) -- print out all directives accepted by this module
    end
end
r:loaded_modules() -- Returns a list of modules loaded by httpd:

for k, module in pairs(r:loaded_modules()) do
    r:puts("I have loaded module " .. module .. "\n")
end
r:runtime_dir_relative(filename) -- Compute the name of a run-time file (e.g., shared memory "file") 
                         -- relative to the appropriate run-time directory.
r:server_info() -- Returns a table containing server information, such as 
                -- the name of the httpd executable file, mpm used etc.
r:set_document_root(file_path) -- Sets the document root for the request to file_path
r:set_context_info(prefix, docroot) -- Sets the context prefix and context document root for a request
r:os_escape_path(file_path) -- Converts an OS path to a URL in an OS dependent way
r:escape_logitem(string) -- Escapes a string for logging
r.strcmp_match(string, pattern) -- Checks if 'string' matches 'pattern' using strcmp_match (globs).
                        -- fx. whether 'www.example.com' matches '*.example.com':
                        
local match = r.strcmp_match("foobar.com", "foo*.com")
if match then 
    r:puts("foobar.com matches foo*.com")
end
r:set_keepalive() -- Sets the keepalive status for a request. Returns true if possible, false otherwise.
r:make_etag() -- Constructs and returns the etag for the current request.
r:send_interim_response(clear) -- Sends an interim (1xx) response to the client.
                       -- if 'clear' is true, available headers will be sent and cleared.
r:custom_response(status_code, string) -- Construct and set a custom response for a given status code.
                               -- This works much like the ErrorDocument directive:
                               
r:custom_response(404, "Baleted!")
r.exists_config_define(string) -- Checks whether a configuration definition exists or not:

if r.exists_config_define("FOO") then
    r:puts("httpd was probably run with -DFOO, or it was defined in the configuration")
end
r:state_query(string) -- Queries the server for state information
r:stat(filename [,wanted]) -- Runs stat() on a file, and returns a table with file information:

local info = r:stat("/var/www/foo.txt")
if info then
    r:puts("This file exists and was last modified at: " .. info.modified)
end
r:regex(string, pattern [,flags]) -- Runs a regular expression match on a string, returning captures if matched:

local matches = r:regex("foo bar baz", [[foo (\w+) (\S*)]])
if matches then
    r:puts("The regex matched, and the last word captured ($2) was: " .. matches[2])
end

-- Example ignoring case sensitivity:
local matches = r:regex("FOO bar BAz", [[(foo) bar]], 1)

-- Flags can be a bitwise combination of:
-- 0x01: Ignore case
-- 0x02: Multiline search
r.usleep(number_of_microseconds) -- Puts the script to sleep for a given number of microseconds.
r:dbacquire(dbType[, dbParams]) -- Acquires a connection to a database and returns a database class.
                        -- See 'Database connectivity' for details.
r:ivm_set("key", value) -- Set an Inter-VM variable to hold a specific value.
                        -- These values persist even though the VM is gone or not being used,
                        -- and so should only be used if MaxConnectionsPerChild is > 0
                        -- Values can be numbers, strings and booleans, and are stored on a 
                        -- per process basis (so they won't do much good with a prefork mpm)
                        
r:ivm_get("key")        -- Fetches a variable set by ivm_set. Returns the contents of the variable
                        -- if it exists or nil if no such variable exists.
                        
-- An example getter/setter that saves a global variable outside the VM:
function handle(r)
    -- First VM to call this will get no value, and will have to create it
    local foo = r:ivm_get("cached_data")
    if not foo then
        foo = do_some_calcs() -- fake some return value
        r:ivm_set("cached_data", foo) -- set it globally
    end
    r:puts("Cached data is: ", foo)
end
r:htpassword(string [,algorithm [,cost]]) -- Creates a password hash from a string.
                                          -- algorithm: 0 = APMD5 (default), 1 = SHA, 2 = BCRYPT, 3 = CRYPT.
                                          -- cost: only valid with BCRYPT algorithm (default = 5).
r:mkdir(dir [,mode]) -- Creates a directory and sets mode to optional mode parameter.
r:mkrdir(dir [,mode]) -- Creates directories recursive and sets mode to optional mode parameter.
r:rmdir(dir) -- Removes a directory.
r:touch(file [,mtime]) -- Sets the file modification time to current time or to optional mtime msec value.
r:get_direntries(dir) -- Returns a table with all directory entries.

function handle(r)
  local dir = r.context_document_root
  for _, f in ipairs(r:get_direntries(dir)) do
    local info = r:stat(dir .. "/" .. f)
    if info then
      local mtime = os.date(fmt, info.mtime / 1000000)
      local ftype = (info.filetype == 2) and "[dir] " or "[file]"
      r:puts( ("%s %s %10i %s\n"):format(ftype, mtime, info.size, f) )
    end
  end
end
r.date_parse_rfc(string) -- Parses a date/time string and returns seconds since epoche.
r:getcookie(key) -- Gets a HTTP cookie
r:setcookie{
  key = [key],
  value = [value],
  expires = [expiry],
  secure = [boolean],
  httponly = [boolean],
  path = [path],
  domain = [domain]
} -- Sets a HTTP cookie, for instance:

r:setcookie{
  key = "cookie1",
  value = "HDHfa9eyffh396rt",
  expires = os.time() + 86400,
  secure = true
}
r:wsupgrade() -- Upgrades a connection to WebSockets if possible (and requested):
if r:wsupgrade() then -- if we can upgrade:
    r:wswrite("Welcome to websockets!") -- write something to the client
    r:wsclose()  -- goodbye!
end
r:wsread() -- Reads a WebSocket frame from a WebSocket upgraded connection (see above):

local line, isFinal = r:wsread() -- isFinal denotes whether this is the final frame.
                                 -- If it isn't, then more frames can be read
r:wswrite("You wrote: " .. line)
r:wswrite(line) -- Writes a frame to a WebSocket client:
r:wswrite("Hello, world!")
r:wsclose() -- Closes a WebSocket request and terminates it for httpd:

if r:wsupgrade() then
    r:wswrite("Write something: ")
    local line = r:wsread() or "nothing"
    r:wswrite("You wrote: " .. line);
    r:wswrite("Goodbye!")
    r:wsclose()
end

Функции ведения журнала

-- examples of logging messages
r:trace1("This is a trace log message") -- trace1 through trace8 can be used
r:debug("This is a debug log message")
r:info("This is an info log message")
r:notice("This is a notice log message")
r:warn("This is a warn log message")
r:err("This is an err log message")
r:alert("This is an alert log message")
r:crit("This is a crit log message")
r:emerg("This is an emerg log message")

Пакет apache2

Доступен пакет apache2 с (по крайней мере) следующим содержимым.

apache2.OK
внутренняя константа OK. Обработчики должны возвращать ее, если они обработают запрос.
apache2.DECLINED
внутренняя константа DECLINED. Обработчики должны возвращать ее, если они не будут обрабатывать запрос.
apache2.DONE
внутренняя константа DONE.
apache2.version
Строка версии сервера Apache HTTP
apache2.HTTP_MOVED_TEMPORARILY
Код состояния HTTP
apache2.PROXYREQ_NONE, apache2.PROXYREQ_PROXY, apache2.PROXYREQ_REVERSE, apache2.PROXYREQ_RESPONSE
Внутренние константы, используемые mod_proxy
apache2.AUTHZ_DENIED, apache2.AUTHZ_GRANTED, apache2.AUTHZ_NEUTRAL, apache2.AUTHZ_GENERAL_ERROR, apache2.AUTHZ_DENIED_NO_USER
Внутренние константы, используемые mod_authz_core

(Другие коды состояния HTTP пока не реализованы.)

Изменение содержимого с помощью Lua-фильтров

Функции-фильтры, реализованные с помощью LuaInputFilter или LuaOutputFilter, спроектированы как функции в трех этапах без блокировок, использующие сопрограммы для приостановки и возобновления функции по мере поступления ведер по цепочке фильтров. Основная структура такой функции:

function filter(r)
    -- Our first yield is to signal that we are ready to receive buckets.
    -- Before this yield, we can set up our environment, check for conditions,
    -- and, if we deem it necessary, decline filtering a request altogether:
    if something_bad then
        return -- This would skip this filter.
    end
    -- Regardless of whether we have data to prepend, a yield MUST be called here.
    -- Note that only output filters can prepend data. Input filters must use the 
    -- final stage to append data to the content.
    coroutine.yield([optional header to be prepended to the content])
    
    -- After we have yielded, buckets will be sent to us, one by one, and we can 
    -- do whatever we want with them and then pass on the result.
    -- Buckets are stored in the global variable 'bucket', so we create a loop
    -- that checks if 'bucket' is not nil:
    while bucket ~= nil do
        local output = mangle(bucket) -- Do some stuff to the content
        coroutine.yield(output) -- Return our new content to the filter chain
    end

    -- Once the buckets are gone, 'bucket' is set to nil, which will exit the 
    -- loop and land us here. Anything extra we want to append to the content
    -- can be done by doing a final yield here. Both input and output filters 
    -- can append data to the content in this phase.
    coroutine.yield([optional footer to be appended to the content])
end

Подключение к базам данных

Mod_lua реализует простую функцию работы с базами данных для запросов и выполнения команд в самых популярных базах данных (mySQL, PostgreSQL, FreeTDS, ODBC, SQLite, Oracle), а также mod_dbd.

Пример ниже демонстрирует, как получить дескриптор базы данных и вернуть информацию из таблицы:

function handle(r)
    -- Acquire a database handle
    local database, err = r:dbacquire("mysql", "server=localhost,user=someuser,pass=somepass,dbname=mydb")
    if not err then
        -- Select some information from it
        local results, err = database:select(r, "SELECT `name`, `age` FROM `people` WHERE 1")
        if not err then
            local rows = results(0) -- fetch all rows synchronously
            for k, row in pairs(rows) do
                r:puts( string.format("Name: %s, Age: %s<br/>", row[1], row[2]) )
            end
        else
            r:puts("Database query error: " .. err)
        end
        database:close()
    else
        r:puts("Could not connect to the database: " .. err)
    end
end

Для использования mod_dbd, укажите mod_dbd как тип базы данных или оставьте поле пустым:

local database = r:dbacquire("mod_dbd")

Объект базы данных и содержащиеся в нем функции

Объект базы данных, возвращаемый функцией dbacquire, имеет следующие методы:

Обычный выбор и запрос из базы данных:

-- Run a statement and return the number of rows affected:
local affected, errmsg = database:query(r, "DELETE FROM `tbl` WHERE 1")

-- Run a statement and return a result set that can be used synchronously or async:
local result, errmsg = database:select(r, "SELECT * FROM `people` WHERE 1")

Использование подготовленных запросов (рекомендуется):

-- Create and run a prepared statement:
local statement, errmsg = database:prepare(r, "DELETE FROM `tbl` WHERE `age` > %u")
if not errmsg then
    local result, errmsg = statement:query(20) -- run the statement with age > 20
end

-- Fetch a prepared statement from a DBDPrepareSQL directive:
local statement, errmsg = database:prepared(r, "someTag")
if not errmsg then
    local result, errmsg = statement:select("John Doe", 123) -- inject the values "John Doe" and 123 into the statement
end

Обработка значений, закрытие баз данных и т. д.:

-- Escape a value for use in a statement:
local escaped = database:escape(r, [["'|blabla]])

-- Close a database connection and free up handles:
database:close()

-- Check whether a database connection is up and running:
local connected = database:active()

Работа с наборами результатов

Набор результатов, возвращаемый db:select или функциями подготовленных запросов, созданными через db:prepare, может использоваться для извлечения строк синхронно или асинхронно, в зависимости от указанного номера строки:
result(0) извлекает все строки синхронно, возвращая таблицу строк.
result(-1) извлекает следующую доступную строку в наборе асинхронно.
result(N) извлекает строку с номером N, асинхронно:

-- fetch a result set using a regular query:
local result, err = db:select(r, "SELECT * FROM `tbl` WHERE 1")

local rows = result(0) -- Fetch ALL rows synchronously
local row = result(-1) -- Fetch the next available row, asynchronously
local row = result(1234) -- Fetch row number 1234, asynchronously
local row = result(-1, true) -- Fetch the next available row, using row names as key indexes.

Можно создать функцию, которая возвращает итерационную функцию для итерации по всем строкам синхронно или асинхронно, в зависимости от аргумента async:

function rows(resultset, async)
    local a = 0
    local function getnext()
        a = a + 1
        local row = resultset(-1)
        return row and a or nil, row
    end
    if not async then
        return pairs(resultset(0))
    else
        return getnext, self
    end
end

local statement, err = db:prepare(r, "SELECT * FROM `tbl` WHERE `age` > %u")
if not err then
     -- fetch rows asynchronously:
    local result, err = statement:select(20)
    if not err then
        for index, row in rows(result, true) do
            ....
        end
    end

     -- fetch rows synchronously:
    local result, err = statement:select(20)
    if not err then
        for index, row in rows(result, false) do
            ....
        end
    end
end

Закрытие соединения с базой данных

Обработки баз данных должны быть закрыты с использованием database:close() когда они больше не нужны. Если вы не закроете их вручную, они в конечном итоге будут удалены сборщиком мусора и закрыты mod_lua, но у вас может накопиться слишком много неиспользуемых подключений к базе данных, если вы оставите закрытие mod_lua. По существу, следующие два способа эквивалентны:

-- Method 1: Manually close a handle
local database = r:dbacquire("mod_dbd")
database:close() -- All done

-- Method 2: Letting the garbage collector close it
local database = r:dbacquire("mod_dbd")
database = nil -- throw away the reference
collectgarbage() -- close the handle via GC

Меры предосторожности при работе с базами данных

Хотя стандартные функции query и run свободно доступны, рекомендуется использовать подготовленные запросы по возможности, чтобы оптимизировать производительность (если обработка базы данных существует долго) и свести к минимуму риск атак с использованием SQL-инъекций. run и query следует использовать только тогда, когда в операторе нет вставленных переменных (статический оператор). При использовании динамических операторов используйте db:prepare или db:prepared.

Директива LuaAuthzProvider

Описание: Подключить функцию поставщика авторизации к mod_authz_core
Синтаксис:
LuaAuthzProvider provider_name /path/to/lua/script.lua function_name
Контекст: настройка сервера
Статус: Расширение
Модуль: mod_lua
Совместимость: 2.4.3 и новее

После регистрации lua-функции как поставщика авторизации она может быть использована с директивой Require:

LuaRoot "/usr/local/apache2/lua"
LuaAuthzProvider foo authz.lua authz_check_foo
<Location "/">
  Require foo johndoe
</Location>
require "apache2"
function authz_check_foo(r, who)
    if r.user ~= who then return apache2.AUTHZ_DENIED
    return apache2.AUTHZ_GRANTED
end

Директива LuaCodeCache

Описание: Настроить кэш скомпилированного кода.
Синтаксис:
LuaCodeCache stat|forever|never
Значение по умолчанию:
LuaCodeCache stat
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Укажите поведение кэша кода в оперативной памяти. Значение по умолчанию — stat, которое отображает верхний уровень скрипта (а не включенные в него) каждый раз, когда этот файл нужен, и перезагружает его, если время изменения указывает, что он новее, чем загруженный ранее. Другие значения заставляют его хранить файл в кэше навсегда (не проверять и не перезагружать) или никогда не кэшировать этот файл.

В общем случае stat или forever подходят для рабочей среды, а stat или never — для разработки.

Примеры:

LuaCodeCache stat
LuaCodeCache forever
LuaCodeCache never

Директива LuaHookAccessChecker

Описание: Предоставьте обработку для фазы access_checker обработки запроса
Синтаксис:
LuaHookAccessChecker /path/to/lua/script.lua hook_function_name [early|late]
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua
Совместимость: Дополнительный третий аргумент поддерживается в 2.3.15 и более поздних версиях

Добавьте свою обработку в фазу access_checker. Функция обработчика доступа обычно возвращает OK, DECLINED или HTTP_FORBIDDEN.

Порядок

Дополнительные аргументы «early» или «late» управляют тем, когда этот скрипт выполняется относительно других модулей.

Директива LuaHookAuthChecker

Описание: Предоставьте обработку для фазы auth_checker обработки запроса
Синтаксис:
LuaHookAuthChecker /path/to/lua/script.lua hook_function_name [early|late]
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua
Совместимость: Дополнительный третий аргумент поддерживается в 2.3.15 и более поздних версиях

Вызовите lua-функцию на фазе auth_checker обработки запроса. Это можно использовать для реализации произвольной проверки аутентификации и авторизации. Очень простой пример:

require 'apache2'

-- fake authcheck hook
-- If request has no auth info, set the response header and
-- return a 401 to ask the browser for basic auth info.
-- If request has auth info, don't actually look at it, just
-- pretend we got userid 'foo' and validated it.
-- Then check if the userid is 'foo' and accept the request.
function authcheck_hook(r)

   -- look for auth info
   auth = r.headers_in['Authorization']
   if auth ~= nil then
     -- fake the user
     r.user = 'foo'
   end

   if r.user == nil then
      r:debug("authcheck: user is nil, returning 401")
      r.err_headers_out['WWW-Authenticate'] = 'Basic realm="WallyWorld"'
      return 401
   elseif r.user == "foo" then
      r:debug('user foo: OK')
   else
      r:debug("authcheck: user='" .. r.user .. "'")
      r.err_headers_out['WWW-Authenticate'] = 'Basic realm="WallyWorld"'
      return 401
   end
   return apache2.OK
end

Порядок

Дополнительные аргументы «early» или «late» управляют тем, когда этот скрипт выполняется относительно других модулей.

Директива LuaHookCheckUserID

Описание: Предоставьте обработку для фазы check_user_id обработки запроса
Синтаксис:
LuaHookCheckUserID /path/to/lua/script.lua hook_function_name [early|late]
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua
Совместимость: Дополнительный третий аргумент поддерживается в 2.3.15 и более поздних версиях

...

Порядок

Дополнительные аргументы «early» или «late» управляют тем, когда этот скрипт выполняется относительно других модулей.

Директива LuaHookFixups

Описание: Предоставьте обработку для фазы fixups обработки запроса
Синтаксис:
LuaHookFixups /path/to/lua/script.lua hook_function_name
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

То же, что и LuaHookTranslateName, но выполняется на фазе fixups

Директива LuaHookInsertFilter

Описание: Предоставьте обработку для фазы insert_filter обработки запроса
Синтаксис:
LuaHookInsertFilter /path/to/lua/script.lua hook_function_name
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Не реализовано

Директива LuaHookLog

Описание: Предоставьте обработку для фазы записи в лог обработки запроса
Синтаксис:
LuaHookLog /path/to/lua/script.lua log_function_name
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Этот простой обработчик ведения журнала позволяет запускать функцию, когда httpd входит в фазу ведения журнала запроса. С его помощью вы можете добавлять данные в свои журналы, обрабатывать данные перед записью обычного журнала или предотвращать создание записи журнала. Чтобы предотвратить обычное ведение журнала, просто верните apache2.DONE в обработчике ведения журнала, в противном случае верните apache2.OK чтобы сказать httpd вести журнал как обычно.

Пример:

LuaHookLog "/path/to/script.lua" logger
-- /path/to/script.lua --
function logger(r)
    -- flip a coin:
    -- If 1, then we write to our own Lua log and tell httpd not to log
    -- in the main log.
    -- If 2, then we just sanitize the output a bit and tell httpd to 
    -- log the sanitized bits.

    if math.random(1,2) == 1 then
        -- Log stuff ourselves and don't log in the regular log
        local f = io.open("/foo/secret.log", "a")
        if f then
            f:write("Something secret happened at " .. r.uri .. "\n")
            f:close()
        end
        return apache2.DONE -- Tell httpd not to use the regular logging functions
    else
        r.uri = r.uri:gsub("somesecretstuff", "") -- sanitize the URI
        return apache2.OK -- tell httpd to log it.
    end
end

Директива LuaHookMapToStorage

Описание: Предоставьте обработку для фазы map_to_storage обработки запроса
Синтаксис:
LuaHookMapToStorage /path/to/lua/script.lua hook_function_name
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Как LuaHookTranslateName но выполняется на фазе map-to-storage запроса. Модули, такие как mod_cache, работают на этой фазе, что делает её интересным примером того, что здесь нужно сделать:

LuaHookMapToStorage "/path/to/lua/script.lua" check_cache
require"apache2"
cached_files = {}

function read_file(filename) 
    local input = io.open(filename, "r")
    if input then
        local data = input:read("*a")
        cached_files[filename] = data
        file = cached_files[filename]
        input:close()
    end
    return cached_files[filename]
end

function check_cache(r)
    if r.filename:match("%.png$") then -- Only match PNG files
        local file = cached_files[r.filename] -- Check cache entries
        if not file then
            file = read_file(r.filename)  -- Read file into cache
        end
        if file then -- If file exists, write it out
            r.status = 200
            r:write(file)
            r:info(("Sent %s to client from cache"):format(r.filename))
            return apache2.DONE -- skip default handler for PNG files
        end
    end
    return apache2.DECLINED -- If we had nothing to do, let others serve this.
end

Директива LuaHookPreTranslate

Описание: Предоставьте обработку для фазы pre_translate обработки запроса
Синтаксис:
LuaHookPreTranslate /path/to/lua/script.lua hook_function_name
Контекст: настройка сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

То же, что и LuaHookTranslateName, но выполняется на фазе pre_translate, где путь URI не декодирован в процентах.

Директива LuaHookTranslateName

Описание: Предоставьте обработку для фазы translate name обработки запроса
Синтаксис:
LuaHookTranslateName /path/to/lua/script.lua hook_function_name [early|late]
Контекст: настройка сервера, виртуальный хост
Переопределение: Все
Статус: Расширение
Модуль: mod_lua
Совместимость: Дополнительный третий аргумент поддерживается в 2.3.15 и более поздних версиях

Добавьте обработку (в APR_HOOK_MIDDLE) к фазе обработки имени запроса. Функция обработки получает один аргумент, request_rec, и должна вернуть код состояния, который является либо кодом HTTP-ошибки, либо константами, определёнными в модуле apache2: apache2.OK, apache2.DECLINED или apache2.DONE.

Для тех, кто не знаком с обработками, по существу каждая обработка вызывается, пока одна из них не вернёт apache2.OK. Если ваша обработка не хочет выполнять перевод, она должна просто вернуть apache2.DECLINED. Если запрос должен быть остановлен, то верните apache2.DONE.

Пример:

# httpd.conf
LuaHookTranslateName "/scripts/conf/hooks.lua" silly_mapper
-- /scripts/conf/hooks.lua --
require "apache2"
function silly_mapper(r)
    if r.uri == "/" then
        r.filename = "/var/www/home.lua"
        return apache2.OK
    else
        return apache2.DECLINED
    end
end

Контекст

Эта директива недействительна в контексте <Directory>, <Files> или .htaccess.

Порядок

Дополнительные аргументы «early» или «late» управляют тем, когда этот скрипт выполняется относительно других модулей.

Директива LuaHookTypeChecker

Описание: Предоставляет хук для фазы type_checker обработки запроса
Синтаксис:
LuaHookTypeChecker /path/to/lua/script.lua hook_function_name
Контекст: настройки сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Данная директива предоставляет хук для фазы type_checker обработки запроса. На этой фазе запросам назначается тип контента и обработчик, и таким образом можно изменить тип и обработчик на основе входных данных:

LuaHookTypeChecker "/path/to/lua/script.lua" type_checker
    function type_checker(r)
        if r.uri:match("%.to_gif$") then -- match foo.png.to_gif
            r.content_type = "image/gif" -- assign it the image/gif type
            r.handler = "gifWizard"      -- tell the gifWizard module to handle this
            r.filename = r.uri:gsub("%.to_gif$", "") -- fix the filename requested
            return apache2.OK
        end

        return apache2.DECLINED
    end

Директива LuaInherit

Описание: Управляет тем, как родительские разделы конфигурации объединяются в дочерние
Синтаксис:
LuaInherit none|parent-first|parent-last
По умолчанию:
LuaInherit parent-first
Контекст: настройки сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua
Совместимость: 2.4.0 и более поздние версии

По умолчанию, если используются директивы LuaHook* в перекрывающихся разделах конфигурации Directory или Location, скрипты, определённые в более специфичном разделе, выполняются после скриптов, определённых в более общем разделе (LuaInherit parent-first). Вы можете изменить этот порядок или вообще исключить применение родительского контекста.

В предыдущих версиях 2.3.x по умолчанию игнорировались директивы LuaHook* из родительских разделов конфигурации.

Директива LuaInputFilter

Описание: Предоставляет функцию Lua для фильтрации входного контента
Синтаксис:
LuaInputFilter filter_name /path/to/lua/script.lua function_name
Контекст: настройки сервера
Статус: Расширение
Модуль: mod_lua
Совместимость: 2.4.5 и более поздние версии

Предоставляет возможность добавить функцию Lua в качестве фильтра входных данных. Как и в случае с фильтрами вывода, фильтры ввода работают как сопрограммы, сначала приостанавливаются перед отправкой буферов, затем приостанавливаются всякий раз, когда нужно передать пакет дальше по цепочке, и, наконец (по желанию), приостанавливаются для добавления чего-либо к входным данным. Глобальная переменная bucket хранит пакеты по мере их передачи Lua-скрипту:

LuaInputFilter myInputFilter "/www/filter.lua" input_filter
<Files "*.lua">
  SetInputFilter myInputFilter
</Files>
--[[
    Example input filter that converts all POST data to uppercase.
]]--
function input_filter(r)
    print("luaInputFilter called") -- debug print
    coroutine.yield() -- Yield and wait for buckets
    while bucket do -- For each bucket, do...
        local output = string.upper(bucket) -- Convert all POST data to uppercase
        coroutine.yield(output) -- Send converted data down the chain
    end
    -- No more buckets available.
    coroutine.yield("&filterSignature=1234") -- Append signature at the end
end

Фильтр ввода поддерживает отказ/пропуск фильтра, если он нежелателен:

function input_filter(r)
    if not good then
        return -- Simply deny filtering, passing on the original content instead
    end
    coroutine.yield() -- wait for buckets
    ... -- insert filter stuff here
end

См. "Изменение содержимого с помощью Lua-фильтров" для получения дополнительной информации.

Директива LuaMapHandler

Описание: Сопоставление пути с обработчиком lua
Синтаксис:
LuaMapHandler uri-pattern /path/to/lua/script.lua [function-name]
Контекст: настройки сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Данная директива сопоставляет шаблон URI с вызовом определенной функции обработчика в определенном файле. Она использует регулярные выражения PCRE для сопоставления URI и поддерживает интерполяцию групп совпадений как в пути к файлу, так и в имени функции. Будьте внимательны при написании регулярных выражений, чтобы избежать проблем безопасности.

Примеры:

LuaMapHandler "/(\w+)/(\w+)" "/scripts/$1.lua" "handle_$2"

Это сопоставит URI, такие как /photos/show?id=9, с файлом /scripts/photos.lua и вызовет функцию обработчика handle_show в lua-виртуальной машине после загрузки этого файла.

LuaMapHandler "/bingo" "/scripts/wombat.lua"

Это вызовет функцию "handle", которая является по умолчанию, если имя конкретной функции не указано.

Директива LuaOutputFilter

Описание: Предоставляет функцию Lua для фильтрации выходного контента
Синтаксис:
LuaOutputFilter filter_name /path/to/lua/script.lua function_name
Контекст: настройки сервера
Статус: Расширение
Модуль: mod_lua
Совместимость: 2.4.5 и более поздние версии

Предоставляет возможность добавить функцию Lua в качестве фильтра выходных данных. Как и в случае с фильтрами ввода, фильтры вывода работают как сопрограммы, сначала приостанавливаются перед отправкой буферов, затем приостанавливаются всякий раз, когда нужно передать пакет дальше по цепочке, и, наконец (по желанию), приостанавливаются для добавления чего-либо к входным данным. Глобальная переменная bucket хранит пакеты по мере их передачи Lua-скрипту:

LuaOutputFilter myOutputFilter "/www/filter.lua" output_filter
<Files "*.lua">
  SetOutputFilter myOutputFilter
</Files>
--[[
    Example output filter that escapes all HTML entities in the output
]]--
function output_filter(r)
    coroutine.yield("(Handled by myOutputFilter)<br/>\n") -- Prepend some data to the output,
                                                          -- yield and wait for buckets.
    while bucket do -- For each bucket, do...
        local output = r:escape_html(bucket) -- Escape all output
        coroutine.yield(output) -- Send converted data down the chain
    end
    -- No more buckets available.
end

Как и в случае с фильтром ввода, фильтр вывода поддерживает отказ/пропуск фильтра, если он нежелателен:

function output_filter(r)
    if not r.content_type:match("text/html") then
        return -- Simply deny filtering, passing on the original content instead
    end
    coroutine.yield() -- wait for buckets
    ... -- insert filter stuff here
end

Lua-фильтры с mod_filter

Когда Lua-фильтр используется в качестве базового поставщика через директиву FilterProvider, фильтрация будет работать только тогда, когда filter-name идентичен provider-name.

См. "Изменение содержимого с помощью Lua-фильтров" для получения дополнительной информации.

Директива LuaPackageCPath

Описание: Добавить каталог в пакет.cpath lua
Синтаксис:
LuaPackageCPath /path/to/include/?.soa
Контекст: настройки сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Добавляет путь в путь поиска общих библиотек lua. Следует тем же соглашениям, что и lua. Просто добавляет в package.cpath в lua-виртуальной машине.

Директива LuaPackagePath

Описание: Добавить каталог в пакет.path lua
Синтаксис:
LuaPackagePath /path/to/include/?.lua
Контекст: настройки сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Добавляет путь в путь поиска модулей lua. Следует тем же соглашениям, что и lua. Просто добавляет в package.path в lua-виртуальной машине.

Примеры:

LuaPackagePath "/scripts/lib/?.lua"
LuaPackagePath "/scripts/lib/?/init.lua"

Директива LuaQuickHandler

Описание: Предоставляет хук для быстрого обработчика обработки запросов
Синтаксис:
LuaQuickHandler /path/to/script.lua hook_function_name
Контекст: настройки сервера, виртуальный хост
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Эта фаза выполняется сразу после того, как запрос был сопоставлен с виртуальным хостом, и может быть использована для обработки запроса перед запуском других фаз или для обработки запроса без необходимости перевода, сопоставления с хранилищем и т. д. Поскольку эта фаза запускается до всего остального, директивы, такие как <Location> или <Directory>, не имеют действия на этой фазе, так как URI еще не были корректно обработаны.

Контекст

Данная директива недействительна в <Directory>, <Files>, или контексте htaccess.

Директива LuaRoot

Описание: Указывает базовый путь для разрешения относительных путей для директив mod_lua
Синтаксис:
LuaRoot /path/to/a/directory
Контекст: настройки сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Указывает базовый путь, который будет использоваться для оценки всех относительных путей внутри mod_lua. Если не указан, они будут разрешены относительно текущего рабочего каталога, что может не всегда работать хорошо для сервера.

Директива LuaScope

Описание: Один из once, request, conn, thread — по умолчанию once
Синтаксис:
LuaScope once|request|conn|thread|server [min] [max]
По умолчанию:
LuaScope once
Контекст: настройки сервера, виртуальный хост, каталог, .htaccess
Переопределение: Все
Статус: Расширение
Модуль: mod_lua

Указывает жизненный цикл области интерпретатора Lua, который будет использоваться обработчиками в этом "каталоге". По умолчанию "once".

once:
использовать интерпретатор один раз и выбросить его.
request:
использовать интерпретатор для обработки чего-либо, основанного на том же файле в рамках этого запроса, который также имеет область видимости запроса.
conn:
То же, что и request, но привязан к connection_rec.
thread:
Использовать интерпретатор в течение всего жизненного цикла потока, обрабатывающего запрос (доступно только с многопоточными MPM).
server:
Этот отличается от других, потому что область видимости сервера довольно долгоживущая, и несколько потоков будут иметь тот же server_rec. Чтобы справиться с этим, Lua-состояния с областью видимости сервера хранятся в списке ресурсов apr. Аргументы min и max задают минимальное и максимальное количество Lua-состояний для хранения в пуле.

Как правило, области thread и server примерно в 2-3 раза быстрее, чем остальные, потому что им не нужно запускать новые Lua-состояния для каждого запроса (особенно с event MPM, так как даже запросы keepalive будут использовать новый поток для каждого запроса). Если вы удовлетворены тем, что вашим скриптам не будут создавать проблем повторное использование состояния, то области thread или server следует использовать для максимальной производительности. В то время как область thread обеспечит самые быстрые ответы, область server будет использовать меньше памяти, так как состояния находятся в пуле, что позволяет, например, 1000 потокам использовать всего 100 Lua-состояний, таким образом, используя только 10% памяти, необходимой для области thread.

© 2018 The Apache Software Foundation
Licensed under the Apache License, Version 2.0.
https://httpd.apache.org/docs/2.4/en/mod/mod_lua.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API