在研读nginx源代码的时候,发现nginx在处理conf的时候,经常会使用ngx_conf_set_off_slot、ngx_conf_set_msec_slot、ngx_conf_set_sec_slot、ngx_conf_set_bufs_slot、ngx_conf_set_enum_slot、ngx_conf_set_bitmask_slot等函数,为了以后的方便,现将以下函数仔细分析一遍。
char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd,void *conf);
char *ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
struct ngx_command_s {
ngx_str_t name;
ngx_uint_t type;
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf;
ngx_uint_t offset; //主要是存放转换后的值在配置结构体的偏移
void *post;
};
函数功能:处理类似variables_hash_max_size 512这样的指令。
char *
ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_int_t *np;
ngx_str_t *value;
ngx_conf_post_t *post;
// offset主要是存放转换后的值在配置结构体的偏移
np = (ngx_int_t *) (p + cmd->offset);
if (*np != NGX_CONF_UNSET) {
return "is duplicate";
}
value = cf->args->elts;
*np = ngx_atoi(value[1].data, value[1].len); //转化为整数
if (*np == NGX_ERROR) {
return "invalid number";
}
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, np);
}
return NGX_CONF_OK;
}
函数功能:处理类似client_body_timeout 60s/1d这样的指令。
char *
ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_msec_t *msp;
ngx_str_t *value;
ngx_conf_post_t *post;
// offset主要是存放转换后的值在配置结构体的偏移
msp = (ngx_msec_t *) (p + cmd->offset);
if (*msp != NGX_CONF_UNSET_MSEC) {
return "is duplicate";
}
value = cf->args->elts;
*msp = ngx_parse_time(&value;[1], 0); //0表示以毫秒为单位
if (*msp == (ngx_msec_t) NGX_ERROR) {
return "invalid value";
}
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, msp);
}
return NGX_CONF_OK;
}
函数功能:处理类似ssl_session_timeout 30m/1d这样的指令。
char *
ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
time_t *sp;
ngx_str_t *value;
ngx_conf_post_t *post;
// offset主要是存放转换后的值在配置结构体的偏移
sp = (time_t *) (p + cmd->offset);
if (*sp != NGX_CONF_UNSET) {
return "is duplicate";
}
value = cf->args->elts;
*sp = ngx_parse_time(&value;[1], 1); //1表示以秒为单位
if (*sp == (time_t) NGX_ERROR) {
return "invalid value";
}
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, sp);
}
return NGX_CONF_OK;
}
函数功能:处理类似client_body_buffer_size 512/512K/512M这样的指令。
char *
ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
size_t *sp;
ngx_str_t *value;
ngx_conf_post_t *post;
// offset主要是存放转换后的值在配置结构体的偏移
sp = (size_t *) (p + cmd->offset);
if (*sp != NGX_CONF_UNSET_SIZE) {
return "is duplicate";
}
value = cf->args->elts;
*sp = ngx_parse_size(&value;[1]); //K/M,byte为默认单位
if (*sp == (size_t) NGX_ERROR) {
return "invalid value";
}
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, sp);
}
return NGX_CONF_OK;
}
函数功能:处理类似client_max_body_size 128K/128M/128G这样的指令。
备注:ngx_conf_set_off_slot和ngx_conf_set_size_slot很相似,能看出的不同点就是ngx_conf_set_size_slot不支持G。
char *
ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
off_t *op;
ngx_str_t *value;
ngx_conf_post_t *post;
// offset主要是存放转换后的值在配置结构体的偏移
op = (off_t *) (p + cmd->offset);
if (*op != NGX_CONF_UNSET) {
return "is duplicate";
}
value = cf->args->elts;
*op = ngx_parse_offset(&value;[1]); //K/M/G
if (*op == (off_t) NGX_ERROR) {
return "invalid value";
}
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, op);
}
return NGX_CONF_OK;
}
函数功能:处理类似daemon off/on这样的指令。
char *
ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_str_t *value;
ngx_flag_t *fp;
ngx_conf_post_t *post;
// offset主要是存放转换后的值在配置结构体的偏移
fp = (ngx_flag_t *) (p + cmd->offset);
if (*fp != NGX_CONF_UNSET) {
return "is duplicate";
}
value = cf->args->elts;
if (ngx_strcasecmp(value[1].data, (u_char *) "on") == 0) {
*fp = 1;
} else if (ngx_strcasecmp(value[1].data, (u_char *) "off") == 0) {
*fp = 0;
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid value \"%s\" in \"%s\" directive, "
"it must be \"on\" or \"off\"",
value[1].data, cmd->name.data);
return NGX_CONF_ERROR;
}
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, fp);
}
return NGX_CONF_OK;
}
函数功能:处理类似pid logs/nginx.pid这样的指令。
char *
ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_str_t *field, *value;
ngx_conf_post_t *post;
// offset主要是存放转换后的值在配置结构体的偏移
field = (ngx_str_t *) (p + cmd->offset);
if (field->data) {
return "is duplicate";
}
value = cf->args->elts;
*field = value[1];
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, field);
}
return NGX_CONF_OK;
}
函数功能:处理类似large_client_header_buffers 4 2k这样的指令。
char *
ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_str_t *value;
ngx_bufs_t *bufs;
// offset主要是存放转换后的值在配置结构体的偏移
bufs = (ngx_bufs_t *) (p + cmd->offset);
if (bufs->num) {
return "is duplicate";
}
value = cf->args->elts;
//第一个参数,整数
bufs->num = ngx_atoi(value[1].data, value[1].len);
if (bufs->num == NGX_ERROR || bufs->num == 0) {
return "invalid value";
}
//第二个参数,size
bufs->size = ngx_parse_size(&value;[2]);
if (bufs->size == (size_t) NGX_ERROR || bufs->size == 0) {
return "invalid value";
}
return NGX_CONF_OK;
}
函数功能:处理类似proxy_http_version 1.1这样的指令。
char *
ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_uint_t *np, i;
ngx_str_t *value;
ngx_conf_enum_t *e;
// offset主要是存放转换后的值在配置结构体的偏移
np = (ngx_uint_t *) (p + cmd->offset);
if (*np != NGX_CONF_UNSET_UINT) {
return "is duplicate";
}
value = cf->args->elts;
e = cmd->post;
//需要和cmd->post里的数据进行对比
for (i = 0; e[i].name.len != 0; i++) {
if (e[i].name.len != value[1].len
|| ngx_strcasecmp(e[i].name.data, value[1].data) != 0)
{
continue;
}
*np = e[i].value;
return NGX_CONF_OK;
}
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"invalid value \"%s\"", value[1].data);
return NGX_CONF_ERROR;
}
函数功能:处理类似proxy_next_upstream error timeout http_502 http_503 http_504这样的指令。
char *
ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_uint_t *np, i, m;
ngx_str_t *value;
ngx_conf_bitmask_t *mask;
// offset主要是存放转换后的值在配置结构体的偏移
np = (ngx_uint_t *) (p + cmd->offset);
value = cf->args->elts;
mask = cmd->post;
//需要跟cmd->post里的数据进行对比
for (i = 1; i < cf->args->nelts; i++) {
for (m = 0; mask[m].name.len != 0; m++) {
if (mask[m].name.len != value[i].len
|| ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
{
continue;
}
if (*np & mask[m].mask) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"duplicate value \"%s\"", value[i].data);
} else {
*np |= mask[m].mask;
}
break;
}
if (mask[m].name.len == 0) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"invalid value \"%s\"", value[i].data);
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}
函数功能:处理类似proxy_set_header ORIG_CLIENT_IP $remote_addr这样的指令。
char *
ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ngx_str_t *value;
ngx_array_t **a;
ngx_keyval_t *kv;
ngx_conf_post_t *post;
// offset主要是存放转换后的值在配置结构体的偏移
a = (ngx_array_t **) (p + cmd->offset);
if (*a == NULL) {
*a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t));
if (*a == NULL) {
return NGX_CONF_ERROR;
}
}
kv = ngx_array_push(*a);
if (kv == NULL) {
return NGX_CONF_ERROR;
}
value = cf->args->elts;
kv->key = value[1];
kv->value = value[2];
if (cmd->post) {
post = cmd->post;
return post->post_handler(cf, post, kv);
}
return NGX_CONF_OK;
}
函数功能:处理类似client_body_temp_path /spool/nginx/client_temp 1 2这样的指令。
char *
ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *p = conf;
ssize_t level;
ngx_str_t *value;
ngx_uint_t i, n;
ngx_path_t *path, **slot;
// offset主要是存放转换后的值在配置结构体的偏移
slot = (ngx_path_t **) (p + cmd->offset);
if (*slot) {
return "is duplicate";
}
path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
if (path == NULL) {
return NGX_CONF_ERROR;
}
value = cf->args->elts;
path->name = value[1];
if (path->name.data[path->name.len - 1] == '/') {
path->name.len--;
}
if (ngx_conf_full_name(cf->cycle, &path-;>name, 0) != NGX_OK) {
return NULL;
}
path->len = 0;
path->manager = NULL;
path->loader = NULL;
path->conf_file = cf->conf_file->file.name.data;
path->line = cf->conf_file->line;
for (i = 0, n = 2; n < cf->args->nelts; i++, n++) {
level = ngx_atoi(value[n].data, value[n].len);
if (level == NGX_ERROR || level == 0) {
return "invalid value";
}
path->level[i] = level;
path->len += level + 1;
}
while (i < 3) {
path->level[i++] = 0;
}
*slot = path;
if (ngx_add_path(cf, slot) == NGX_ERROR) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}