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 Это заключительный этап «исправления всего необходимого» перед запуском обработчиков содержимого. Здесь следует выполнять все последние изменения запроса.
Обработчик содержимого например, файлы .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. У него есть метатаблица, позволяющая выполнять с ним полезные операции. В основном он содержит те же поля, что и структура request_rec, многие из которых доступны не только для чтения, но и для записи. (Содержимое полей-таблиц можно изменить, но сами поля нельзя переназначить на другие таблицы.)

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

Указание dbType в качестве первого параметра dbacquire чувствительно к регистру.

Это должно быть одно из следующих значений: mysql, pgsql, freetds, odbc, sqlite2, sqlite3, 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) на этап translate name обработки запроса. Функция хука получает один аргумент — 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 с вызовом определённой функции-обработчика в заданном файле. Для сопоставления URI используются регулярные выражения PCRE; группы совпадений можно подставлять как в путь к файлу, так и в имя функции. Тщательно составляйте регулярные выражения, чтобы избежать проблем с безопасностью.

Примеры:

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

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

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

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

Добавляет путь в путь поиска общих библиотек Lua. Используются те же соглашения, что и в Lua. Эта директива просто изменяет package.cpath в виртуальных машинах Lua.

Директива LuaPackagePath

Описание: Добавляет каталог в package.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, используемого обработчиками в этом «Directory». По умолчанию используется значение «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