Модуль mod_dav. Архитектура модуля
В предыдущей статье мы рассмотрели реализацию протокола WebDAV в сервере Apache. В этой статье, которая является последней в серии, мы рассмотрим устройство модуля mod_dav - центрального модуля поддержки протокола WebDAV в Apache. Также мы покажем как создавать собственные dav-провайдеры.
Данная статья впервые была опубликова в 6 номере рассылки "Информационный бюллетень от ApacheDev.ru". Теперь, начиная с 6 выпуска, данная рассылка выпускается на базе сервиса Subscribe.ru. Подписаться на рассылку.
Введение
Как уже было сказано в предыдущих статьях [1,2], модуль mod_dav является интерфейсным модулем, в котором происходит только обработка протокола WebDAV, а реализацию взаимодействия с хранилищем ресурсов, хранение свойств и т.п. модуль mod_dav делегирует сторонним модулям (back-end модулям или dav-провайдерами). В mod_dav такое взаимодействие реализовано в виде нескольких семейств хуков (сгруппированных по функциональности), обработчики которых должны быть реализованы 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) {
// Выполняем действия, необходимые для инициализации
// Данный обработчик вызывается после загрузки модуля и
// после обработки конфигурации
// (Примечание: Данный обработчик выполняется при загрузке дважды.
// Способ обойти такое поведение читайте в статье :
// /2006/03/13/problemi-pri-sozdanii-modula/)
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, // регистрация обработчиков
};
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) {
// Выполняем действия, необходимые для инициализации
// Данный обработчик вызывается после загрузки модуля и
// после обработки конфигурации
// (Примечание: Данный обработчик выполняется при загрузке дважды.
// Способ обойти такое поведение читайте в статье :
// /2006/03/13/problemi-pri-sozdanii-modula/)
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. До встречи.
___________________________
http://www.pictgallery.ru/
Комментарий от андрюха — Сентябрь 6, 2008 @ 11:36 am
___________________________
http://playboy-design.com/
Комментарий от skif — Сентябрь 6, 2008 @ 11:38 am
Комментарий от Ножки Буша — Октябрь 16, 2008 @ 8:14 am
Комментарий от Ножки Буша — Октябрь 16, 2008 @ 8:15 am
Комментарий от УПЯЧКА — Октябрь 16, 2008 @ 8:19 am
Комментарий от УПЯЧКА — Октябрь 16, 2008 @ 8:20 am
УПЯЧКА СЛЕДИТ ЗА ТОБОЙ ВЕЗДЕ!
Комментарий от УПЯЧКА — Октябрь 16, 2008 @ 8:21 am
Комментарий от УПЯЧКА — Октябрь 16, 2008 @ 8:22 am
Комментарий от УПЯЧКА — Октябрь 16, 2008 @ 8:26 am
Комментарий от УПЯЧКА — Октябрь 16, 2008 @ 8:27 am
Комментарий от УПЯЧКА — Октябрь 16, 2008 @ 8:29 am
Комментарий от УПЯЧКА — Октябрь 16, 2008 @ 8:33 am
_________________________
http://eliteforex.ru/
http://www.kondu.ru/
Комментарий от Олег — Декабрь 17, 2008 @ 9:18 pm
но мне помогло! Респект!
Комментарий от Инесса — Декабрь 20, 2008 @ 12:28 pm
Комментарий от Кирилл — Декабрь 20, 2008 @ 12:30 pm
Комментарий от Субаровод — Март 10, 2009 @ 2:54 am
Комментарий от Любитель драйва — Март 11, 2009 @ 1:37 am
Комментарий от неумёха — Март 13, 2009 @ 3:31 am
Комментарий от Марио — Апрель 16, 2009 @ 11:30 am