前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx0.1.0之http模块初始化源码分析(1)

nginx0.1.0之http模块初始化源码分析(1)

作者头像
theanarkh
发布2019-03-06 10:59:13
5550
发布2019-03-06 10:59:13
举报
文章被收录于专栏:原创分享原创分享

http模块的初始化类似event模块,初始化的起点在解析到http指令的时候。对应的处理函数是ngx_http_block,因为该函数比较长,所以我们分段解析。第一部分先解析http模块的pre_conf、create_main_conf函数的实现。

代码语言:javascript
复制
static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char                        *rv;
    ngx_uint_t                   mi, m, s, l, p, a, n;
    ngx_uint_t                   port_found, addr_found, virtual_names;
    ngx_conf_t                   pcf;
    ngx_array_t                  in_ports;
    ngx_listening_t             *ls;
    ngx_http_listen_t           *lscf;
    ngx_http_module_t           *module;
    ngx_http_handler_pt         *h;
    ngx_http_conf_ctx_t         *ctx;
    ngx_http_in_port_t          *in_port, *inport;
    ngx_http_in_addr_t          *in_addr, *inaddr;
    ngx_http_server_name_t      *s_name, *name;
    ngx_http_core_srv_conf_t   **cscfp, *cscf;
    ngx_http_core_loc_conf_t    *clcf;
    ngx_http_core_main_conf_t   *cmcf;
#if (WIN32)
    ngx_iocp_conf_t             *iocpcf;
#endif

    /* the main http context */
    ngx_test_null(ctx,
                  ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)),
                  NGX_CONF_ERROR);
    // 创建一个ngx_http_conf_ctx_t结构体挂载到cycle的ctx中
    *(ngx_http_conf_ctx_t **) conf = ctx;

    /* count the number of the http modules and set up their indices */

    ngx_http_max_module = 0;
    // 遍历所有的nginx模块,筛选出http模块
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
        // 标记该模块在http中的索引,位置
        ngx_modules[m]->ctx_index = ngx_http_max_module++;
    }
    // 根据http的模块数,分配一个数组,分别由下面三个字段指向
    /* the main http main_conf, it's the same in the all http contexts */
    ngx_test_null(ctx->main_conf,
                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
                  NGX_CONF_ERROR);

    /* the http null srv_conf, it's used to merge the server{}s' srv_conf's */
    ngx_test_null(ctx->srv_conf,
                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
                  NGX_CONF_ERROR);

    /* the http null loc_conf, it's used to merge the server{}s' loc_conf's */
    ngx_test_null(ctx->loc_conf,
                  ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
                  NGX_CONF_ERROR);


    /* create the main_conf, srv_conf and loc_conf in all http modules */

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }
        // http模块的上下文,是ngx_http_module_t结构体
        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;
        // 解析http配置前执行的钩子
        if (module->pre_conf) {
            if (module->pre_conf(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
        // 创建一个ngx_http_core_main_conf_t结构体,挂到main_conf数组相应的位置
        if (module->create_main_conf) {
            ngx_test_null(ctx->main_conf[mi], module->create_main_conf(cf),
                          NGX_CONF_ERROR);
        }
        // 创建一个ngx_http_core_srv_conf_t结构体,挂到srv_conf数组相应的位置
        if (module->create_srv_conf) {
            ngx_test_null(ctx->srv_conf[mi], module->create_srv_conf(cf), 
                          NGX_CONF_ERROR);
        }
        // 创建一个ngx_http_core_loc_conf_s 结构体,挂到loc_conf数组相应的位置
        if (module->create_loc_conf) {
            ngx_test_null(ctx->loc_conf[mi], module->create_loc_conf(cf),
                          NGX_CONF_ERROR);
        }
    }
    ...
}

下面我们看一下各个http模块的这些钩子函数都做了些什么。

1 pre_conf钩子

log模块 其他模块都是基于log模块的ngx_http_log_fmt_ops变量进行的。

代码语言:javascript
复制
ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = {
    { ngx_string("addr"), INET_ADDRSTRLEN - 1, ngx_http_log_addr },
    { ngx_string("conn"), NGX_INT32_LEN, ngx_http_log_connection },
    { ngx_string("pipe"), 1, ngx_http_log_pipe },
    { ngx_string("time"), sizeof("28/Sep/1970:12:00:00") - 1,
                          ngx_http_log_time },
    { ngx_string("msec"), TIME_T_LEN + 4, ngx_http_log_msec },
    { ngx_string("request"), 0, ngx_http_log_request },
    { ngx_string("status"), 3, ngx_http_log_status },
    { ngx_string("length"), NGX_OFF_T_LEN, ngx_http_log_length },
    { ngx_string("apache_length"), NGX_OFF_T_LEN, ngx_http_log_apache_length },
    { ngx_string("i"), NGX_HTTP_LOG_ARG, ngx_http_log_header_in },
    { ngx_string("o"), NGX_HTTP_LOG_ARG, ngx_http_log_header_out },
    { ngx_null_string, 0, NULL }
};

static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf)
{
    ngx_http_log_op_name_t  *op;

    for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ }
    op->op = NULL;

    return NGX_OK;
}

