Apache中过滤器实现机制分析.doc
文本预览下载声明
Apache中实现机制的分析struct ap_filter_rec_t {
const char *name;
ap_filter_func filter_func;
ap_init_filter_func filter_init_func;
ap_filter_type ftype;
struct ap_filter_rec_t *next;
};
该结构定义了作为一个过滤器必须具备的各个特性。name是过滤器的名称;filter_func是过滤器对应的函数,当过滤器被激活的时候,其将调用该函数对请求进行过滤处理。filter_init_func用于在过滤处理句柄被激活之前调用。需要注意的是,该过滤器仅能用于HTTP协议。其余协议的初始化由协议本身实现。
yype则是过滤器的类型。next则是指向下一个过滤器结构。
ctx通常用来保存过滤器frec可能需要的额外的信息,由于需要的信息的千差万别,因此只能将其类型定义为void,待真正需要的时候再做强制转换。
Apache的各个过滤器之间通过next形成链表结构。
R则是与当前过滤器关联的请求信息。C则是与当前过滤器关联的连接信息。
//////////////////////////////////////////////////////////////////////////////////////////////////////
Apache中对过滤器的保存是根据过滤器名称进行的,保存结果形成一棵过滤树。由于过滤器分为输入过滤器和输出过滤器两种,因此最终结果将用两棵过滤树保存。这两颗树的树根在Apache中分别用registered_input_filters和registered_output_filters表示。它们是全局变量,类型为filter_trie_node结构,其定义如下:
struct filter_trie_node {
ap_filter_rec_t *frec;
filter_trie_child_ptr *children;
int nchildren;
int size;
};
frec是该结点中实际保存的过滤器结构;children用来记录该结点的所有子结点,Apache中对子结点的分配总是以4为单位进行的,不过即使一次分配了四个单元,但也不一定所有的单元都被使用,其中有一些空闲的单元。因此nchildren用来记录当前结点的子结点中所有的已经被使用的结点的个数,而size则用来记录实际分配的结点的个数,其值总是大于或者等于nchildren。size-nchildren则就是子结点中尚未使用的结点的个数。
现在我们来看一下Apache中是如何进行过滤器注册的,由于过滤器的注册的唯一根据就是过滤器名称,因此我们假设存在下面四个过滤器,其名称以及对应的过滤器执行函数分别如下:
输出过滤器名称 输出过滤器执行函数 face face_func() facd facd_func() fb fb_func() food food_func() 首先我们来看一下“face”过滤器的注册过程。
在Apache中过滤器的注册是通过函数ap_regieste_input_filter和ap_register_output_filter两个函数进行的。它们的实现几乎完成一样,在内部都是调用register_filter函数,只不过输入过滤器是挂结到registered_input_filters树下面,而输出过滤器则是挂结到registered_output_filters树下。
由于face过滤器是第一个过滤器,因此此前registered_output_filters系统初始化为NULL。在register_filter函数内部,函数首先判断register_ouput_filters是否为NULL,如果为NULL,那么其将调用trie_node_alloc函数为其分配空间,该函数完成的事情很简单:
如果分配空间的该结点没有父结点,比如此时的register_output_filters,其是所有结点的祖先,没有父结点, 一次性为filter_trie_node中的children分配四个单元,因此对于register_output_filters,调用trie_node_alloc后的结果将如下图所示:
register_output_filters调用filter_trie_node后的图示
分配之后register_output_filters的size为4,而nchildren则0。
一旦分配了register_output_fi
显示全部