前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx0.1.0之http模块初始化源码分析(2)

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

作者头像
theanarkh
发布2019-03-06 09:53:49
3520
发布2019-03-06 09:53:49
举报
文章被收录于专栏:原创分享原创分享

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

这里没有描述 下面是指令的解析。

1 access模块

1 allow、deny指令

代码语言:javascript
复制
// 每次遇到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模块的配置对应的结构体是

代码语言:javascript
复制
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字段为压缩等级。并配置了

代码语言:javascript
复制
ngx_conf_num_bounds_t  ngx_http_gzip_comp_level_bounds = {
    ngx_conf_check_num_bounds, 1, 9
};

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

代码语言:javascript
复制
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字段大小。并配置了校验函数。

代码语言:javascript
复制
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字段。设置校验函数。

代码语言:javascript
复制
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作为中间代理的时候,哪些条件下需要会对响应进行压缩。

代码语言:javascript
复制
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

代码语言:javascript
复制
// 把配置的路径放到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模块主要是设置该结构体的值。

代码语言:javascript
复制
 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 c char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ¨K19K }

6 user_id模块

user_id模块是跟设置cookie相关的

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

代码语言:javascript
复制
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。其中域名指令配置了校验函数。

代码语言:javascript
复制
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的过期时间。

代码语言:javascript
复制
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子模块很多,就先分析到这。后面再继续分析其他的子模块。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 access模块
  • 2 gzip
  • 3 index模块
  • 4 ssl模块
  • 5 static_handler模块
  • 6 user_id模块
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档