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

2024-03-27 21:48

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

本文讲解http各个模块create_srv_conf和create_loc_conf钩子,还有指令的解析。
各模块的create_srv_conf和create_loc_conf函数逻辑都类似,不一一列举,执行完后内存视图是。
这里没有描述
下面是指令的解析。

1 access模块

1 allow、deny指令

// 每次遇到allow或者deny命令的时候执行的回调
static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,void *conf)
{ngx_http_access_loc_conf_t *alcf = conf;ngx_str_t               *value;ngx_inet_cidr_t          in_cidr;ngx_http_access_rule_t  *rule;// 存储配置的结构体if (alcf->rules == NULL) {alcf->rules = ngx_create_array(cf->pool, 5,sizeof(ngx_http_access_rule_t));if (alcf->rules == NULL) {return NGX_CONF_ERROR;}}if (!(rule = ngx_push_array(alcf->rules))) {return NGX_CONF_ERROR;}value = cf->args->elts;// 第一个字符是d说明是deny,否则是allowrule->deny = (value[0].data[0] == 'd') ? 1 : 0;// allif (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) {rule->mask = 0;rule->addr = 0;return NGX_CONF_OK;}// 配置了具体的值,转成二进制形式的iprule->addr = inet_addr((char *) value[1].data);// ip有效if (rule->addr != INADDR_NONE) {rule->mask = 0xffffffff;return NGX_CONF_OK;}// 无效则判断值的格式为cidrif (ngx_ptocidr(&value[1], &in_cidr) == NGX_ERROR) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid paramter \"%s\"",value[1].data);return NGX_CONF_ERROR;}rule->mask = in_cidr.mask;rule->addr = in_cidr.addr;return NGX_CONF_OK;
}	

2 gzip

1 enable指令
gzip模块的配置对应的结构体是

struct {ngx_flag_t           enable;ngx_flag_t           no_buffer;ngx_bufs_t           bufs;ngx_uint_t           http_version;ngx_uint_t           proxied;int                  level;size_t               wbits;size_t               memlevel;ssize_t              min_length;
} ngx_http_gzip_conf_t

使用ngx_conf_set_flag_slot设置enable为0或1。

2 gzip_buffers
设置bufs的num和size字段。即分配num个size大小的buffer用于压缩响应。默认是一页内存的size。

3 gzip_comp_level
设置level字段为压缩等级。并配置了

ngx_conf_num_bounds_t  ngx_http_gzip_comp_level_bounds = {ngx_conf_check_num_bounds, 1, 9
};

ngx_conf_check_num_bounds函数用于检查设置的值是否合法。

char *ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data)
{ngx_conf_num_bounds_t  *bounds = post;ngx_int_t  *np = data;// 如果设置了hign是-1则只需要校验值是否大于lowif (bounds->high == -1) {if (*np >= bounds->low) {return NGX_CONF_OK;}ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"value must be equal or more than %d", bounds->low);return NGX_CONF_ERROR;}// 校验值if (*np >= bounds->low && *np <= bounds->high) {return NGX_CONF_OK;}ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"value must be between %d and %d",bounds->low, bounds->high);return NGX_CONF_ERROR;
}

4 gzip_window
设置wbits字段大小。并配置了校验函数。

static char *ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data)
{int *np = data;int  wbits, wsize;wbits = 15;// 32 * 1024 = 2的15次方,256等于2的8次方for (wsize = 32 * 1024; wsize > 256; wsize >>= 1) {// 如果用户传的和当前的大小一样,把绝对大小转成2的次方数存储if (wsize == *np) {// 用户传的是1k,2k,nginx存的是2的几次方*np = wbits;return NGX_CONF_OK;}// 减一即除以2,右移一位wbits--;}return "must be 512, 1k, 2k, 4k, 8k, 16k, or 32k";
}

5 gzip_hash
设置memlevel字段的值,设置了ngx_http_gzip_set_hash_p函数进行校验。类似ngx_http_gzip_set_window_p函数。

6 gzip_no_buffer
设置no_buffer字段

