Не смотря на большое количество плюсов, которыми обладает этот замечательный сервер, у него есть и свои минусы. Один из из них, возможно даже наибольший — это очень скудная документация. На сайте проекта этому уделено всего несколько небольших wiki-страничек, которые почти полностью дублируют txt-файлы из каталога doc исходных кодов lighttpd. Из всей этой не богатой документации программистам посвящён только один раздел Plugins, описывающий ловушки, которые сервер предоставляет своим модулям. Остальная же документация, в основном, посвящена конфигурированию самого сервера и его модулей. Основным же руководством для разработчика в такой ситуации остаются только исходный код проекта. Благо он имеет довольно хорошую архитектуру, читабельный вид и не большой размер.
Структура плагина
Итак, наилучшем способом начать знакомство с плагинами lighttpd будет просмотр исходного кода самого простого модуля. Таковым является mod_skeleton.c, находящийся в папке src. Этот небольшой модуль всего-то и делает, что запрещает доступ к файлам, указанным в переменной skeleton.array конфигурационного файла. Но это не основная его обязанность. Основная же его задача — это быть шаблоном для новых плагинов. При создания нового модуля вы можете просто скопировать файл mod_skeleton.c с новым именем в тот же каталог и заменить в нём все "skeleton" на название вашего модуля. Имена исходных файлов могут быть любыми, а вот скомпилированный модуль должен иметь вид mod_имя_модуля.so для POSIX систем и mod_имя_модуля.dll для Windows систем. Теперь рассмотрим основные структуры и функции этого шаблона.
typedef struct {
array *match;
} plugin_config;
Структура plugin_config должна содержать переменные, значения которых будет браться из файла конфигураций.
typedef struct {
PLUGIN_DATA;
buffer *match_buf;
plugin_config **config_storage;
plugin_config conf;
} plugin_data;
Структура plugin_data — это основная структура модуля, содержащая всю информацию необходимую для его работы.
typedef struct {
size_t foo;
} handler_ctx;
Структура handler_ctx содержит данные специфические для каждого соединения.
int mod_skeleton_plugin_init(plugin *p)
Эта фунция вызывается при загрузке модуля сервером. Её имя обязательно должно иметь формат mod_имя_модуля_plugin_init. Здесь нужно заполнить структуру plugin, содержащую информацию о модуле: версию сервера, название модуля, обработчики ловушек.
INIT_FUNC(mod_skeleton_init)
Инициализация плагина. Вызывается после загрузки плагина.
FREE_FUNC(mod_skeleton_free)
Вызывается перед выгрузкой плагина из памяти. В этой функции необходимо освободить всю память, которую мы выделяли в процессе работы модуля.
SETDEFAULTS_FUNC(mod_skeleton_set_defaults)
Вызывается при конфигурировании сервера. Здесь для переменных из plugin_config вводятся соответствия с записями из конфигурационного файла. В данном случае наша переменная match будет соотвествовать записи skeleton.array и иметь тип массив. Подробнее об этой не мало важной функции и о функции mod_skeleton_patch_connection мы узнаем в следующей части этой статьи.
URIHANDLER_FUNC(mod_skeleton_uri_handler)
А это то, ради чего все и затевалось. Эта функция вызывается после того как на сервер пришел запрос на выдачу странички и до того как сервер отправил ответ, а конкретнее после обработки uri на символы типа .. и %20. Здесь мы можем делать с сервером все что угодно, от изменения самого uri, до форсирования отправки запроса. В нашем случае здесь проверяется uri на вхождение в список match.
Все эти функции были указанны в качестве обработчиков определенных событий в mod_skeleton_plugin_init:
p->init = mod_skeleton_init;
p->handle_uri_clean = mod_skeleton_uri_handler;
p->set_defaults = mod_skeleton_set_defaults;
p->cleanup = mod_skeleton_free;
Но кроме этих ловушек есть и другие.
Ловушки сервера
init - вызывается после загрузки плагина
cleanup - вызывается перед выгрузкой плагина
set_defaults - вызывается во время конфигурации
handle_trigger - вызывается один раз в секунду
handle_sighup - вызывается когда сервер получил SIGHUP
Ловушки соединения
handle_uri_raw — вызывается после установки uri.path_raw, uri.authority и uri.scheme
handle_uri_clean — вызывается после "очистки" uri.path от последовательностей типа .. и %20
handle_docroot — вызывается в конце обработки логического пути (указанного пользователем в браузере) при получении docroot
handle_physical — вызывается после формирования физического пути, если не найден другой обработчик этого запроса
handle_subrequest_start — вызывается если установлен и проверен физический путь
handle_subrequest — вызывается в конце http_response_prepare
handle_request_done — вызывается когда запрос окончен
handle_connection_close — вызывается когда соединение закрыто
handle_joblist — called after the connection_state_engine is left again and plugin internal handles have to be called
connection_reset — вызывается при очистки структуры connection
Сборка
Для сборки вашего модуля надо будет добавить нижележащие строки в src/Makefile.am, естественно, заменив skeleton на имя вашего модуля.
lib_LTLIBRARIES += mod_skeleton.la
mod_skeleton_la_SOURCES = mod_skeleton.c
mod_skeleton_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_skeleton_la_LIBADD = $(common_libadd)
Предупреждение: модули, собранные под одну версию lighttpd, не смогут быть запущены под другой.
Ссылки
1. Официальный сайт Lighttpd
2. Документация для разработчиков Lighttpd
P.S.
Уже после написания этой статьи я нашёл книжку Андре Богуса "Lighttpd". Далее, уже зная, что такая книга существует и даже скачав её, я нашёл на официальном сайте ссылочку на неё, а рядом и ссылку на другую книгу "Lighttpd: The painless way". Правда по этой ссылке находилась только статья "Deploying a Rails application with Lighttpd", которую полноценной книгой ну никак не назовёшь. Впрочем, двухсотстраничной книги Богуса вполне хватит, не только для того чтобы удовлетворить свое любопытство по lighttpd, но и для того чтобы стать гуру в этом веб-сервере. Так, что с документаций, пусть даже и не официальной, у lightttpd все в порядке.

Миша мозг!
ОтветитьУдалитькстати, а где применяется lighthttpd ?
blastav, там, где надо быстро и надежно.
ОтветитьУдалить"Зачастую lighttpd используется для отдачи статического содержимого, в то время как его генерацией занимается более сложный веб-сервер. Такие посещаемые сайты как SourceForge.net, Imageshack.us, mirror.dkm.cz используют lighttpd на своих серверах." (с) wikipedia.
Youtuby тоже его использует.
А что заставило тебя разбираться с написанием плагинов под lighttpd?
ОтветитьУдалитьNikolay, работа. Пишу модуль для кеширования страничек.
ОтветитьУдалитьПодскажите, а возможно изменить как-либо контент перед выдачей его клиенту?
ОтветитьУдалитьДа возможно. Смотрите в сторону chunk. Для примера можно глянуть модуль mod_cgi.
ОтветитьУдалить