ImageVerifierCode 换一换
格式:DOC , 页数:9 ,大小:159KB ,
资源ID:7231692      下载积分:10 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/7231692.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(Apache中过滤器实现机制分析.doc)为本站上传会员【xrp****65】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

Apache中过滤器实现机制分析.doc

1、Apache中过滤器实现机制的分析 内容提要 Apache中的过滤器形成了链表结构,当响应请求输出的时候,请求将依次流经整个过滤器链,直到到达最后一个过滤器,直接将其发送到网络中去。 在过滤器的最顶端,代码生成客户端请求的内容,通常称之为“内容生成器”,内容生成器产生的内容使用Apache的标准输入机制ap_rputs(),ap_rprintf()或者ap_rwrite()输入过滤器顶端。每一个过滤器都被定义为一个回调,该回调从前一个过滤器接受输出(如果是第一个过滤器的话,没有前一个过滤器,那么此时从内容生成器中接受输入),对其进行操作,同时将处理结果传递给下链表中的下一个过滤器。传递可

2、以使用ap_fc_*函数,比如ap_fc_puts(),ap_fc_printf()以及ap_fc_write()等等。 当内容生成器生成内容之后,Apache系统将传递一个“结束流”标记给过滤器链表,过滤器将使用这个“结束流”来刷新所有的内部状态以及决定那些不完整的语法。 过滤器函数 过滤器函数通常用于执行回调,它将传递一个指针给对应的过滤器以及一个存储段,其中包含需要过滤得内容。在过滤器的ctx中,回调将查找它的上下文,上下文就是通过ctx提供。过滤器可能安装很多次,每次都接受自己的安装上下文指针。回调总是与过滤器关联在一起的,通常通过指定的名字描述。在ap_register_i

3、nput_filter()和ap_register_output_filter()中会将指定的关联函数与指定的过滤器关联在一起。 如果传递给注册函数的初始化参数不为NULL, 在Apache1.3版本,当Apache为特定请求生成内容,返回客户之前, frec是Apache过滤器结点,其是ap_filter_rec_t结构,该结构用来定义一个Apache过滤器,其定义如下: struct ap_filter_rec_t { const char *name; ap_filter_func filter_func; ap_init_filter_fun

4、c filter_init_func; ap_filter_type ftype; struct ap_filter_rec_t *next; }; 该结构定义了作为一个过滤器必须具备的各个特性。name是过滤器的名称;filter_func是过滤器对应的函数,当过滤器被激活的时候,其将调用该函数对请求进行过滤处理。filter_init_func用于在过滤处理句柄被激活之前调用。需要注意的是,该过滤器仅能用于HTTP协议。其余协议的初始化由协议本身实现。 yype则是过滤器的类型。next则是指向下一个过滤器结构。 ctx通常用来保存过滤器frec可能需要的额外

5、的信息,由于需要的信息的千差万别,因此只能将其类型定义为void,待真正需要的时候再做强制转换。 Apache的各个过滤器之间通过next形成链表结构。 R则是与当前过滤器关联的请求信息。C则是与当前过滤器关联的连接信息。 ////////////////////////////////////////////////////////////////////////////////////////////////////// Apache中对过滤器的保存是根据过滤器名称进行的,保存结果形成一棵过滤树。由于过滤器分为输入过滤器和输出过滤器两种,因此最终结果将用两棵过滤树保存

6、这两颗树的树根在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中

7、对子结点的分配总是以4为单位进行的,不过即使一次分配了四个单元,但也不一定所有的单元都被使用,其中有一些空闲的单元。因此nchildren用来记录当前结点的子结点中所有的已经被使用的结点的个数,而size则用来记录实际分配的结点的个数,其值总是大于或者等于nchildren。size-nchildren则就是子结点中尚未使用的结点的个数。 现在我们来看一下Apache中是如何进行过滤器注册的,由于过滤器的注册的唯一根据就是过滤器名称,因此我们假设存在下面四个过滤器,其名称以及对应的过滤器执行函数分别如下: 输出过滤器名称 输出过滤器执行函数 face face_func() fac

8、d 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过滤器是第一个过滤器,因此此前register

9、ed_output_filters系统初始化为NULL。在register_filter函数内部,函数首先判断register_ouput_filters是否为NULL,如果为NULL,那么其将调用trie_node_alloc函数为其分配空间,该函数完成的事情很简单: (1) 如果分配空间的该结点没有父结点,比如此时的register_output_filters,其是所有结点的祖先,没有父结点, 一次性为filter_trie_node中的children分配四个单元,因此对于register_output_filters,调用trie_node_alloc后的结果将如下图所示:

10、register_output_filters调用filter_trie_node后的图示 分配之后register_output_filters的size为4,而nchildren则0。 一旦分配了register_output_filters所需要的空间之后,就可以将face过滤器挂结到其下面。挂结不是一次性完成的,其包括多个步骤。register_filters函数首先将过滤器的名称全部变为小写进行处理,并对名称中的每一个字母都进行类似处理register_output_filters的过程。对于face,函数首先处理字母“f”。对于f字母,函数也首先调用trie_node_al

