Взаимодействие модулей Apache с файлами конфигурации (httpd.conf и .htaccess)
Большинство модулей от администраторов и пользователей требуют некоторой настройки. Системные администраторы конфигурируют Apache, используя httpd.conf, а пользователи (авторы) используют файлы .htaccess. Модулями можно управлять с помощью директив конфигурации, которые также задаются в этих файлах.
В этой статье мы покажем, как в модуле использовать директивы конфигурации, а также как работать с директивами других модулей.
Основы конфигурации модулей
С точки зрения системного администратора есть несколько видов директив. Они могут быть классифицированы в соответствии с их областями действия. То есть некоторые директивы распространяют свое действие на весь сервер, тогда как другие действуют только внутри некоторых границ, таких как <VirtualHost> или <Directory>.
Директивы также могут переопределять значения друг друга. Например, директива внутри секции <Directory> переопределяет директиву вне этой секции. В большинстве случаев это приводит к рекурсивной обработке секций, даже не смотря на то, что они используются разными модулями с совершенно разным поведением.
Вот стандартные контексты конфигурации, используемые в Apache:
- Главная конфигурация (Main Config)
- Директивы этого контекста находятся в файле httpd.conf, но не внутри какой-либо секции. Применяются глобально, кроме тех случаев, где они переопределены. Такие директивы подходят для стандартных настроек системы, таких как MIME-типов, а также для тех, которые используются только при запуске сервера, например список загружаемых модулей. Большинство директив можно использовать в данном контексте.
- Конфигурация виртуального хоста (Virtual Host)
- Каждый виртуальный хост имеет свою серверную конфигурацию, установленную в секции <VirtualHost>. Директивы, используемые в главной конфигурации, можно использовать и на этом уровне, а также наоборот.
- Конфигурация каталога (Directory)
- Секции <Directory>, <Files> и <Location> могут задавать многоуровневую иерархию конфигураций. Это самые используемые контексты конфигурации. Для краткости мы рассмотрим их вместе, как иерархию конфигураций каталогов.
- .htaccess
- .htaccess - это дополнение к иерархии каталогов, с помощью которого сервер разрешает вносить авторам свои значения директив, конечно, если доступ на это (AllowOverride) разрешен администратором сервера.
Однако запомните, что контексты это не всегда то же самое, что и секции конфигурации. Так, например, модули могут создавать для себя свои собственные секции: например, mod_access создает секцию <Limits>, а mod_perl создает секцию <Perl>.
Структуры данных конфигурации
Как рассказано выше, есть две различные иерархии в директивах конфигурации: серверы (VirtualHost) и каталоги (Directory), поэтому существуют две разные структуры данных: конфигурация сервера (per-server config) и конфигурация каталога (per-directory config). У каждого модуля есть собственные указатели на эти структуры, хотя модули редко используют их одновременно.
Конфигурация сервера хранится в структуре server_rec, которая создается для каждого виртуального хоста при запуске сервера. Конфигурация каталога хранится в структуре request_rec и создается для конкретного каталога функциями слияния конфигураций при каждом запросе (об этом ниже).
Управление конфигурацией модуля
Не менее пяти из шести используемых элементов структуры модуля Apache предназначены для конфигурации:
module my_module = {
STANDARD20_MODULE_STUFF,
my_create_dir_conf, /* Создание конфигурации каталога */
my_merge_dir_conf, /* Слияние конфигураций каталогов */
my_create_svr_conf, /* Создание конфигурации сервера */
my_merge_svr_conf, /* Слияние конфигураций серверов */
my_cmds, /* Директивы конфигурации */
my_hooks
};
STANDARD20_MODULE_STUFF,
my_create_dir_conf, /* Создание конфигурации каталога */
my_merge_dir_conf, /* Слияние конфигураций каталогов */
my_create_svr_conf, /* Создание конфигурации сервера */
my_merge_svr_conf, /* Слияние конфигураций серверов */
my_cmds, /* Директивы конфигурации */
my_hooks
};
Каждый модуль сам определяет собственные структуры конфигурации. После того, как структуры определены, модуль должен реализовать для них функции выделения памяти и инициализации:
typedef struct {
/* Поля структуры конфигурации сервера (хоста) */
}my_svr_cfg;
static void* my_create_svr_conf(apr_pool_t* pool, server_rec* svr) {
my_svr_cfg* svr = apr_pcalloc(pool, sizeof(my_svr_cfg));
/* Инициализация полей svr */
return svr;
}
typedef struct {
/* Поля структуры конфигурации каталога */
}my_dir_cfg;
static void* my_create_dir_conf(apr_pool_t* pool, char* x) {
my_dir_cfg* dir = apr_pcalloc(pool, sizeof(my_dir_cfg));
/* Инициализация полей dir */
return dir;
}
/* Поля структуры конфигурации сервера (хоста) */
}my_svr_cfg;
static void* my_create_svr_conf(apr_pool_t* pool, server_rec* svr) {
my_svr_cfg* svr = apr_pcalloc(pool, sizeof(my_svr_cfg));
/* Инициализация полей svr */
return svr;
}
typedef struct {
/* Поля структуры конфигурации каталога */
}my_dir_cfg;
static void* my_create_dir_conf(apr_pool_t* pool, char* x) {
my_dir_cfg* dir = apr_pcalloc(pool, sizeof(my_dir_cfg));
/* Инициализация полей dir */
return dir;
}
Вот все, что необходимо сделать для создания структур конфигурации. Далее Apache будет использовать результат работы этих функций. Теперь доступ к значениям этих структур может быть получен в любое время через указатели server_rec и request_rec:
my_svr_cfg* svr = ap_get_module_config(s->module_config, &my_module) ;
my_dir_cfg* dir = ap_get_module_config(r->per_dir_config, &my_module) ;
my_dir_cfg* dir = ap_get_module_config(r->per_dir_config, &my_module) ;
Создание директив конфигурации
Выше был описан массив my_cmds, который хранит все директивы, обрабатываемые данным модулем. Обычно директивы задаются с помощью макросов, определенных в файле http_config.h.
Например:
static const cmd_rec my_cmds[] = {
AP_INIT_TAKE1(“MyFirstDirective”, my_first_cmd_func, my_ptr,
OR_ALL, “Это моя первая директива”),
/* Другие директивы модуля */
{ NULL }
};
AP_INIT_TAKE1(“MyFirstDirective”, my_first_cmd_func, my_ptr,
OR_ALL, “Это моя первая директива”),
/* Другие директивы модуля */
{ NULL }
};
Макрос AP_INIT_TAKE1 - один из многих подобных макросов для определения директив модуля. Все они имеют одинаковый прототип со следующими аргументами:
- Имя директивы.
- Функция обработки этой директивы.
- Указатель на структуру данных (обычно NULL).
- Область действия директивы.
- Краткое описание директивы.
Функции конфигурации
Неотъемлемой частью каждой директивы является обрабатывающая ее функция. Обычно это функция, устанавливающая некоторые поля одной из структур конфигурации. Прототип макроса AP_INIT_TAKE1 одинаковый, вне зависимости от того, для какой конфигурации мы создаем директиву: каталога или сервера:
const char* my_first_cmd_func(cmd_parms* cmd, void* cfg, const char* arg)
Аргумент cmd ссылается на структуру cmd_parms, поля которой используются Apache и модулями. Вот поля, представляющие интерес:
- void *info - содержит my_ptr из макроса создания директивы.
- apr_pool_t *pool - пул для долговременного хранения ресурсов.
- apr_pool_t *temp_pool - пул для временного хранения ресурсов.
- server_rec *server - структура данных конфигурации сервера.
Конфигурацию каталога можно получить из аргумента cfg, а конфигурацию сервера из server_rec. Аргумент arg содержит значение обрабатываемой директивы.
Типы функций конфигурации
В примере, приведенном выше, мы использовали макрос AP_INIT_TAKE1, который предназначен для директивы, имеющей один строковый аргумент. Это один из множества подобных макросов, определенных в http_config.h:
- AP_INIT_NO_ARGS (без аргументов)
- AP_INIT_FLAG (один флаговый аргумент)
- AP_INIT_TAKE1 (один строковый аргумент)
- AP_INIT_TAKE2, AP_INIT_TAKE3, AP_INIT_TAKE12 и т.д. - директивы с различным числом строковых аргументов.
- AP_INIT_ITERATE (функция вызывается повторно для произвольного количества произвольных аргументов)
- AP_INIT_ITERATE2 (функция вызывается повторно для двух аргументов)
- AP_INIT_RAW_ARGS (функция вызывается для всех аргументов сразу)
Такой подход дает авторам модулей выбор, как готовых прототипов для заданного количества аргументов, так и возможность ручной обработки макросом RAW_ARGS. Модули, использующие RAW_ARGS, получают аргументы, циклически вызывая функцию ap_getword_conf до тех пор, пока она не вернет NULL.
Области конфигурации
В вышеприведенном примере мы использовали OR_ALL, что означает, что директива MyFirstDirective может использоваться в любом месте файла httpd.conf или в любом .htaccess файле (если .htaccess разрешены на сервере). Вот другие значения, которые мы можем использовать:
- Флаг RSRC_CONF определяет верхний уровень httpd.conf или контекст VirtualHost. Все директивы, используемые в блоке VirtualHost, должны использовать этот флаг.
- ACCESS_CONF - уровень httpd.conf в контексте каталога. Наиболее подходящее значение для директив контекста каталога, а если использовать вместе (используя OR) с RSRC_CONF, то и для любого места в httpd.conf.
- OR_LIMIT, OR_OPTIONS, OR_FILEINFO, OR_AUTHCFG, OR_INDEXES - разрешают использовать директивы в .htaccess в соответствии с настройками AllowOverride.
Другие функции конфигурации
В общем случае, как в примере выше, необходимо создавать собственные функции для обработки директивы. Но это не всегда обязательно. В случае с простой директивой, которая только устанавливает значение некоторого поля в конфигурации каталога, мы можем использовать одну из следующих функций: ap_set_string_slot, ap_set_string_slot_lower, ap_set_int_slot, ap_set_flag_slot, ap_set_file_slot, в зависимости от типа поля структуры. Чтобы задать значение этого поля, Вы должны передать указатель на него, как, например:
AP_INIT_TAKE1(“MySimpleDirective”, ap_set_int_slot,
(void*)APR_OFFSETOF(my_dir_cfg, myintvar),
OR_ALL, “Установка myintvar”);
(void*)APR_OFFSETOF(my_dir_cfg, myintvar),
OR_ALL, “Установка myintvar”);
Где myintvar - это целочисленное поле структуры my_dir_config
Иерархия конфигураций
Теперь мы разобрались с тем, как создавать структуры конфигураций и поработали с ними. Последняя тема, которую нам надо рассмотреть, это создание и работа с иерархией конфигураций, а именно, как директивы, установленные на разных уровнях, будут взаимодействовать друг с другом. Эту задачу решают функции объединения, определенные в структуре модуля.
Функции объединения вызываются всякий раз, когда одинаковые директивы существуют более чем на одном уровне, начиная с верхнего уровня httpd.conf. В случае с конфигурацией каталога может быть неограниченное количество уровней, и таким образом функция объединения вызывается несколько раз, объединяя файлы .htaccess и секции в httpd.conf.
Указатели на функции объединения в структуре модуля могут иметь значения NULL. В этом случае все директивы в нижних (по уровню) секциях игнорируются, поэтому инкрементная сборка конфигурации невозможна.
Обычно функции объединения используются в тех случаях, когда необходимо использовать директивы, которые заданы в секциях на самых нижних уровнях, но при этом наследовать директивы с верхних уровней. Рассмотрим следующий пример:
typedef struct {
int a, b, c;
}my_dir_cfg;
int a, b, c;
}my_dir_cfg;
С директивами, устанавливающими значение каждого поля и со следующей конфигурацией:
<Location />
SetMyA 123
SetMyC 321
</Location>
SetMyA 123
SetMyC 321
</Location>
<Location /somewhere/>
SetMyB 456
</Location>
SetMyB 456
</Location>
<Location /somewhere/else/again/>
SetMyC 789
</Location>
SetMyC 789
</Location>
Самый вложенный каталог - это /somewhere/else/again/, поэтому нам надо установить для с значение 789, а значения a и b унаследовать от значений предыдущих уровней. Для этого нам нужна функция объединения, которая имеет вид:
static void* my_merge_dir_conf(apr_pool_t* pool, void* BASE, void* ADD) {
my_dir_cfg* base = BASE;
my_dir_cfg* add = ADD;
my_dir_cfg* conf = apr_palloc(pool, sizeof(my_dir_cfg));
conf->a = ( add->a == UNSET ) ? base->a : add->a;
conf->b = ( add->b == UNSET ) ? base->b : add->b;
conf->c = ( add->c == UNSET ) ? base->c : add->c;
return conf;
}
my_dir_cfg* base = BASE;
my_dir_cfg* add = ADD;
my_dir_cfg* conf = apr_palloc(pool, sizeof(my_dir_cfg));
conf->a = ( add->a == UNSET ) ? base->a : add->a;
conf->b = ( add->b == UNSET ) ? base->b : add->b;
conf->c = ( add->c == UNSET ) ? base->c : add->c;
return conf;
}
Для оптимизации функции мы присвоим константе UNSET некоторое неиспользуемое значение (например “-1″, если все наши значения должны быть положительными) и инициализируем все поля my_dir_cfg этим значением в функции create_config. Теперь наша конфигурация обработается в следующем порядке:
- На верхнем уровне a принимает значение 123, а c 321.
- Первое объединение присваивает b значение 456. Так как a и c не заданы на этом уровне, то они наследуют предыдущие значения.
- На уровне /somewhere/else/ директив нет, поэтому этот уровень просто наследуется от вышележащего /somewhere/ без необходимости какого-либо слияния.
- Второе объединение задает новое значение c, переопределяя предыдущее значение и наследуя значения a и b. Итак, в результате мы имеем a=123, b=456, с=789.
Очевидно, что это тривиальная функция объединения. Обычно необходимо сделать что-то более интересное: например, объединить сложные структуры или работать в ситуации, когда нет четкого значения UNSET для принятия решения.
Это почти все, что можно сказать о конфигурации модулей Apache. Надеюсь, что Вам понравился данный материал. Если у Вас остались вопросы, то отправляйте их на info@apachedev.ru Я обязательно отвечу на них.
Комментарий от jobs — Февраль 7, 2008 @ 9:33 am
____________________
www.specmachines.ru/
Комментарий от андрюха — Август 29, 2008 @ 12:07 pm
Комментарий от Пётр — Октябрь 18, 2008 @ 5:54 pm
Комментарий от Тимур — Октябрь 18, 2008 @ 5:55 pm
+3
Комментарий от Амалия — Октябрь 18, 2008 @ 5:55 pm
Комментарий от Alex — Февраль 6, 2009 @ 2:23 am