7 gzip_http_version
设置http_version字段。设置校验函数。


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;np = (ngx_uint_t *) (p + cmd->offset);if (*np != NGX_CONF_UNSET_UINT) {return "is duplicate";}value = cf->args->elts;/*数组,每个元素一个值有效值ngx_conf_enum_t  ngx_http_gzip_http_version[] = {{ ngx_string("1.0"), NGX_HTTP_VERSION_10 },{ ngx_string("1.1"), NGX_HTTP_VERSION_11 },{ ngx_null_string, 0 }};*/e = 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;
}	

8 gzip_proxied
设置proxied字段。nginx作为中间代理的时候,哪些条件下需要会对响应进行压缩。

ngx_conf_bitmask_t  ngx_http_gzip_proxied_mask[] = {{ ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF },{ ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED },{ ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE },{ ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE },{ ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE },{ ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM },{ ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG },{ ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH },{ ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY },{ ngx_null_string, 0 }
};
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;np = (ngx_uint_t *) (p + cmd->offset);value = cf->args->elts;mask = cmd->post;for (i = 1; i < cf->args->nelts; i++) {for (m = 0; mask[m].name.len != 0; m++) {// 比较字符串,不一样则跳过,一样则判断是否已经存在,否则获取对应的mask设置对应的位if (mask[m].name.len != value[i].len|| ngx_strcasecmp(mask[m].name.data, value[i].data) != 0){continue;}// 为true说明np已经存在该mask对应的值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;
}

9 gzip_min_length
设置min_length字段,代表响应的包多大时才进行压缩。响应包根据centent-length进行判断。

3 index模块

1 index 处理请求路径以/结尾的的url

// 把配置的路径放到indices字段。
static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,void *conf)
{ngx_http_index_loc_conf_t *ilcf = conf;ngx_uint_t  i;ngx_str_t  *index, *value;value = cf->args->elts;// 第一个值不能是绝对路径if (value[1].data[0] == '/' && ilcf->indices.nelts == 0) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"first index \"%s\" in \"%s\" directive ""must not be absolute",value[1].data, cmd->name.data);return NGX_CONF_ERROR;}for (i = 1; i < cf->args->nelts; i++) {if (value[i].len == 0) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"index \"%s\" in \"%s\" directive is invalid",value[1].data, cmd->name.data);return NGX_CONF_ERROR;}// push一个字符串到indices数组里ngx_test_null(index, ngx_push_array(&ilcf->indices), NGX_CONF_ERROR);index->len = value[i].len;index->data = value[i].data;// 更新值index指令后面的路径最大字符数if (ilcf->max_index_len < index->len + 1) {ilcf->max_index_len = index->len + 1;}}return NGX_CONF_OK;
}

4 ssl模块

ssl模块主要是设置该结构体的值。

 struct {ngx_flag_t      enable;ngx_str_t       certificate;ngx_str_t       certificate_key;ngx_ssl_ctx_t  *ssl_ctx;
} ngx_http_ssl_srv_conf_t

5 static_handler模块

1 redirect_cache

