Модуль 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.8cbasic_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.1proxyreqстрока да Указывает, является ли это запросом прокси. Это значение обычно устанавливается на фазе 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 processa: 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