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

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

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

我们继续分析ngx_http_block函数的代码,指令解析完,继续执行各子模块的钩子函数。

代码语言:javascript
复制
/*
     * init http{} main_conf's, merge the server{}s' srv_conf's
     * and its location{}s' loc_conf's
     */
    // 取出ngx_http_core_module在http上下文的main配置 
    cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
    // server指令的管理结构
    cscfp = cmcf->servers.elts;

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

        /* init http{} main_conf's */
        // ngx_conf_parse没有赋值的字段在这进行初始化
        if (module->init_main_conf) {
            rv = module->init_main_conf(cf, ctx->main_conf[mi]);
            if (rv != NGX_CONF_OK) {
                *cf = pcf;
                return rv;
            }
        }
        // http上下文下所有的server指令对应的结构体数组
        for (s = 0; s < cmcf->servers.nelts; s++) {

            /* merge the server{}s' srv_conf's */

            if (module->merge_srv_conf) {
                // 合并http层和server层配置
                rv = module->merge_srv_conf(cf,
                                            // 子模块在http上下文的srv_conf配置,内容由子模块创建
                                            ctx->srv_conf[mi],
                                            /*
                                                cscfp[s]指向server上下文中的ngx_http_core_srv_conf_t结构体,
                                                通过反向指针找到server指令创建的上下文,再找出某个模块的的srv_conf
                                            */
                                            cscfp[s]->ctx->srv_conf[mi]);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }
            }

            if (module->merge_loc_conf) {

                /* merge the server{}'s loc_conf */
                // 合并http层和非嵌套的location层的配置
                rv = module->merge_loc_conf(cf,
                                            ctx->loc_conf[mi],
                                            cscfp[s]->ctx->loc_conf[mi]);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }

                /* merge the locations{}' loc_conf's */
                /*
                    合并server和非嵌套location的配置、非嵌套location和嵌套location的配置,
                    &cscfp[s]->locations:server下的所有非嵌套location
                    cscfp[s]->ctx->loc_conf,server层各模块关于location的配置 
                */
                rv = ngx_http_merge_locations(cf, &cscfp[s]->locations,
                                              cscfp[s]->ctx->loc_conf,
                                              module, mi);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }
            }
        }
    }

1 init_main_conf 只有charset模块实现了init_main_conf函数。

代码语言:javascript
复制
static char *ngx_http_charset_init_main_conf(ngx_conf_t *cf, void *conf)
{
    ngx_http_charset_main_conf_t *mcf = conf;

    ngx_uint_t                  i, n;
    ngx_http_charset_t         *charset;
    ngx_http_charset_tables_t  *tables;

    tables = mcf->tables.elts;
    charset = mcf->charsets.elts;
    // 遍历charset数组
    for (i = 0; i < mcf->charsets.nelts; i++) {
        if (!charset[i].server) {
            continue;
        }

        charset[i].tables = ngx_pcalloc(cf->pool,
                                        sizeof(char *) * mcf->charsets.nelts);

        if (charset[i].tables == NULL) {
            return NGX_CONF_ERROR;
        }

        for (n = 0; n < mcf->tables.nelts; n++) {
            if ((ngx_int_t) i == tables[n].src) {
                charset[i].tables[tables[n].dst] = tables[n].src2dst;
                continue;
            }

            if ((ngx_int_t) i == tables[n].dst) {
                charset[i].tables[tables[n].src] = tables[n].dst2src;
            }
        }
    }
    //校验
    for (i = 0; i < mcf->charsets.nelts; i++) {
        if (!charset[i].server) {
            continue;
        }

        for (n = 0; n < mcf->charsets.nelts; n++) {
            if (i == n) {
                continue;
            }

            if (charset[i].tables[n]) {
                continue;
            }

            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
                          " no \"charset_map\" between the charsets "
                          "\"%s\" and \"%s\"",
                          charset[i].name.data, charset[n].name.data);
            return NGX_CONF_ERROR;
        }
    }

    return NGX_CONF_OK;
}

在这里插入图片描述