gzip模块

代码语言:javascript
复制
static ngx_http_log_op_name_t ngx_http_gzip_log_fmt_ops[] = {
    { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, ngx_http_gzip_log_ratio },
    { ngx_null_string, 0, NULL }
};

static ngx_int_t ngx_http_gzip_pre_conf(ngx_conf_t *cf)
{
    ngx_http_log_op_name_t  *op;
    /*
        找到第一个没有名字的项,即最后一项,然后把op置空,
        为了防止下面一个for循环的时候op->op为空,不会导致死循环,
        因为执行完该函数后,op->op是下一个pre_conf函数执行时,
        ngx_http_log_fmt_ops数组的最后一个被判断的op->op
    */
    for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ }
    op->op = NULL;

    op = ngx_http_log_fmt_ops;
    /*
        找到最后一个op有值但是没有名字的项,这里其实是一个巧妙的设计,
        因为op有值但是没有名字的项,op->op指向的是一个ngx_http_log_op_name_t数组,
        然后op继续指向该数组第一个元素,继续迭代
    */
    for (op = ngx_http_log_fmt_ops; op->op; op++) {
        if (op->name.len == 0) {
            op = (ngx_http_log_op_name_t *) op->op;
        }
    }
    /*
        每个模块中的ngx_http_log_op_name_t数组最后一个元素都是空的,
        然后在这给op->op赋值,op->op指向的数组的最后一个元素也是空项,以此类推
    */
    op->op = (ngx_http_log_op_pt) ngx_http_gzip_log_fmt_ops;

    return NGX_OK;
}

userid模块

代码语言:javascript
复制
static ngx_http_log_op_name_t ngx_http_userid_log_fmt_ops[] = {
    { ngx_string("uid_got"), 0, ngx_http_userid_log_uid_got },
    { ngx_string("uid_set"), 0, ngx_http_userid_log_uid_set },
    { ngx_null_string, 0, NULL }
};
static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf)
{
    ngx_http_log_op_name_t  *op;

    for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ }
    op->op = NULL;

    op = ngx_http_log_fmt_ops;

    for (op = ngx_http_log_fmt_ops; op->op; op++) {
        if (op->name.len == 0) {
            op = (ngx_http_log_op_name_t *) op->op;
        }
    }

    op->op = (ngx_http_log_op_pt) ngx_http_userid_log_fmt_ops;

    return NGX_OK;
}

各模块不一一列举,各模块的pre_conf函数执行完后内存视图是如下。

在这里插入图片描述

2 create_main_conf钩子

1 http_core模块

代码语言:javascript
复制
static void *ngx_http_core_create_main_conf(ngx_conf_t *cf)
{
    ngx_http_core_main_conf_t *cmcf;

    ngx_test_null(cmcf,
                  ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t)),
                  NGX_CONF_ERROR);

    ngx_init_array(cmcf->servers, cf->pool,
                   5, sizeof(ngx_http_core_srv_conf_t *),
                   NGX_CONF_ERROR);

    return cmcf;
}

2 charset_filter模块

代码语言:javascript
复制
static void *ngx_http_charset_create_main_conf(ngx_conf_t *cf)
{
    ngx_http_charset_main_conf_t  *mcf;

    if (!(mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_main_conf_t)))) {
        return NGX_CONF_ERROR;
    }

    ngx_init_array(mcf->charsets, cf->pool, 5, sizeof(ngx_http_charset_t),
                   NGX_CONF_ERROR);

    ngx_init_array(mcf->tables, cf->pool, 10, sizeof(ngx_http_charset_tables_t),
                   NGX_CONF_ERROR);

    return mcf;
}

3 log模块

代码语言:javascript
复制
static void *ngx_http_log_create_main_conf(ngx_conf_t *cf)
{
    ngx_http_log_main_conf_t  *conf;

    char       *rc;
    ngx_str_t  *value;

    if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)))) {
        return NGX_CONF_ERROR;
    }

    ngx_init_array(conf->formats, cf->pool, 5, sizeof(ngx_http_log_fmt_t),
                  NGX_CONF_ERROR);

    cf->args->nelts = 0;
    // 设置参数,在ngx_http_log_set_format里使用
    if (!(value = ngx_push_array(cf->args))) {
        return NGX_CONF_ERROR;
    }

    if (!(value = ngx_push_array(cf->args))) {
        return NGX_CONF_ERROR;
    }

    value->len = sizeof("combined") - 1;
    value->data = (u_char *) "combined";

    if (!(value = ngx_push_array(cf->args))) {
        return NGX_CONF_ERROR;
    }

    *value = ngx_http_combined_fmt;

    rc = ngx_http_log_set_format(cf, NULL, conf);
    if (rc != NGX_CONF_OK) {
        return NULL;
    }

    return conf;
}

执行完create_main_conf后的内存视图如下。

在这里插入图片描述

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 pre_conf钩子
  • 2 create_main_conf钩子
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档