前言
上一篇动手实践一下简单HTTP模块的开发,我们知道调用其模块需要先能够读取nginx.conf文件中的配置项。这篇笔记关于HTTP模块怎样获取感兴趣的配置项。
怎样使用HTTP配置
处理HTTP配置项可以分为以下四个步骤:
- 创建数据结构用于存储配置项对应的参数;
- 设定配置项在nginx.conf中出现时的限制条件与回调方法;
- 实现2中的回调方法,或使用Nginx框架预设的14个回调方法;
- 合并不同级别的配置块中出现的同名配置项;
以上步骤都与上篇笔记中提到的ngx_http_module_t和ngx_command_t密切相关。
分配用于保存配置参数的数据机构
在ngx_http_mytest_modules.c文件中创建一个包含所有我们感兴趣的参数的结构体:
typedef struct {
ngx_str_t my_str;
ngx_int_t my_num;
ngx_flag_t my_flag;
size_t my_size;
ngx_array_t *my_str_array;
ngx_array_t *my_keyval;
off_t my_off;
ngx_msec_t my_msec;
time_t my_sec;
ngx_bufs_t my_bufs;
ngx_uint_t my_enum_seq;
ngx_uint_t my_bitmask;
ngx_uint_t my_access;
ngx_path_t *my_path;
} ngx_http_mytset_conf_t;
之所以严格定义一套结构来存储的原因如下:
举例:
http {
test_str main;
server {
listen 80;
test_str server80;
location /url1 {
mytest;
test_str loc1;
}
location /url2 {
mytest;
test_str loc2;
}
}
server {
listen 8080;
test_str server8080;
location /url3 {
mytest;
test_str loc3;
}
}
}
HTTP框架在解析conf配置文件时,只要遇到http{}、server{}或者location{}块就会立刻分配一个
ngx_http_mytset_conf_t结构。
在此配置中,多个location块中的相同配置允许同时有效,意味着如果存储location块的ngx_http_mytset_conf_t数据结构也必须保存许多份。
HTTP模块感兴趣的配置项需要统一的使用一种struct结构来存储。所以需要严格定义一套结构。
通过前篇笔记中的提到的ngx_http_module_t中的回调方法,Nginx实现对ngx_http_mytset_conf_t结构的管理。
再次贴上:
/* 在读取、重载配置时定义的接口,成员表示8个阶段
* HTTP框架在启动过程中会在每个阶段都调用其中相应的方法
* 这里做简单模块,并没有什么工作需要在初始化中完成,因此可以设为NULL
*/
typedef struct {
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
void *(*create_main_conf)(ngx_conf_t *cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
void *(*create_loc_conf)(ngx_conf_t *cf);
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;
其中,create_main_conf / create_srv_conf / create_loc_conf三个方法负责把
ngx_http_mytset_conf_t结构传递给HTTP框架。
HTTP框架提供了main、srv、loc三种级别,分别表示直接出现在http{}、server{}、location{}块内的配置项。
当nginx.conf出现http{}时,HTTP框架则调用所有HTTP模块可能实现的create_main_conf / create_srv_conf / create_loc_conf方法生成存储main级别的配置参数结构体;当出现server{}时,则调用可能的create_srv_conf / create_loc_conf方法;依次类推...
举例:
在以上的mytest配置中,mytest模块在http{}调用1次create_main_conf ,create_loc_conf则调用多次。
这里,我们在ngx_http_mytest_modules.c文件中实现
static void *
ngx_http_mytest_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_mytset_conf_t *mycf;
mycf = (ngx_http_mytset_conf_t *)ngx_palloc(cf->pool, sizeof(ngx_http_mytset_conf_t));
if (mycf == NULL) {
return NULL;
}
mycf->my_flag = NGX_CONF_UNSET;
mycf->my_num = NGX_CONF_UNSET;
mycf->my_str_array = NGX_CONF_UNSET_PTR;
mycf->my_keyval = NULL;
mycf->my_off = NGX_CONF_UNSET;
mycf->my_msec = NGX_CONF_UNSET_MSEC;
mycf->my_sec = NGX_CONF_UNSET;
mycf->my_size = NGX_CONF_UNSET_SIZE;
return mycf;
}
设定配置项解析方式
这里就牵涉到上篇笔记中的ngx_command_t结构。再次贴上举例笔记:typedef struct ngx_command_s ngx_command_t;
struct ngx_command_s {
ngx_str_t name; // 配置项名
ngx_uint_t type; // 配置项类型,指定配置项可以出现的位置,比如出现在server块还是location块
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); // 如果出现name项,调用此方法处理
ngx_uint_t conf;
ngx_uint_t offset; // 在配置文件的偏移量
void *post; 读取配置后的处理方法
};
以上文的http配置项为例:
- name指的是“test_str”;
- type决定这个配置项可以在哪些块,可携带参数类型和个数。可以取多值,各值间用“|”连接;
- set为处理配置项方法,这里既可以自定义实现方法,也可以用Nginx预设的14个解析方法;(下篇详细介绍)
- conf用于指示配置项所处内存的相对偏移配置,仅在type设置为表示模块不需要解析不属于任何{}内的全局配置项时设置conf值,使之指向每个每个模块解析全局配置项的配置结构体。**PS**:每一个进程都有唯一的ngx_cycle_t核心结构体,它的一个成员void**** conf_ctx表示指向一个成员皆为四重指针的数组,特意为event、http、mail模块配置项设计。conf取值有:NGX_HTTP_MAIN_CONF_OFFSET、NGX_HTTP_SRV_CONF_OFFSET、NGX_HTTP_LOC_CONF_OFFSET,分别代表使用create_main_conf、create_srv_conf、create_loc_conf方法产生的配置参数结构体。对于HTTP模块,conf值必须设置。因为HTTP框架自动解析时需要知道把解析的配置项值写入哪个配置结构体,这个就由conf值完成;
- offset表示当前配置项在整个存储配置结构体中的偏移位置,以byte为单位。此偏移量通过调用offsetof(type, elements)宏完成设置;
- post指针用途很多。如果自定义配置项回调方法,post用途由用户定义,也可以不使用,可随意设置;如果使用Nginx预设的配置项解析方法,就得根据预设方法决定post用途。(略)
总结
这篇首先笔记了下HTTP模块如何保存配置文件的配置项,然后总体介绍了下如何设置解析方法,HTTP模块具体的解析方法放在下篇详细介绍。本来想把这一节看完再梳理的,发现HTTP模块解析配置项的方法实在很多,所以决定下篇吧。。
主要参考
《深入理解Nginx》