2 merge_srv_conf 我们继续看一下各个模块的merge_srv_conf函数。 http_core模块

代码语言:javascript
复制
static char *ngx_http_core_merge_srv_conf(ngx_conf_t *cf,
                                          void *parent, void *child)
{
    ngx_http_core_srv_conf_t *prev = parent;
    ngx_http_core_srv_conf_t *conf = child;

    ngx_http_listen_t          *l;
    ngx_http_server_name_t     *n;
    ngx_http_core_main_conf_t  *cmcf;

    /* TODO: it does not merge, it inits only */
    // 如果该server没有配置listen指令,则设置默认值
    if (conf->listen.nelts == 0) {
        ngx_test_null(l, ngx_push_array(&conf->listen), NGX_CONF_ERROR);
        // 任何地址进来的连接都可以
        l->addr = INADDR_ANY;
#if (WIN32)
        l->port = 80;
#else
        /* STUB: getuid() should be cached */
        // 等于0说明是root
        l->port = (getuid() == 0) ? 80 : 8000;
#endif
        l->family = AF_INET;
    }
    // 没有配置servername,则取本机主机名
    if (conf->server_names.nelts == 0) {
        ngx_test_null(n, ngx_push_array(&conf->server_names), NGX_CONF_ERROR);
        ngx_test_null(n->name.data, ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN),
                      NGX_CONF_ERROR);
        // 获取主机名 
        if (gethostname((char *) n->name.data, NGX_MAXHOSTNAMELEN) == -1) {
            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
                               "gethostname() failed");
            return NGX_CONF_ERROR;
        }

        n->name.len = ngx_strlen(n->name.data);
        // 该servername对应的server配置
        n->core_srv_conf = conf;

#if 0
        ctx = (ngx_http_conf_ctx_t *)
                                    cf->cycle->conf_ctx[ngx_http_module.index];
        cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
#endif
        cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

        if (cmcf->max_server_name_len < n->name.len) {
            cmcf->max_server_name_len = n->name.len;
        }
    }
    /*
        如果第一个参数没有值,则取第二个参数的,如果第二个参数也没有值,
        则取第三个参数的,即子类没有值,则取父类的,父类也没有值,则取默认的
    */
    ngx_conf_merge_size_value(conf->connection_pool_size,
                              prev->connection_pool_size, 256);
    ngx_conf_merge_msec_value(conf->post_accept_timeout,
                              prev->post_accept_timeout, 60000);
    ngx_conf_merge_size_value(conf->request_pool_size,
                              prev->request_pool_size, 4096);
    ngx_conf_merge_msec_value(conf->client_header_timeout,
                              prev->client_header_timeout, 60000);
    ngx_conf_merge_size_value(conf->client_header_buffer_size,
                              prev->client_header_buffer_size, 1024);
    ngx_conf_merge_bufs_value(conf->large_client_header_buffers,
                              prev->large_client_header_buffers,
                              4, ngx_pagesize);

    if (conf->large_client_header_buffers.size < conf->connection_pool_size) {
        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                           "the \"large_client_header_buffers\" size must be "
                           "equal to or bigger than \"connection_pool_size\"");
        return NGX_CONF_ERROR;
    }

    ngx_conf_merge_unsigned_value(conf->restrict_host_names,
                                  prev->restrict_host_names, 0);

    return NGX_CONF_OK;
}

rewrite模块

代码语言:javascript
复制
static char *ngx_http_rewrite_merge_srv_conf(ngx_conf_t *cf,
                                             void *parent, void *child)
{
    ngx_http_rewrite_srv_conf_t *prev = parent;
    ngx_http_rewrite_srv_conf_t *conf = child;

    ngx_conf_merge_value(conf->log, prev->log, 0);

    return NGX_CONF_OK;
}

ssl模块