11、loc分配其需要的空间,调用形式如下: filter_trie_node* child=filter_node_alloc(FILTER_POOL,node,*n); 与分配registered_output_filters时候调用filter_node_alloc(FILTER_POOL,NULL,0)不同的是此处指定的新分配的结点必须挂结到结点node即register_output_filters下面。 因此实际上,trie_node_alloc内部不仅仅提供内存分配的过程,还提供了层次挂结的过程,除了前面的(1),trie_node_alloc还包括两个重要的功能: (

12、2) 如果需要分配的结点必须挂结到指定的父结点之下,其首先在该父结点的所有孩子中查找是否已经存在该结点。查找过程如下所示: for (i = 0; i < parent->nchildren; i++) { if (c == parent->children[i].c) { return parent->children[i].child; } else if (c < parent->children[i].c) { break; } } 比如对于“f”函数在父结点register_output_filters的所有子结点中查找时候已经存在,如果存在则直接返回该结点;事实上

13、目前register_output_filters中并不存在,因此函数将分配filter_trie_node空间(包括四个子结点空间的分配)并调用trie_node_link进行父子挂结。挂结的具体过程我们在后面描述。一旦进行挂结,则挂结后的示意图如下所示: 一旦将child挂结到根结点下面,那么根结点nchildren变为1,表示已经有一个单元被占用。一旦对字母“f”的处理完毕,当前处理结点node将从根结点register_output_filters移动到child中,此时,你可以从下图中看出。 注册函数在处理完字母“f”后其将继续处理“a”。对a以及后面的“c”和“e”与对

14、f的处理几乎完全相同,处理时候首先在当前的父结点node中查找是否存在同样的结点,如果存在则直接返回,否则生成新的结点,同时进行挂结。 至此函数完成了对挂钩“face”的注册,实际的真正的挂钩数据保存在“e”结点的frec结构中。 现在我们继续看看函数对挂钩“fb”的注册过程。函数首先处理字母“f”,它将首先查找根结点中是否存在“f”结点。事实上此时确实存在,因此函数只是简单的返回f指向的结点,同时将当前结点node指向f结点。函数继续处理b结点,其父亲为node,即f指向的结点。函数在node的children数组中查找b结点,结果没有查找到,则生成一个带有四个空闲单元的结点,并将其

15、挂结到node中合适的位置,同时对b结点进行初始化。当face和fb挂钩都注册之后,这个结点树结构如下所示。 对于其余的结点facd和food的注册过程完全类似,一旦所有的挂钩注册完毕,整个过滤器树如图所示。 到所有的挂钩注册完毕,所有的挂钩形成了一个典型的挂钩树,如果上面的图我们还不能清楚的看出来的话,我们可以用下图表示: ////////////////////////////////////////////////////////////////////////////////////////////////////// 过滤器的查找 Apache中对过滤器

16、的查找也是通过名称来进行的。过滤器的查找主要是通过函数ap_get_output_filter_handle进行的,该函数的内部主要调用的则是静态函数get_filter_handle,其调用原型如下: get_filter_handle(name, registered_output_filters); name则是需要查找的过滤器的名称,registered_output_filters则是过滤树的根结点。一旦查找到name名称的过滤器,该函数将返回该过滤器的结构filter_rec_t;否则返回NULL。 get_filter_handle函数的内部的查找机制与注册过滤器非

17、常类似。在查找过程中,Apache必须维护三个结点指针,一个指向所有的过滤器树的根结点,一个指向当前结点,还有一个指向当前结点的子结点。比如如果需要查找过滤器树中是否存在“face”过滤器,其从首先在根结点register_output_filters的所有子结点中查找是否存在f结点。如果查找到,则将当前结点置为f结点,并继续在当前结点即f结点的所有子结点中查找是否存在“a”结点,如果找到继续将a结点作为当前结点,并在“a”的所有子结点中查找是否存在“c”结点。如此类退,直到找到满足要求的结点,并返回它的过滤器。 有一点需要注意的是,为了加快对当前结点的所有子结点的查找速度,在查找过程中,

18、函数使用了二分法进行查找,二分法的使用能够有效的改善查找速度。 ////////////////////////////////////////////////////////////////////////////////////////////////////// 过滤器的添加 在Apache中,过滤器可以分为三种大的类型:独立过滤器、与请求关联过滤器以及与连接关联过滤器。事实上在查看请求记录结构request_rec的时候,会发现下面的代码: struct request_rec{ …… struct ap_filter_t *output_fil

19、ters; struct ap_filter_t *input_filters; struct ap_filter_t *proto_output_filters; struct ap_filter_t *proto_input_filters; …… } 同时在连接记录结构conn_rec中,我们也会看到下面的代码: struct conn_rec{ …… struct ap_filter_t *input_filters; struct ap_filter_t *output_filters; …… } 在Apache2.0中为了

