nginx框架---配置文件ngx_conf_handler函数

在上代码之前先做点铺垫,做下简单解释,这样更方便理解源码
在调用ngx_conf_handler前,已经调用了ngx_conf_read_token将配置项信息放入到了cf->args中了,所以能从里面拿到配置项的名称和值
函数逻辑很简单,分为以下几步:
  1. cf->args找到配置项名字
  2. 然后遍历模块,每个模块继续遍历其配置项,找到模块指定配置项指针(ngx_command_t *commands)
  3. 调用其set(函数);
遍历过程对模块不太熟悉的可以看看

ngx_module_t

重点描述下ngx_command_s 的type,也就是配置类型,借用《深入理解nginx模块开发与架构解析》的图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下面是源码(带注释)
static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
    char           *rv;
    void           *conf, **confp;
    ngx_uint_t      i, found;
    ngx_str_t      *name;
    ngx_command_t  *cmd;
	//cf->args->elts 不是包含了配置项的名字和值吗?为什么可以取到名字?
    //因为cf->args->elts是一个链表,首节点就是配置项名字,并且每个元素都以'\0'结尾了
    name = cf->args->elts;

    found = 0;
    //遍历模块
    for (i = 0; cf->cycle->modules[i]; i++) {

        cmd = cf->cycle->modules[i]->commands;
        if (cmd == NULL) {
            continue;
        }
        //遍历模块的配置项
        for ( /* void */ ; cmd->name.len; cmd++) {

            if (name->len != cmd->name.len) {
                continue;
            }
            //匹配配置项的名字
            if (ngx_strcmp(name->data, cmd->name.data) != 0) {
                continue;
            }

            found = 1;

            if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
                && cf->cycle->modules[i]->type != cf->module_type)
            {
                continue;
            }

            /* is the directive's location right ? */
            //匹配配置项的类型
            if (!(cmd->type & cf->cmd_type)) {
                continue;
            }
            //不是块配置项 又没找到字符";"
            if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                  "directive \"%s\" is not terminated by \";\"",
                                  name->data);
                return NGX_ERROR;
            }
            //是块配置项又没找到字符"{"
            if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                   "directive \"%s\" has no opening \"{\"",
                                   name->data);
                return NGX_ERROR;
            }

            /* is the directive's argument count right ? */
            //排除参数个数与配置项要求不符合的情况
            if (!(cmd->type & NGX_CONF_ANY)) {

                if (cmd->type & NGX_CONF_FLAG) {

                    if (cf->args->nelts != 2) {
                        goto invalid;
                    }

                } else if (cmd->type & NGX_CONF_1MORE) {

                    if (cf->args->nelts < 2) {
                        goto invalid;
                    }

                } else if (cmd->type & NGX_CONF_2MORE) {

                    if (cf->args->nelts < 3) {
                        goto invalid;
                    }

                } else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {

                    goto invalid;

                } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
                {
                    goto invalid;
                }
            }

            /* set up the directive's configuration context */

            conf = NULL;
            
            if (cmd->type & NGX_DIRECT_CONF) {
                conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];

            } else if (cmd->type & NGX_MAIN_CONF) {
                conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);

            } else if (cf->ctx) {
                confp = *(void **) ((char *) cf->ctx + cmd->conf);

                if (confp) {
                    conf = confp[cf->cycle->modules[i]->ctx_index];
                }
            }

            rv = cmd->set(cf, cmd, conf);

            if (rv == NGX_CONF_OK) {
                return NGX_OK;
            }

            if (rv == NGX_CONF_ERROR) {
                return NGX_ERROR;
            }

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                               "\"%s\" directive %s", name->data, rv);

            return NGX_ERROR;
        }
    }

    if (found) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "\"%s\" directive is not allowed here", name->data);

        return NGX_ERROR;
    }

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "unknown directive \"%s\"", name->data);

    return NGX_ERROR;

invalid:

    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                       "invalid number of arguments in \"%s\" directive",
                       name->data);

    return NGX_ERROR;
}
上诉源码内容有注释,不做多解释,下面代码可能看起来可能会有点晕,我描述下自己的理解,
 			if (cmd->type & NGX_DIRECT_CONF) {
                conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];

            } else if (cmd->type & NGX_MAIN_CONF) {
                conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);

            } else if (cf->ctx) {
                confp = *(void **) ((char *) cf->ctx + cmd->conf);

                if (confp) {
                    conf = confp[cf->cycle->modules[i]->ctx_index];
                }
            }

            rv = cmd->set(cf, cmd, conf);
cf->ctx 是一个void****指针,就是全局变量cycle的指针
struct ngx_cycle_s {
    void                  ****conf_ctx;
	....    
}
根据配置项类型,来取出其在conf_ctx结构体中的位置

1、当类型是包含NGX_DIRECT_CONF时,"{}"外的配置,conf =((void **) cf->ctx)[cf->cycle->modules[i]->index];

2、当类型是包含NGX_MAIN_CONF时, "{}"外的配置,conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);

有什么区别呢?你可以把((void *) cf->ctx)[cf->cycle->modules[i]->index]当做下图标红的void,区别如下图
在这里插入图片描述

3、当类型不是上诉2种呢?"{}"内的配置,这里的cf->ctx 值已经被更改过了,会指定到结构体上去了

	confp = *(void **) ((char *) cf->ctx + cmd->conf);
    if (confp) {
        conf = confp[cf->cycle->modules[i]->ctx_index];
    }

在这里插入图片描述

为什么指针会这样取?继续讨论,当根据类型取出适当位置的结构体指针后,就调用了下面代码
 	rv = cmd->set(cf, cmd, conf);

顾名思义应该是用来设置配置结构体的,是否真是这样,举例说明:

1、ngx_core_module,下图右边红框标示就是其set函数,由于其类型是NGX_DIRECT_CONF,是核心模块,配置结构体一开始就已经分配好了,也就是conf 所指向的结构体,所以只需要设置其配置结构体的值就好了
在这里插入图片描述
2、ngx_http_module,其类型是NGX_MAIN_CONF,其set接口是 ngx_http_block
详情可参考ngx_http_block
在这里插入图片描述
在该函数内部为conf 分配了内存,代码如下:

static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
	...
	ngx_http_conf_ctx_t         *ctx;
	...
	ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
	...
    *(void **) conf = ctx;
    ...
    cf->ctx = ctx;
}

为了让void*指向ngx_http_conf_ctx_t结构体,conf取数只能如下形式

conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);

在这里插入图片描述
3、ngx_http_core_module,既不是NGX_MAIN_CONF 也不是NGX_DIRECT_CONF,set 接口的内容也是设置值了,不过多描述

在这里插入图片描述
这里说下conf 的取值,为什么要先取confp

confp = *(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
    conf = confp[cf->cycle->modules[i]->ctx_index];
}

这里要注意的是此时cf->ctx在 上诉第2个过程已经更改值了,直接指向了ngx_http_conf_ctx_t结构体如下图所示
在这里插入图片描述
在看下ngx_http_conf_ctx_t定义,cmd->conf就是结构体成员所在的位置,根据confp = *(void **) ((char *) cf->ctx + cmd->conf);
就能知道是哪一个结构体成员,然后根据ctx_index(同级子模块所在的索引)找到指定配置结构体

typedef struct {
    void        **main_conf;
    void        **srv_conf;
    void        **loc_conf;
} ngx_http_conf_ctx_t;
至此基本将配置文件的内容设置进来内存,也就是全局变量cycle 的 ***conf_ctx成员
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

dai1396734

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值