2006 г.
Модуль mod_dav. Архитектура модуля
Сипягин Максим, ApacheDev.ru
В предыдущей статье мы рассмотрели реализацию протокола WebDAV в сервере Apache. В этой статье, которая является последней в серии, мы рассмотрим устройство модуля mod_dav
- центрального модуля поддержки протокола WebDAV в Apache. Также мы покажем как создавать собственные dav-провайдеры.
Введение
Как уже было сказано в предыдущих статьях [1, 2], модуль mod_dav
является интерфейсным модулем, в котором происходит только обработка протокола WebDAV, а реализацию взаимодействия с хранилищем ресурсов, хранение свойств и т.п. модуль mod_dav
делегирует сторонним модулям (back-end модулям или dav-провайдерами). В mod_dav
такое взаимодействие реализовано в виде нескольких семейств хуков (сгруппированных по функциональности), обработчики которых должны быть реализованы dav-провайдерами.
Всего в mod_dav предоставлено семь групп хуков: обработка двух из них обязательна, а остальных - опционально. Сперва мы покажем общую схему, а затем опишем основные группы подробно.
Архитектура mod_dav
Рисунок. Архитектура mod_dav
На рисунке изображены все группы хуков, предоставляемых модулем mod_dav. Синим цветом выделены те группы хуков, для которых в dav-провайдере необходимы обработчики. Сейчас мы кратко рассмотрим каждую из этих групп, а ниже, уже более детально, изучим самые важные из них.
Название группы |
Описание |
dav_hooks_repository |
Обязательная группа хуков. Объединяет хуки, отвечающие за взаимодействие с хранилищем ресурсов. |
dav_hooks_propdb |
Обязательная группа хуков. В ней собраны хуки необходимые для работы со свойствами ресурсов (метаданными). |
dav_hooks_liveprop |
Хуки для работы с Live-свойствами. Live-свойства предназначены для хранения значений, определяемых сервером, например: "getcontentlength" - длина тела ответа. |
dav_hooks_locks |
Хуки для работы с блокировками ресурсов. |
dav_hooks_vsn |
Версионность ресурсов. |
dav_hooks_binding |
Связывание ресурсов. |
dav_hooks_search |
Поиск ресурсов. |
Теперь подробно рассмотрим три наиболее важные группы: dav_hooks_repository
, dav_hooks_propdb
и dav_hooks_locks
.
mod_dav: Работа с хранилищем ресурсов
Для взаимодействия с хранилищем (репозитарием) ресурсов в mod_dav
существует группа хуков dav_hooks_repository
. Основное ее предназначение - это обработка входных и выходных потоков хранилища ресурсов. Обработчики этих хуков также обеспечивают выполнение основных файловых операций над ресурсами, например: копирование/перемещение ресурсов, создание коллекции, удаление ресурса и т.п.
Рассмотрим все хуки этой группы подробнее:
get_resource
- Один из главных хуков данной группы. Обработчик хука
get_resource
связывает ресурс с URI запроса. Он должен возвращать структуру dav_resource
, описывающую запрошенный ресурс. Структура dav_resource
возвращается даже в случае, если запрошенный ресурс не существует.
get_parent_resource
- Обработчик этого хука возвращает описатель (дескриптор) родительского ресурса для запрошенного URI. Если URI запроса указывает на корневую коллекцию, тогда возвращается
NULL
.
is_same_resource
- Определяет, ссылаются ли два дескриптора на один и тот же ресурс.
is_parent_resource
- Служит для определения, является ли один ресурс родительским для другого.
open_stream
- Создает структуру потока -
dav_stream
, необходимую при заливке ресурса. Обработчик вызывается каждый раз, когда в хранилище добавляется новый ресурс.
close_stream
- Закрывает открытый поток. Вызывается после того, как ресурс полностью залит.
write_stream
- Вызывается циклически для блочной обработки данных закачиваемого ресурса.
seek_stream
- Абсолютное смещение в потоке. Используется для поддержки заголовка
Content-Range
в методах GET/PUT.
set_headers
- Вызывается перед отправкой ответа клиенту для установки заголовков. Обработчик хука
deliver
не вызывается, если используется метод HEAD.
deliver
- Одни из главных хуков группы. Используется для отправки ресурса в заданный фильтр. Используется как для ресурсов, так и для коллекций.
create_collection
- Создает коллекцию. В случае, если коллекция создана успешно, обработчик должен вернуть
NULL
.
copy_resource
- Хук копирования ресурса или коллекции. Свойства ресурсов также копируются.
move_resource
- Перенос ресурса.
remove_resource
- Хук удаления ресурса или коллекции. При удалении ресурса также удаляются и его свойства.
walk
- Хук обхода иерархии коллекций и ресурсов. Используется, когда запрос поступил на коллекцию и глубина обхода больше 0 (т.е. необходимо обработать вложенные объекты).
getetag
- Получить
ETag
для ресурса.
mod_dav: Работа со свойствами
Второй важнейшей и обязательной группой хуков является группа работы со свойствами. Основной задачей обработчиков этой группы является организация хранения свойств ресурсов и коллекций. Также они обеспечивают выполнения всех операций над свойствами. Рассмотрим эти хуки.
open
- Получаем дескриптор хранилища свойств.
close
- Закрываем открытое хранилище свойств.
define_namespaces
- Определение внутренних пространств имен для свойств.
output_value
- Получение значения определенного свойства для указанного ресурса.
map_namespaces
- Отображение глобальных пространств имен на пространства имен dav-провайдера.
store
- Сохранить значение свойства для указанного имени.
remove
- Удалить свойство.
exists
- Проверяет, существует ли такое свойство.
first_name
- Возвращает имя первого свойства ресурса.
next_name
- Возвращает имя следующего свойства.
get_rollback
apply_rollback
- Поддержка механизма отката изменений. Провайдером задается структура
dav_deadprop_rollback
, в которой хранятся старые имена и значения свойств.
mod_dav: Блокировки
Последняя группа, которую мы рассмотрим, отвечает за функционирование механизма блокировок. Она не является обязательной, но необходима для реализации методов WebDAV: Lock и Unlock.
get_supportedlock
- Возвращает значение свойства supportedlock для ресурса.
parse_locktoken
- Парсит поступивший токен блокировки. Тут мы создаем и возвращаем структуру
dav_locktoken
.
format_locktoken
- Преобразуем структуру
dav_locktoken
в строку URI.
compare_locktoken
- Сравниваем два токена блокировок.
open_lockdb
- Открывает и подготавливает хранилище блокировок. Dav-провайдер может воспользоваться значением директивы
DAVLockDB
для размещения своего хранилища (значение можно получить с помощью функции dav_get_lockdb_path()
).
close_lockdb
- Хук завершения работы с блокировками.
remove_locknull_state
- Выводим ресурс из состояния
lock-null
.
create_lock
- Создаем блокировку для ресурса. В обработчике этого хука должен быть создан токен новой блокировки.
get_locks
- Получить все блокировки указанного ресурса.
find_lock
- Найти блокировку ресурса по заданному токену.
has_locks
- Хук проверки ресурса на наличие блокировок. Должна возвращать
TRUE
, даже если у ресурса есть только блокировки с истекшим сроком жизни (time-out).
append_locks
- Добавить блокировки ресурсу.
remove_lock
- Удалить блокировку с заданным токеном.
refresh_locks
- Обновить блокировки у ресурса. Список токенов задает блокировки, которые необходимо обновить. Также в качестве аргумента передается структура
time_t
, описывающая текущее время.
lookup_resource
- Найти ресурс, связанный с указанным токеном блокировки.
Теперь, после рассмотрения основных групп хуков модуля mod_dav
, перейдем к практике. И посмотрим на код модуля-провайдера. Я не буду мешать код с текстом, поэтому все пояснения оформлены в виде комментариев к коду.
Структура dav - провайдера
Совет: Нижеизложенный код изучать лучше с конца.
// структура модуля для хранения директив
typedef struct {
const char *test_dav_directive;
}test_dav_server_conf;
// Обработчик хука post_config
static int test_dav_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s) {
// Выполняем действия, необходимые для инициализации
// Данный обработчик вызывается после загрузки модуля и
// после обработки конфигурации
// (Примечание: Данный обработчик выполняется при загрузке дважды.
// Способ обойти такое поведение читайте в статье
// «Проблемы при создании модуля»)
return OK;
}
// Создать структуру конфигурации модуля
static void *create_server_config(apr_pool_t *p, server_rec *s){
test_dav_server_conf *conf = NULL;
conf = (test_dav_server_conf*)apr_palloc(p, sizeof(*conf));
return (void*)conf;
}
// Обработчик директивы
static const char *test_dav_cmd(cmd_parms *cmd, void *config,
const char *arg1){
test_dav_server_conf *conf;
// Получить указатель на структуру конфигурации модуля
conf = ap_get_module_config(cmd->server->module_config, &test_dav_provider_module);
// Сохранить значение директивы
conf->test_dav_directive = apr_pstrdup(cmd->pool, arg1);
return NULL;
}
// Директивы модуля
static const command_rec test_dav_cmds[] = {
// Декларация директивы и ее обработчика
AP_INIT_TAKE1("tes_dav_directive", test_dav_cmd, NULL, ACCESS_CONF|RSRC_CONF,
"Тестовая директива с одним аргументом"),
{NULL}
};
// Структура DAV провайдера
static dav_provider test_dav_provider =
{
&test_dav_hooks_repos, // Работа с хранилищем
&test_dav_hooks_propdb, // Работа со свойствами
&test_dav_hooks_locks, // Блокировка
NULL, // Версионность
NULL, // Связывание
NULL // Поиск
};
// Регистрация обработчиков хуков
static void register_hooks(apr_pool_t *pconf){
ap_hook_post_config(test_dav_post_config, NULL, NULL, APR_HOOK_MIDDLE);
// Регистрация DAV провайдера
dav_register_provider(pconf, "test_dav_provider", &test_dav_provider);
}
// Главная структура модуля Apache
module AP_MODULE_DECLARE_DATA test_dav_provider_module = {
STANDARD20_MODULE_STUFF,
NULL,
NULL,
create_server_config, // создание конфигурации модуля
NULL,
test_dav_cmds, // список директив модуля
register_hooks, // регистрация обработчиков
};
Данный код, а также код обработчиков test_dav_hooks_repos
, test_dav_hooks_propdb
и test_dav_hooks_locks
можно скачать в виде архива.
Послесловие
Это последняя статья из серии про модуль mod_dav
. Надеюсь, что она стала вам полезной и сняла часть вопросов, касающихся реализации WebDAV в сервере. Если у вас остались вопросы, то присылайте их мне на info@apachedev.ru. До встречи.