代码语言:javascript
复制
static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
                                         void *parent, void *child)
{
    ngx_http_ssl_srv_conf_t *prev = parent;
    ngx_http_ssl_srv_conf_t *conf = child;

    ngx_conf_merge_value(conf->enable, prev->enable, 0);

    if (conf->enable == 0) {
        return NGX_CONF_OK;
    }
    // server上下文里没有配置证书和私钥则取http上下文的
    ngx_conf_merge_str_value(conf->certificate, prev->certificate,
                             NGX_DEFLAUT_CERTIFICATE);

    ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
                             NGX_DEFLAUT_CERTIFICATE_KEY);

    /* TODO: configure methods */

    conf->ssl_ctx = SSL_CTX_new(SSLv23_server_method());

    if (conf->ssl_ctx == NULL) {
        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, "SSL_CTX_new() failed");
        return NGX_CONF_ERROR;
    }
    // 加载用户证书
    if (SSL_CTX_use_certificate_file(conf->ssl_ctx,
                                     (char *) conf->certificate.data,
                                     SSL_FILETYPE_PEM) == 0) {
        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
                      "SSL_CTX_use_certificate_file(\"%s\") failed",
                      conf->certificate.data);
        return NGX_CONF_ERROR;
    }
    // 加载用户私钥
    if (SSL_CTX_use_PrivateKey_file(conf->ssl_ctx,
                                    (char *) conf->certificate_key.data,
                                    SSL_FILETYPE_PEM) == 0) {
        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed",
                      conf->certificate_key.data);
        return NGX_CONF_ERROR;
    }

    return NGX_CONF_OK;
}

3 merge_loc_conf access模块

代码语言:javascript
复制
static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf,
                                            void *parent, void *child)
{
    ngx_http_access_loc_conf_t  *prev = parent;
    ngx_http_access_loc_conf_t  *conf = child;
    // 如果location里的配置为空,则取父级的配置
    if (conf->rules == NULL) {
        conf->rules = prev->rules;
    }

    return NGX_CONF_OK;
}

charset模块

代码语言:javascript
复制
static char *ngx_http_charset_merge_loc_conf(ngx_conf_t *cf,
                                             void *parent, void *child)
{
    ngx_http_charset_loc_conf_t *prev = parent;
    ngx_http_charset_loc_conf_t *conf = child;

    ngx_conf_merge_value(conf->enable, prev->enable, 0);
    ngx_conf_merge_value(conf->autodetect, prev->autodetect, 0);

    if (conf->source_charset == NGX_CONF_UNSET) {
        conf->source_charset = prev->source_charset;
    }

    ngx_conf_merge_value(conf->default_charset, prev->default_charset,
                         conf->source_charset);

    return NGX_CONF_OK;
}

http_core模块

