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

2024-03-27 21:48

本文主要是介绍nginx0.1.0之http模块初始化源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

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变量进行的。

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模块

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模块


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模块

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模块

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模块

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后的内存视图如下。
在这里插入图片描述
欢迎关注公众号欢迎关注公众号

这篇关于nginx0.1.0之http模块初始化源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853494

相关文章

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

多模块的springboot项目发布指定模块的脚本方式

《多模块的springboot项目发布指定模块的脚本方式》该文章主要介绍了如何在多模块的SpringBoot项目中发布指定模块的脚本,作者原先的脚本会清理并编译所有模块,导致发布时间过长,通过简化脚本... 目录多模块的springboot项目发布指定模块的脚本1、不计成本地全部发布2、指定模块发布总结多模

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

锐捷和腾达哪个好? 两个品牌路由器对比分析

《锐捷和腾达哪个好?两个品牌路由器对比分析》在选择路由器时,Tenda和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专