1<?xml version="1.0" encoding="ISO-8859-1"?> 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 3<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head><!-- 4 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5 This file is generated from xml source: DO NOT EDIT 6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 7 --> 8<title>How filters work in Apache 2.0 - Apache HTTP Server</title> 9<link href="/style/css/manual.css" rel="stylesheet" media="all" type="text/css" title="Main stylesheet" /> 10<link href="/style/css/manual-loose-100pc.css" rel="alternate stylesheet" media="all" type="text/css" title="No Sidebar - Default font size" /> 11<link href="/style/css/manual-print.css" rel="stylesheet" media="print" type="text/css" /><link rel="stylesheet" type="text/css" href="/style/css/prettify.css" /> 12<script src="/style/scripts/prettify.min.js" type="text/javascript"> 13</script> 14 15<link href="/images/favicon.ico" rel="shortcut icon" /></head> 16<body id="manual-page"><div id="page-header"> 17<p class="menu"><a href="/mod/">Modules</a> | <a href="/mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="/glossary.html">Glossary</a> | <a href="/sitemap.html">Sitemap</a></p> 18<p class="apache">Apache HTTP Server Version 2.4</p> 19<img alt="" src="/images/feather.gif" /></div> 20<div class="up"><a href="./"><img title="<-" alt="<-" src="/images/left.gif" /></a></div> 21<div id="path"> 22<a href="http://www.apache.org/">Apache</a> > <a href="http://httpd.apache.org/">HTTP Server</a> > <a href="http://httpd.apache.org/docs/">Documentation</a> > <a href="../">Version 2.4</a> > <a href="./">Developer Documentation</a></div><div id="page-content"><div id="preamble"><h1>How filters work in Apache 2.0</h1> 23<div class="toplang"> 24<p><span>Available Languages: </span><a href="/en/developer/filters.html" title="English"> en </a></p> 25</div> 26 27 <div class="warning"><h3>Warning</h3> 28 <p>This is a cut 'n paste job from an email 29 (<022501c1c529$f63a9550$7f00000a@KOJ>) and only reformatted for 30 better readability. It's not up to date but may be a good start for 31 further research.</p> 32 </div> 33</div> 34<div id="quickview"><ul id="toc"><li><img alt="" src="/images/down.gif" /> <a href="#types">Filter Types</a></li> 35<li><img alt="" src="/images/down.gif" /> <a href="#howinserted">How are filters inserted?</a></li> 36<li><img alt="" src="/images/down.gif" /> <a href="#asis">Asis</a></li> 37<li><img alt="" src="/images/down.gif" /> <a href="#conclusion">Explanations</a></li> 38</ul><ul class="seealso"><li><a href="#comments_section">Comments</a></li></ul></div> 39<div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 40<div class="section"> 41<h2><a name="types" id="types">Filter Types</a></h2> 42 <p>There are three basic filter types (each of these is actually broken 43 down into two categories, but that comes later).</p> 44 45 <dl> 46 <dt><code>CONNECTION</code></dt> 47 <dd>Filters of this type are valid for the lifetime of this connection. 48 (<code>AP_FTYPE_CONNECTION</code>, <code>AP_FTYPE_NETWORK</code>)</dd> 49 50 <dt><code>PROTOCOL</code></dt> 51 <dd>Filters of this type are valid for the lifetime of this request from 52 the point of view of the client, this means that the request is valid 53 from the time that the request is sent until the time that the response 54 is received. (<code>AP_FTYPE_PROTOCOL</code>, 55 <code>AP_FTYPE_TRANSCODE</code>)</dd> 56 57 <dt><code>RESOURCE</code></dt> 58 <dd>Filters of this type are valid for the time that this content is used 59 to satisfy a request. For simple requests, this is identical to 60 <code>PROTOCOL</code>, but internal redirects and sub-requests can change 61 the content without ending the request. (<code>AP_FTYPE_RESOURCE</code>, 62 <code>AP_FTYPE_CONTENT_SET</code>)</dd> 63 </dl> 64 65 <p>It is important to make the distinction between a protocol and a 66 resource filter. A resource filter is tied to a specific resource, it 67 may also be tied to header information, but the main binding is to a 68 resource. If you are writing a filter and you want to know if it is 69 resource or protocol, the correct question to ask is: "Can this filter 70 be removed if the request is redirected to a different resource?" If 71 the answer is yes, then it is a resource filter. If it is no, then it 72 is most likely a protocol or connection filter. I won't go into 73 connection filters, because they seem to be well understood. With this 74 definition, a few examples might help:</p> 75 76 <dl> 77 <dt>Byterange</dt> 78 <dd>We have coded it to be inserted for all requests, and it is removed 79 if not used. Because this filter is active at the beginning of all 80 requests, it can not be removed if it is redirected, so this is a 81 protocol filter.</dd> 82 83 <dt>http_header</dt> 84 <dd>This filter actually writes the headers to the network. This is 85 obviously a required filter (except in the asis case which is special 86 and will be dealt with below) and so it is a protocol filter.</dd> 87 88 <dt>Deflate</dt> 89 <dd>The administrator configures this filter based on which file has been 90 requested. If we do an internal redirect from an autoindex page to an 91 index.html page, the deflate filter may be added or removed based on 92 config, so this is a resource filter.</dd> 93 </dl> 94 95 <p>The further breakdown of each category into two more filter types is 96 strictly for ordering. We could remove it, and only allow for one 97 filter type, but the order would tend to be wrong, and we would need to 98 hack things to make it work. Currently, the <code>RESOURCE</code> filters 99 only have one filter type, but that should change.</p> 100</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 101<div class="section"> 102<h2><a name="howinserted" id="howinserted">How are filters inserted?</a></h2> 103 <p>This is actually rather simple in theory, but the code is 104 complex. First of all, it is important that everybody realize that 105 there are three filter lists for each request, but they are all 106 concatenated together. So, the first list is 107 <code>r->output_filters</code>, then <code>r->proto_output_filters</code>, 108 and finally <code>r->connection->output_filters</code>. These correspond 109 to the <code>RESOURCE</code>, <code>PROTOCOL</code>, and 110 <code>CONNECTION</code> filters respectively. The problem previously, was 111 that we used a singly linked list to create the filter stack, and we 112 started from the "correct" location. This means that if I had a 113 <code>RESOURCE</code> filter on the stack, and I added a 114 <code>CONNECTION</code> filter, the <code>CONNECTION</code> filter would 115 be ignored. This should make sense, because we would insert the connection 116 filter at the top of the <code>c->output_filters</code> list, but the end 117 of <code>r->output_filters</code> pointed to the filter that used to be 118 at the front of <code>c->output_filters</code>. This is obviously wrong. 119 The new insertion code uses a doubly linked list. This has the advantage 120 that we never lose a filter that has been inserted. Unfortunately, it comes 121 with a separate set of headaches.</p> 122 123 <p>The problem is that we have two different cases were we use subrequests. 124 The first is to insert more data into a response. The second is to 125 replace the existing response with an internal redirect. These are two 126 different cases and need to be treated as such.</p> 127 128 <p>In the first case, we are creating the subrequest from within a handler 129 or filter. This means that the next filter should be passed to 130 <code>make_sub_request</code> function, and the last resource filter in the 131 sub-request will point to the next filter in the main request. This 132 makes sense, because the sub-request's data needs to flow through the 133 same set of filters as the main request. A graphical representation 134 might help:</p> 135 136<div class="example"><pre>Default_handler --> includes_filter --> byterange --> ...</pre></div> 137 138 <p>If the includes filter creates a sub request, then we don't want the 139 data from that sub-request to go through the includes filter, because it 140 might not be SSI data. So, the subrequest adds the following:</p> 141 142<div class="example"><pre>Default_handler --> includes_filter -/-> byterange --> ... 143 / 144Default_handler --> sub_request_core</pre></div> 145 146 <p>What happens if the subrequest is SSI data? Well, that's easy, the 147 <code>includes_filter</code> is a resource filter, so it will be added to 148 the sub request in between the <code>Default_handler</code> and the 149 <code>sub_request_core</code> filter.</p> 150 151 <p>The second case for sub-requests is when one sub-request is going to 152 become the real request. This happens whenever a sub-request is created 153 outside of a handler or filter, and NULL is passed as the next filter to 154 the <code>make_sub_request</code> function.</p> 155 156 <p>In this case, the resource filters no longer make sense for the new 157 request, because the resource has changed. So, instead of starting from 158 scratch, we simply point the front of the resource filters for the 159 sub-request to the front of the protocol filters for the old request. 160 This means that we won't lose any of the protocol filters, neither will 161 we try to send this data through a filter that shouldn't see it.</p> 162 163 <p>The problem is that we are using a doubly-linked list for our filter 164 stacks now. But, you should notice that it is possible for two lists to 165 intersect in this model. So, you do you handle the previous pointer? 166 This is a very difficult question to answer, because there is no "right" 167 answer, either method is equally valid. I looked at why we use the 168 previous pointer. The only reason for it is to allow for easier 169 addition of new servers. With that being said, the solution I chose was 170 to make the previous pointer always stay on the original request.</p> 171 172 <p>This causes some more complex logic, but it works for all cases. My 173 concern in having it move to the sub-request, is that for the more 174 common case (where a sub-request is used to add data to a response), the 175 main filter chain would be wrong. That didn't seem like a good idea to 176 me.</p> 177</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 178<div class="section"> 179<h2><a name="asis" id="asis">Asis</a></h2> 180 <p>The final topic. :-) Mod_Asis is a bit of a hack, but the 181 handler needs to remove all filters except for connection filters, and 182 send the data. If you are using <code class="module"><a href="/mod/mod_asis.html">mod_asis</a></code>, all other 183 bets are off.</p> 184</div><div class="top"><a href="#page-header"><img alt="top" src="/images/up.gif" /></a></div> 185<div class="section"> 186<h2><a name="conclusion" id="conclusion">Explanations</a></h2> 187 <p>The absolutely last point is that the reason this code was so hard to 188 get right, was because we had hacked so much to force it to work. I 189 wrote most of the hacks originally, so I am very much to blame. 190 However, now that the code is right, I have started to remove some 191 hacks. Most people should have seen that the <code>reset_filters</code> 192 and <code>add_required_filters</code> functions are gone. Those inserted 193 protocol level filters for error conditions, in fact, both functions did 194 the same thing, one after the other, it was really strange. Because we 195 don't lose protocol filters for error cases any more, those hacks went away. 196 The <code>HTTP_HEADER</code>, <code>Content-length</code>, and 197 <code>Byterange</code> filters are all added in the 198 <code>insert_filters</code> phase, because if they were added earlier, we 199 had some interesting interactions. Now, those could all be moved to be 200 inserted with the <code>HTTP_IN</code>, <code>CORE</code>, and 201 <code>CORE_IN</code> filters. That would make the code easier to 202 follow.</p> 203</div></div> 204<div class="bottomlang"> 205<p><span>Available Languages: </span><a href="/en/developer/filters.html" title="English"> en </a></p> 206</div><div class="top"><a href="#page-header"><img src="/images/up.gif" alt="top" /></a></div><div class="section"><h2><a id="comments_section" name="comments_section">Comments</a></h2><div class="warning"><strong>Notice:</strong><br />This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed again by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Freenode, or sent to our <a href="http://httpd.apache.org/lists.html">mailing lists</a>.</div> 207<script type="text/javascript"><!--//--><![CDATA[//><!-- 208var comments_shortname = 'httpd'; 209var comments_identifier = 'http://httpd.apache.org/docs/2.4/developer/filters.html'; 210(function(w, d) { 211 if (w.location.hostname.toLowerCase() == "httpd.apache.org") { 212 d.write('<div id="comments_thread"><\/div>'); 213 var s = d.createElement('script'); 214 s.type = 'text/javascript'; 215 s.async = true; 216 s.src = 'https://comments.apache.org/show_comments.lua?site=' + comments_shortname + '&page=' + comments_identifier; 217 (d.getElementsByTagName('head')[0] || d.getElementsByTagName('body')[0]).appendChild(s); 218 } 219 else { 220 d.write('<div id="comments_thread">Comments are disabled for this page at the moment.<\/div>'); 221 } 222})(window, document); 223//--><!]]></script></div><div id="footer"> 224<p class="apache">Copyright 2014 The Apache Software Foundation.<br />Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.</p> 225<p class="menu"><a href="/mod/">Modules</a> | <a href="/mod/directives.html">Directives</a> | <a href="http://wiki.apache.org/httpd/FAQ">FAQ</a> | <a href="/glossary.html">Glossary</a> | <a href="/sitemap.html">Sitemap</a></p></div><script type="text/javascript"><!--//--><![CDATA[//><!-- 226if (typeof(prettyPrint) !== 'undefined') { 227 prettyPrint(); 228} 229//--><!]]></script> 230</body></html>