由于笔者需要,开发nginx模块,有一个配置命令需要传入多个值,然而在网上找了又找,都是传递一个参数的,于是乎,没有办法只能在源码中徜徉了,找到了,类似命令就
是server块中的server_name命令,允许有多个值的存在,现在看下nginx自己是怎么进行解析的吧,由于我们只需要在本模块中使用命令,也就是说,我们只需要解析就好,不需
要跟全局命令进行merge了,好了,不多说,开始吧
nginx.conf中的内容是这样的
server {
listen 80;
server_name localhost alias;
...
}
server_name可以有超过一个参数的值
该命令项是:
{ ngx_string("server_name"),
NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
ngx_http_core_server_name,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL
}
指明了该值是在SERVER块中定义的 NGX_HTTP_SRV_CONF,允许有超过一个参数 NGX_CONF_1MORE,解析函数是ngx_http_core_server_name,该函数定义是这样的
static char *
ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_srv_conf_t *cscf = conf;//ngx_http_core_srv_conf_t定义在当前文件中
u_char ch;
ngx_str_t *value;
ngx_uint_t i;
ngx_http_server_name_t *sn;
value = cf->args->elts;
for (i = 1; i < cf->args->nelts; i++) {
ch = value[i].data[0];
if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))
|| (ch == '.' && value[i].len < 2))
{
//如果server_name的值是以*开始,并且(长度小于3的字符串,或者字符串第二个字符不是.的)不可用
//或者第一个字符是.并且长度小于2,也是不可用的
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"server name \"%V\" is invalid", &value[i]);
return NGX_CONF_ERROR;
}
if (ngx_strchr(value[i].data, '/')) {
//如果server_name中有/字符的也不可用
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"server name \"%V\" has suspicious symbols",
&value[i]);
}
//否则,在cscf中新建一个数组元素,并且返回新元素指针,
sn = ngx_array_push(&cscf->server_names);
if (sn == NULL) {
return NGX_CONF_ERROR;
}
//接下来是给新元素指针sn赋值
#if (NGX_PCRE)
sn->regex = NULL;
#endif
sn->server = cscf;
//
if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {
sn->name = cf->cycle->hostname;
} else {
//给新元素的服务器名称赋值
sn->name = value[i];
}
if (value[i].data[0] != '~') {
//服务器名称都是小写的
ngx_strlow(sn->name.data, sn->name.data, sn->name.len);
continue;
}
#if (NGX_PCRE) //这里面应该就是正则表达式部分,不予置评
{
u_char *p;
ngx_regex_compile_t rc;
u_char errstr[NGX_MAX_CONF_ERRSTR];
if (value[i].len == 1) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"empty regex in server name \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
value[i].len--;
value[i].data++;
ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
rc.pattern = value[i];
rc.err.len = NGX_MAX_CONF_ERRSTR;
rc.err.data = errstr;
for (p = value[i].data; p < value[i].data + value[i].len; p++) {
if (*p >= 'A' && *p <= 'Z') {
rc.options = NGX_REGEX_CASELESS;
break;
}
}
sn->regex = ngx_http_regex_compile(cf, &rc);
if (sn->regex == NULL) {
return NGX_CONF_ERROR;
}
sn->name = value[i];
cscf->captures = (rc.captures > 0);
}
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"using regex \"%V\" "
"requires PCRE library", &value[i]);
return NGX_CONF_ERROR;
#endif
}
return NGX_CONF_OK;
}
除此之外,之前我们还应该建立存放命令的结构体的变量内存,该开辟过程,放在了ngx_http_core_create_srv_conf中
static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf);
该函数的调用就是在建立SERVER解析的时候
static ngx_http_module_t ngx_http_core_module_ctx = {
ngx_http_core_preconfiguration, /* preconfiguration */
NULL, /* postconfiguration */
ngx_http_core_create_main_conf, /* create main configuration */
ngx_http_core_init_main_conf, /* init main configuration */
ngx_http_core_create_srv_conf, /* create server configuration */
ngx_http_core_merge_srv_conf, /* merge server configuration */
ngx_http_core_create_loc_conf, /* create location configuration */
ngx_http_core_merge_loc_conf /* merge location configuration */
};
这样,在该模块中,我们就能够使用传递进来的变量了