Nginx基础. Nginx通配散列表

本文介绍了Nginx如何支持通配符的散列表,包括前置和后置通配符的处理方法,如ngx_hash_find_wc_tail和ngx_hash_find_wc_head函数的使用。在散列表中,通配符关键字被特殊处理以便查询。初始化函数和查找过程也进行了分析,虽然未能详细探讨构成names的过程。
摘要由CSDN通过智能技术生成
之前学习过Nginx中的普通散列表, 关于其初始化以及整体的构造有了大致的了解.
接下来就是在普通散列表的基础上, 分析更复杂的散列表构造. 因为Nginx作为一个Web服务器, 它的各种散列表中的关键字多以字符串为主, 特别是URI域名, 比如 www.ben.com.
既然是这样, 那么Nginx就需要去支持带有通配符的主机域名, 即带"*"的域名, 包括前置通配符, 如 *.test.com; 或是后置通配符, 如www.ben.*. 注意的是, 不支持通配符在中间.


支持通配符的散列表
文章开头提到Nginx支持具有前置通配符或是后置通配符或是没有通配符的域名.
所谓支持通配符的散列表, 就是把基本散列表中元素的关键字, 用去除通配符以后的字符作为关键字加入. 例如, 对于关键字 "www.ben.*", 这样带通配符的情况, 直接建立一个专用的后置通配符散列表, 存储元素的关键字为"www.ben". 这样, 如果要检索 www.ben.com 是否匹配 www.ben.* , 可以用Nginx提供的方法 ngx_hash_find_wc_tail检索, 此函数会把要查询的 www.ben.com 转化为 www.ben 字符串再开始查询.
同理, 对于关键字为 "*.ben.com"的元素, 也直接建立一个前置通配符的散列表, 存储元素的关键字为 "com.ben." , 如果要检索“smtp.ben.com”是否匹配 ".ben.com", 直接使用Nginx提供的 ngx_hash_find_wc_head方法查询. 该方法会把要查询的 "smtp.ben.com"转化为 "com.ben."再开始查询

散列表的结构体定义如下:

typedef struct {
    ngx_hash_t        hash;
    void             *value;
} ngx_hash_wildcard_t;
当使用此支持通配符的散列表作为某容器的元素时, 可以使用这个指针指向用户数据. (这个字段是用来存放某个已经达到末尾的通配符url对应的value值,如果通配符url没有达到末尾,这个字段为NULL.)
可以看到这个结构体只是简单的对基本散列表容器的封装.
下面说明一下Nginx对于server_name主机名通配符的支持规则:
        首先选择完全匹配的主机名. 比如"www.ben.com"就先在基本散列表中寻找"www.ben.com"是否存在
        如果没有找到, 然后选择通配符在前面的主机名. "*.ben.com"
        最后, 还没找到的话, 比如 "www.ben.*"

想要在一个搜索中对3个散列表进行寻找, Nginx提供了一个结构体:
typedef struct {
    ngx_hash_t            hash;
    ngx_hash_wildcard_t  *wc_head;
    ngx_hash_wildcard_t  *wc_tail;
} ngx_hash_combined_t;
这个结构体中就包含了三个散列表, 基本散列表, 通配符在头部的散列表, 通配符在最后的散列表.

这里再次提一下, 前置通配符散列表中元素的关键字, 在把*通配符去掉后, 会按照 "." 符号分隔, 并以倒序的方式作为关键字来存储元素.
在进行查询时, 待查询的关键字name也会以同样的方式被转化, 之后再做递归查询.
进行前置通配符或是后置通配符的查询时, 可以用上面提到的函数进行查询. 在对ngx_hash_combined_t结构体进行查找时, 使用ngx_hash_find_combined进行查找. 查找规则符合上面的顺序
也就是: ngx_hash_find ---> ngx_hash_find_wc_head ---> ngx_hash_find_wc_tail
    


初始化函数.
既然要使用到支持通配符的散列表, 那么先看其初始化函数.
传入的ngx_hash_key_t中关键字已经被处理过(注释会讲到)

ngx_int_t
ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
    ngx_uint_t nelts)
{
    size_t                len, dot_len;
    ngx_uint_t            i, n, dot;
    ngx_array_t           curr_names, next_names;
    ngx_hash_key_t       *name, *next_name;
    ngx_hash_init_t       h;
    ngx_hash_wildcard_t  *wdc;

     //初始化两个动态数组. 接下来会使用. 其中元素都是 ngx_hash_key_t类型的
    //curr_names就是会被最终传到ngx_hash_init的数组
    if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,
                       sizeof(ngx_hash_key_t))
        != NGX_OK)
     ...
    //next_names最终被传到ngx_hash_wildcard_init中去的数组
    if (ngx_array_init(&next_names, hinit->temp_pool, nelts,
                       sizeof(ngx_hash_key_t))
        != NGX_OK)
     ...

     //从整体看, 一个大循环. 目的是构造一个ngx_hash_key_t类型的数组, 传递给ngx_hash_init函数去构造一个哈希表.
     //从细节看, 这其中会递归调用ngx_hash_wildcard_init函数. 从而最终生成n级哈希表.
     //值得注意的是, 这个循环的使用的变量 n 不是递增的. 而是会随i而变化的. i也是一个循环的变量, 下面会看到
    for (n = 0; n < nelts; n = i) {

        dot = 0;
          //寻找第一个 ".", 这样目的是两个: 1. 看是否存在 ","    2. 找到构建这个散列表的所需关键字长度
        for (len = 0; len < names[n].key.len; len++) {
            if (names[n].key.data[len] == '.') {
                dot = 1;
                break;
            }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值