代码语言:javascript
复制
static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
                                          void *parent, void *child)
{
    ngx_http_core_loc_conf_t *prev = parent;
    ngx_http_core_loc_conf_t *conf = child;

    int               i, key;
    ngx_http_type_t  *t;

    ngx_conf_merge_str_value(conf->root, prev->root, "html");

    if (ngx_conf_full_name(cf->cycle, &conf->root) == NGX_ERROR) {
        return NGX_CONF_ERROR;
    }
    // 子层没有配置types
    if (conf->types == NULL) {
        // 父层也没有配置
        if (prev->types) {
            conf->types = prev->types;

        } else {
            // 取默认的
            ngx_test_null(conf->types,
                          ngx_palloc(cf->pool, NGX_HTTP_TYPES_HASH_PRIME
                                                        * sizeof(ngx_array_t)),
                          NGX_CONF_ERROR);
            // 初始化分配的数组
            for (i = 0; i < NGX_HTTP_TYPES_HASH_PRIME; i++) {
                ngx_init_array(conf->types[i], cf->pool,
                               5, sizeof(ngx_http_type_t), NGX_CONF_ERROR);
            }
            // 遍历默认配置
            for (i = 0; default_types[i].exten.len; i++) {
                /*
                    #define ngx_http_types_hash_key(key, ext)                                   \
                    {                                                                   \
                        u_int n;                                                        \
                        for (key = 0, n = 0; n < ext.len; n++) {                        \
                            key += ext.data[n];                                         \
                        }                                                               \
                        key %= NGX_HTTP_TYPES_HASH_PRIME;                               \
                    }
                */
                // 用宏算出数组索引,如果索引一样说明extern一样,则覆盖,这里假设了不会存在html和lmth这样type
                ngx_http_types_hash_key(key, default_types[i].exten);

                ngx_test_null(t, ngx_push_array(&conf->types[key]),
                              NGX_CONF_ERROR);
                t->exten.len = default_types[i].exten.len;
                t->exten.data = default_types[i].exten.data;
                t->type.len = default_types[i].type.len;
                t->type.data = default_types[i].type.data;
            }
        }
    }

    if (conf->err_log == NULL) {
        if (prev->err_log) {
            conf->err_log = prev->err_log;
        } else {
            conf->err_log = cf->cycle->new_log;
        }
    }

    if (conf->error_pages == NULL && prev->error_pages) {
        conf->error_pages = prev->error_pages;
    }

    ngx_conf_merge_str_value(conf->default_type,
                             prev->default_type, "text/plain");

    ngx_conf_merge_size_value(conf->client_max_body_size,
                              prev->client_max_body_size, 1 * 1024 * 1024);
    ngx_conf_merge_size_value(conf->client_body_buffer_size,
                              prev->client_body_buffer_size,
                              (size_t) 2 * ngx_pagesize);
    ngx_conf_merge_msec_value(conf->client_body_timeout,
                              prev->client_body_timeout, 60000);
    ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
    ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
    ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 60000);
    ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0);
    ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output,
                              1460);
    ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0);
    ngx_conf_merge_msec_value(conf->keepalive_timeout,
                              prev->keepalive_timeout, 75000);
    ngx_conf_merge_sec_value(conf->keepalive_header,
                              prev->keepalive_header, 0);
    ngx_conf_merge_msec_value(conf->lingering_time,
                              prev->lingering_time, 30000);
    ngx_conf_merge_msec_value(conf->lingering_timeout,
                              prev->lingering_timeout, 5000);

    ngx_conf_merge_value(conf->reset_timedout_connection,
                         prev->reset_timedout_connection, 0);
    ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);

    if (conf->open_files == NULL) {
        conf->open_files = prev->open_files;
    }

    return NGX_CONF_OK;
}

其余模块就不一一列举,大致的逻辑都是一样的,就是子层的配置没有值则取父层的,父层也没有值则取默认的。

4 ngx_http_merge_locations

代码语言:javascript
复制
static char *ngx_http_merge_locations(ngx_conf_t *cf,
                                      ngx_array_t *locations,
                                      void **loc_conf,
                                      ngx_http_module_t *module,
                                      ngx_uint_t ctx_index)
{
    char                       *rv;
    ngx_uint_t                  i;
    ngx_http_core_loc_conf_t  **clcfp;

    clcfp = /* (ngx_http_core_loc_conf_t **) */ locations->elts;
    // 遍历父层的location
    for (i = 0; i < locations->nelts; i++) {
        /* 
            先合并server和非嵌套location层的配置
            loc_conf[ctx_index]:server层的location配置,
            clcfp[i]->loc_conf[ctx_index]:location层各模块的配置
        */
        rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
                                    clcfp[i]->loc_conf[ctx_index]);
        if (rv != NGX_CONF_OK) {
            return rv;
        }
        /*
          再合并嵌套location和非嵌套location的配置, 
          &clcfp[i]->locations:各模块关于嵌套的lcaotion,
          clcfp[i]->loc_conf:各模块和关于非嵌套location的配置
        */
        rv = ngx_http_merge_locations(cf, &clcfp[i]->locations,
                                      clcfp[i]->loc_conf, module, ctx_index);
        if (rv != NGX_CONF_OK) {
            return rv;
        }
    }

    return NGX_CONF_OK;
}

http模块初始化到这,内存视图差不多是下图所示。http、server、location都有类似的结构,一个配置最后存储在哪个位置取决于他在哪个上下文中。

这里没有描述

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

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

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

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

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