Apache HTTP Server 版本 2.4
可用语言: en
这是一封电子邮件 (<022501c1c529$f63a9550$7f00000a@KOJ>) 的剪切粘贴内容,仅为了更好的可读性而重新格式化。它不是最新的,但可能是进一步研究的良好起点。
有三种基本的过滤器类型(实际上,每种类型都细分为两个类别,但这将在后面讨论)。
连接
AP_FTYPE_CONNECTION
,AP_FTYPE_NETWORK
)协议
AP_FTYPE_PROTOCOL
,AP_FTYPE_TRANSCODE
)资源
PROTOCOL
相同,但内部重定向和子请求可以在不结束请求的情况下更改内容。(AP_FTYPE_RESOURCE
,AP_FTYPE_CONTENT_SET
)区分协议过滤器和资源过滤器非常重要。资源过滤器与特定资源绑定,它也可能与标头信息绑定,但主要绑定是与资源。如果你正在编写过滤器,并且想知道它是资源过滤器还是协议过滤器,正确的提问方式是:“如果请求重定向到不同的资源,是否可以删除此过滤器?”如果答案是肯定的,那么它就是资源过滤器。如果答案是否定的,那么它很可能是一个协议过滤器或连接过滤器。我不会讨论连接过滤器,因为它们似乎已经被很好地理解了。根据这个定义,一些例子可能会有所帮助
对每个类别进行进一步细分以获得另外两种过滤器类型,纯粹是为了排序。我们可以删除它,只允许一种过滤器类型,但顺序往往会出错,我们需要进行一些修改才能使其正常工作。目前,RESOURCE
过滤器只有一种过滤器类型,但这应该会改变。
从理论上讲,这实际上很简单,但代码很复杂。首先,重要的是每个人都要意识到每个请求都有三个过滤器列表,但它们都是连接在一起的
r->output_filters
(对应于 RESOURCE)r->proto_output_filters
(对应于 PROTOCOL)r->connection->output_filters
(对应于 CONNECTION)之前的问题是,我们使用单链表来创建过滤器堆栈,并且我们从“正确”的位置开始。这意味着,如果我在堆栈上有一个RESOURCE
过滤器,并且我添加了一个CONNECTION
过滤器,那么CONNECTION
过滤器将被忽略。这应该是有道理的,因为我们会在c->output_filters
列表的顶部插入连接过滤器,但r->output_filters
的末尾指向曾经位于c->output_filters
前面的过滤器。这显然是错误的。新的插入代码使用双链表。这具有我们永远不会丢失已插入过滤器的优点。不幸的是,它也带来了一系列不同的问题。
问题是我们有两个不同的情况,我们使用子请求。第一个是将更多数据插入响应。第二个是用内部重定向替换现有响应。这两个是不同的情况,需要分别对待。
在第一种情况下,我们是在处理程序或过滤器中创建子请求。这意味着下一个过滤器应该传递给make_sub_request
函数,并且子请求中的最后一个资源过滤器将指向主请求中的下一个过滤器。这是有道理的,因为子请求的数据需要通过与主请求相同的过滤器集。图形表示可能会有所帮助
Default_handler --> includes_filter --> byterange --> ...
如果 includes 过滤器创建子请求,那么我们不希望来自该子请求的数据通过 includes 过滤器,因为它可能不是 SSI 数据。因此,子请求添加以下内容
Default_handler --> includes_filter -/-> byterange --> ... / Default_handler --> sub_request_core
如果子请求是 SSI 数据会发生什么?这很简单,includes_filter
是一个资源过滤器,因此它将在Default_handler
和sub_request_core
过滤器之间添加到子请求中。
子请求的第二种情况是,当一个子请求将成为真正的请求时。每当在处理程序或过滤器之外创建子请求,并且将 NULL 作为下一个过滤器传递给make_sub_request
函数时,就会发生这种情况。
在这种情况下,资源过滤器对新请求不再有意义,因为资源已更改。因此,我们不是从头开始,而是简单地将子请求的资源过滤器的开头指向旧请求的协议过滤器的开头。这意味着我们不会丢失任何协议过滤器,也不会尝试通过不应该看到它的过滤器发送此数据。
问题是我们现在正在使用双链表作为我们的过滤器堆栈。但是,你应该注意到,在这个模型中,两个列表可能相交。那么,你如何处理上一个指针?这是一个非常难以回答的问题,因为没有“正确”的答案,两种方法都同样有效。我查看了我们使用上一个指针的原因。唯一的原因是允许更轻松地添加新服务器。话虽如此,我选择的解决方案是让上一个指针始终停留在原始请求上。
这会导致一些更复杂的逻辑,但它适用于所有情况。我担心将其移动到子请求,是因为对于更常见的情况(其中子请求用于将数据添加到响应),主过滤器链将是错误的。在我看来,这似乎不是一个好主意。
绝对最后一点是,这段代码之所以如此难以正确编写,是因为我们进行了太多修改来强迫它工作。我最初编写了大部分修改,因此我负有很大责任。但是,现在代码已经正确了,我开始删除一些修改。大多数人应该已经看到reset_filters
和add_required_filters
函数消失了。这些函数为错误条件插入了协议级过滤器,实际上,这两个函数都做了同样的事情,一个接一个,这真的很奇怪。因为我们不再为错误情况丢失协议过滤器,所以这些修改消失了。HTTP_HEADER
、Content-length
和Byterange
过滤器都在insert_filters
阶段添加,因为如果它们早些添加,我们就会有一些有趣的交互。现在,它们都可以移动到与HTTP_IN
、CORE
和CORE_IN
过滤器一起插入。这将使代码更容易理解。
可用语言: en