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,否则是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;
}	

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则只需要校验值是否大于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进行判断。

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=1
   for (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->nelts
       for (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代表会话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子模块很多,就先分析到这。后面再继续分析其他的子模块。
欢迎关注公众号欢迎关注公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值