20、兼容HTTP1.1标准,服务器在建立连接的时候,在该连接上可能传送多个请求,因此对于请求过滤器而言其只对该针对该请求进行过滤;而如果是连接过滤器的话,其将对该连接中的所有的请求都进行过滤。我们可以用下面的示意图进行描述: 图示:请求过滤器 图示:连接过滤器 请求过滤器和处理过滤器都必须与给定的请求和连接进行关联,如果过滤器没有与任何的请求和连接进行关联,则我们称之为独立过滤器。 对于非独立过滤器,为了能够将它与给定的请求或者连接进行关联,我们必须调用ap_add_input_filter或者ap_add_output_filter。我们仅仅来了解ap_add_input_f

21、ilter函数, ap_add_output_filter函数与之几乎完全相同,我们不再赘述。 ap_add_input_filter函数原型如下所示: AP_DECLARE(ap_filter_t *) ap_add_input_filter(const char *name, void *ctx, request_rec *r, conn_rec *c) 函数参数中,name则是给定的过滤器的名称,ctx则是传递给过滤器执行函数可能需要的额外参数,通常是一个struct结构,不过由于s

22、truct结构内部我们无法知道,因此我们只能通过void进行强制转换。r则是过滤器需要关联的请求结构;c则是过滤器需要进行关联的连接结构。 在进一步分析之前,我们首先来看一下Apache中是如何组织给定的请求或者连接中的过滤器的。Apache中使用ap_filter _t链表结构进行保存,ap_filter_t的定义如下: struct ap_filter_t { ap_filter_rec_t *frec; void *ctx; ap_filter_t *next; request_rec *r; conn_rec

23、 *c; }; 每一个连接或者请求占用一个ap_filter_t结构,不同请求之间相互通过next形成一个链表;而对于每个连接或者请求而言,与其关联的所有的过滤器都保存在frec中,过滤器之间也相互形成链表。因此整个结构可以用下面的图示形容: 当然apache中对于ap_filter_t结构的组织并不是随意的,无序的。为了能够更好的组织Apache中的各种过滤器,系统将其分为五种类型:AP_FTYPE_RESOURCE、AP_FTYPE_CONTENT_SET、AP_FTYPE_PROTOCOL、AP_FTYPE_TRANSCODE、AP_FTYPE_CONNECTION、AP_

24、FTYPE_NETWORK。这些类型定义在枚举结构ap_filter_type中。 对于AP_FTYPE_RESOURCE类型的过滤器,其通常用于修改传递给该过滤器的内容,比如SSI或者PHP过滤器就是这种类型。 AP_FTYPE_CONTENT_SET过滤器则主要用来将文档的正文作为整体进行修改,通常在AP_FTYPE_RESOURCE过滤器使用之后才被使用。这种过滤器只修改文档的正文,并不修改文档的类型等信息。典型的就是deflat过滤器,其只对文档正文进行压缩和解压。 AP_FTYPE_PROTOCOL过滤器则仅仅处理服务器和客户机之间的协议,比如HTTP和POP协议过滤器就是

25、这种类型。 AP_FTYPE_TRANSCODE过滤器则仅仅修改传输编码。 AP_FTYPE_CONNECTION是Apache中最经常也是最重要的过滤器之一。该过滤器将会修改文档的正文部分,不过该过滤器更多的是必须与连接进行关联,这真是我们通常称之为连接过滤器的原因。最简单的例子,我们通常需要将一个HTTP连接分裂成为多个请求或者在返回客户端之前将多个请求的返回内容用一个HTTP连接进行返回。不过有一点需要保证的是,这些种类的过滤器不能针对子请求进行过滤。 最后一种过滤器类型则是AP_FTYPE_NETWORK,该请求并不修改任何内容,它们的责任仅仅是将从客户端接受数据送入过滤器队列中

26、或者将过滤后的最终内容返回给客户端而已。 每个过滤器Apache都安排赋以一个整数,从10到60。如果过滤器的类型<30,即AP_FTYPE_PROTOCOL,则认为该过滤器是正文过滤器;如果过滤器的类型介于AP_FTYPE_PROTOCOL和AP_FTYPE_CONNECTION,则称之为协议过滤器;其余的所有的过滤器都称之为连接过滤器。 Apache中对于过滤器的组织的主要依据真是过滤器的类型。 因此如果我们需要将一个过滤器添加到指定的请求或者连接上。 数据传递 当一个过滤器处理完相应的数据之后,它就必须将该数据传递给下一个过滤器继续进行处理。Apache中使用函数ap_pass_brigade在不同的过滤器之间传递缓冲区。函数的原型定义如下: AP_DECLARE(apr_status_t) ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket); 其中,filter是传递的下一个过滤器,对于当前过滤器而言,下一个过滤器就是filter->next.bucket则是需要传递的存储段组。

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服