Модуль 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 Доступно для записи Описание allowoverridesstring нет Параметры AllowOverride, применённые к текущему запросу. ap_auth_typestring да Если выполнялась проверка аутентификации, здесь указывается её тип (например, basic)argsstring да Аргументы строки запроса, извлечённые из запроса (например, foo=bar&name=johnsmith)assbackwardsboolean нет Равно true, если это запрос в стиле HTTP/0.9 (например, GET /foo(без заголовков) )auth_namestring нет Имя области, используемой для авторизации (если применимо). bannerstring нет Баннер сервера, например Apache HTTP Server/2.4.3 openssl/0.9.8cbasic_auth_pwstring нет Пароль базовой аутентификации, отправленный с этим запросом, если он есть canonical_filenamestring нет Каноническое имя файла запроса content_encodingstring нет Кодировка содержимого текущего запроса content_typestring да Тип содержимого текущего запроса, определённый на этапе type_check (например, image/gifилиtext/html)context_prefixstring нет context_document_rootstring нет document_rootstring нет Корневой каталог узла err_headers_outtable нет Среда MIME-заголовков ответа, выводимая даже при ошибках и сохраняющаяся при внутренних перенаправлениях. Таблица Lua только для чтения, подходящая для перебора, доступна как r:err_headers_out_table(). filenamestring да Имя файла, с которым сопоставлен запрос, например /www/example.com/foo.txt. Его можно изменить на этапах pre-translate-name, translate-name или map-to-storage запроса, чтобы стандартный обработчик (или обработчики скриптов) мог обслуживать другой файл, а не тот, который был запрошен. handlerstring да Имя обработчика, который должен обслуживать этот запрос; например, lua-script, если запрос должен обслуживаться mod_lua. Обычно задаётся директивамиAddHandlerилиSetHandler, но также может быть задано через mod_lua, чтобы другой обработчик мог обслужить определённый запрос, который иначе им не обрабатывался бы.headers_intable да Среда MIME-заголовков запроса. Содержит такие заголовки, как Host, User-Agent, Refererи другие. Таблица Lua только для чтения, подходящая для перебора, доступна как r:headers_in_table().headers_outtable да Среда MIME-заголовков ответа. Таблица Lua только для чтения, подходящая для перебора, доступна как r:headers_out_table(). hostnamestring нет Имя узла, заданное заголовком Host:или полным URI.is_httpsboolean нет Выполняется ли этот запрос через HTTPS is_initial_reqboolean нет Является ли этот запрос исходным или подзапросом limit_req_bodynumber нет Ограничение размера тела запроса для этого запроса или 0, если ограничение отсутствует. log_idstring нет Идентификатор запроса в журнале доступа и журнале ошибок. methodstring нет Метод запроса, например GETилиPOST.notestable да Список заметок, которые могут передаваться от одного модуля другому. Таблица Lua только для чтения, подходящая для перебора, доступна как r:notes_table(). optionsstring нет Директива Options, применённая к текущему запросу. path_infostring нет PATH_INFO, извлечённый из этого запроса. portnumber нет Порт сервера, используемый запросом. protocolstring нет Используемый протокол, например HTTP/1.1proxyreqstring да Указывает, является ли запрос прокси-запросом. Обычно это значение задаётся на этапе post_read_request/pre_translate_name/translate_name запроса. rangestring нет Содержимое заголовка Range:.remainingnumber нет Количество байтов, оставшихся для чтения из тела запроса. server_builtstring нет Время сборки исполняемого файла сервера. server_namestring нет Имя сервера для этого запроса. some_auth_requiredboolean нет Требовалась ли авторизация для этого запроса. subprocess_envtable да Переменные среды, заданные для этого запроса. Таблица Lua только для чтения, подходящая для перебора, доступна как r:subprocess_env_table(). startednumber нет Время запуска (или перезапуска) сервера в секундах с начала эпохи (1 января 1970 года) statusnumber да Текущий код ответа HTTP для этого запроса, например 200или404.the_requeststring нет Строка запроса в том виде, в котором она была отправлена клиентом, например GET /foo/bar HTTP/1.1.unparsed_uristring нет Не разобранный URI запроса uristring да URI после разбора httpd userstring да Если выполнялась проверка аутентификации, здесь указывается имя аутентифицированного пользователя. useragent_ipstring нет 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.
Указание 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