char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{char  *p = conf;ngx_int_t              i, j, dup, invalid;ngx_str_t              *value, line;ngx_http_cache_t       *c;ngx_http_cache_hash_t  *ch, **chp;chp = (ngx_http_cache_hash_t **) (p + cmd->offset);if (*chp) {return "is duplicate";}// ch指向ngx_http_cache_hash_t结构体if (!(ch = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_hash_t)))) {return NGX_CONF_ERROR;}// 挂载*chp = ch;dup = 0;invalid = 0;value = cf->args->elts;// 格式 value[i] => a=1for (i = 1; i < cf->args->nelts; i++) {// 第二个字符是=if (value[i].data[1] != '=') {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid value \"%s\"", value[i].data);return NGX_CONF_ERROR;}switch (value[i].data[0]) {case 'h':// 已经赋值过if (ch->hash) {dup = 1;break;}// 把等号后面的值转成数字ch->hash = ngx_atoi(value[i].data + 2, value[i].len - 2);if (ch->hash == (size_t)  NGX_ERROR || ch->hash == 0) {invalid = 1;break;}continue;case 'n':if (ch->nelts) {dup = 1;break;}ch->nelts = ngx_atoi(value[i].data + 2, value[i].len - 2);if (ch->nelts == (size_t) NGX_ERROR || ch->nelts == 0) {invalid = 1;break;}continue;case 'l':if (ch->life) {dup = 1;break;}line.len = value[i].len - 2;line.data = value[i].data + 2;ch->life = ngx_parse_time(&line, 1);if (ch->life == NGX_ERROR || ch->life == 0) {invalid = 1;break;}continue;case 'u':if (ch->update) {dup = 1;break;}line.len = value[i].len - 2;line.data = value[i].data + 2;ch->update = ngx_parse_time(&line, 1);if (ch->update == NGX_ERROR || ch->update == 0) {invalid = 1;break;}continue;default:invalid = 1;}if (dup) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"duplicate value \"%s\"", value[i].data);return NGX_CONF_ERROR;}if (invalid) {ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,"invalid value \"%s\"", value[i].data);return NGX_CONF_ERROR;}}// 分配一个元素是ngx_http_cache_t的二维数组ch->elts = ngx_pcalloc(cf->pool,ch->hash * ch->nelts * sizeof(ngx_http_cache_t));if (ch->elts == NULL) {return NGX_CONF_ERROR;}// 初始化二维数组的字段for (i = 0; i < (ngx_int_t) ch->hash; i++) {// ch->elts是一个二维数组,元素是ngx_http_cache_t,c等于每个一维数组的首地址 c = ch->elts + i * ch->nelts;// 初始化该一维数组的fd字段,长度是ch->neltsfor (j = 0; j < (ngx_int_t) ch->nelts; j++) {c[j].fd = NGX_INVALID_FILE;}}return NGX_CONF_OK;
}

6 user_id模块

user_id模块是跟设置cookie相关的

1 userid
是否开启设置cookie的功能。处理函数是ngx_conf_set_enum_slot,可用值是

ngx_http_userid_state[] = {{ ngx_string("off"), NGX_HTTP_USERID_OFF },{ ngx_string("log"), NGX_HTTP_USERID_LOG },{ ngx_string("v1"), NGX_HTTP_USERID_V1 },{ ngx_string("on"), NGX_HTTP_USERID_ON },{ ngx_null_string, 0 }
};

2 userid_service
处理函数是ngx_conf_set_num_slot

3 userid_name,userid_domain,userid_path
这三个是cookie相关的,名字,域名。路径。处理函数是ngx_conf_set_str_slot。其中域名指令配置了校验函数。

char *ngx_conf_check_domain(ngx_conf_t *cf, void *post, void *data)
{ngx_str_t  *domain = data;if (domain->len == 4 && ngx_strcmp(domain->data, "none") == 0) {domain->len = 1;domain->data = (u_char *) ".";}return NGX_CONF_OK;
}

4 userid_expires
该指令设置cookie的过期时间。

char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ngx_http_userid_conf_t *ucf = conf;ngx_str_t   *value;if (ucf->expires != NGX_CONF_UNSET) {return "is duplicate";}value = cf->args->elts;// 值是max代表cookie永不过期if (ngx_strcmp(value[1].data, "max") == 0) {ucf->expires = NGX_HTTP_USERID_MAX_EXPIRES;return NGX_CONF_OK;}// off代表会话cookieif (ngx_strcmp(value[1].data, "off") == 0) {ucf->expires = 0;return NGX_CONF_OK;}// 设置一个固定的时间ucf->expires = ngx_parse_time(&value[1], 1);if (ucf->expires == NGX_ERROR) {return "invalid value";}if (ucf->expires == NGX_PARSE_LARGE_TIME) {return "value must be less than 68 years";}return NGX_CONF_OK;
}

因为http子模块很多,就先分析到这。后面再继续分析其他的子模块。
欢迎关注公众号欢迎关注公众号

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



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

相关文章

详解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和锐捷都是备受关注的品牌,各自有独特的产品特点和市场定位,选择哪个品牌的路由器更合适,实际上取决于你的具体需求和使用场景,我们从... 在选购路由器时,锐捷和腾达都是市场上备受关注的品牌,但它们的定位和特点却有所不同。锐捷更偏向企业级和专