本文讲解http各个模块create_srv_conf和create_loc_conf钩子,还有指令的解析。 各模块的create_srv_conf和create_loc_conf函数逻辑都类似,不一一列举,执行完后内存视图是。
这里没有描述 下面是指令的解析。
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,否则是allow
rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
// all
if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) {
rule->mask = 0;
rule->addr = 0;
return NGX_CONF_OK;
}
// 配置了具体的值,转成二进制形式的ip
rule->addr = inet_addr((char *) value[1].data);
// ip有效
if (rule->addr != INADDR_NONE) {
rule->mask = 0xffffffff;
return NGX_CONF_OK;
}
// 无效则判断值的格式为cidr
if (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;
}
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则只需要校验值是否大于low
if (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进行判断。
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;
}
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
1 redirect_cache
c char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ¨K19K }
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代表会话cookie
if (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子模块很多,就先分析到这。后面再继续分析其他的子模块。