本文主要是介绍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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!