<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AskApache &#187; Search Results  &#187;  etags</title>
	<atom:link href="http://www.askapache.com/search/etags/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.askapache.com</link>
	<description>Advanced Web Development</description>
	<lastBuildDate>Sun, 29 Jan 2012 12:04:08 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Optimize a Website for Speed, Security, and Easy Management</title>
		<link>http://www.askapache.com/hosting/optimize-website-files-cache-security.html</link>
		<comments>http://www.askapache.com/hosting/optimize-website-files-cache-security.html#comments</comments>
		<pubDate>Fri, 19 Feb 2010 01:45:26 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Hosting]]></category>

		<guid isPermaLink="false">http://www.askapache.com/?p=1380</guid>
		<description><![CDATA[<p><a href="http://www.askapache.com/htaccess/optimize-website-files-cache-security.html" class="IFL hs hs37" title="Discover how to setup and manage a website from top to bottom for optimized speed, security, and simplicity"></a>Learn how to setup, configure, secure, optimize, and create a low-maintenance website the AskApache way.  I'm piecing together all the hacks, tricks, methods, and ideas discussed throughout this blog and all across Netdom and glueing them all together to show you how to have the most optimized, crazy fastest, and best website setup I can think of.<br class="C" /></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/hosting/optimize-website-files-cache-security.html"></a><a href="http://www.askapache.com/hosting/optimize-website-files-cache-security.html"><cite>AskApache.com</cite></a></p><p><img class="IFL" src="http://uploads.askapache.com/2008/09/computerimg.jpg" alt="optimized server setup" title="optimized server setup" />Over the past 10 or so years I've been directly or indirectly involved in configuring/administrating/hacking thousands of websites, and I realized today that I've actually learned quite a bit about how to really make them work hard for me, instead of the other way around. It came as a mild shock to think of where I was back then vs. now because the improvements and optimizations are hundreds of smaller improvements, but taken together, the  optimization hacks I've found through trial and error and much reading are as Donald would say, <strong>YOOUUGE</strong> compared to a basic website setup.<br class="C" /></p>

<p class="cnote">I use this awesome skeleton setup for all my high-paying clients <em>sorry poor people!</em> and also of course on this blog, which I use as a bleeding-edge dev server for my crazy testing.  So realize that I'm already past this setup and using it to do cooler stuff.  In order for you to use these more advanced ideas, you first need to get up to speed on what I'm doing so you know what I'm talking about.  This article tries to help you accomplish that... remains to be seen.</p>


<h2>An Optimized Website, The Real Deal</h2>
<p>This first article is to give you some ideas and get you thinking and reading before the first article in this series comes out.  This series details how to setup, configure, secure, optimize, and manage a website the best possible way I can come up with.  It pieces together all the AskApache hacks and tricks and uses methods and ideas discussed all over this blog and all over the net and glues them all together to show you how to have the most optimized, fastest, best website setup I can think of.</p>
<p>Knowing the why and how behind the operation of a Web Server allows us to optimize that operation.  For this example we will be creating the website <code>www.askapache.com</code>, which will be running WordPress and php.  We will also set up <code>static.askapache.com</code> to serve all of our sites uploads, images, css and javascript files, flash files, etc. with advanced caching and security using Apache Server .htaccess files.  So lets get started and take a look at this site structure for a moment.</p>

<pre>/home/askapache.com
|-- /home/askapache.com/backups/
|-- /home/askapache.com/public_html/
|-- /home/askapache.com/inc/
|-- /home/askapache.com/logs/
|-- /home/askapache.com/static/
|-- /home/askapache.com/tmp/
|-- /home/askapache.com/.htpasswd-basic
`-- /home/askapache.com/.htpasswd-digest</pre>


<ul>
<li><code>/backups/</code> - For <a href="http://www.askapache.com/wordpress/encrypted-wordpress-site-backups.html">encrypted backups of WordPress database and site files</a>. And any other backups.</li>
<li><code>/public_html/</code> - The document root for <code>www.askapache.com</code></li>
<li><code>/inc/</code> - Folder to keep your php include files for extra security and easy management.</li>
<li><code>/logs/</code> - Save your php, apache, and other logs here or create symlinks to them.</li>
<li><code>/static/</code> - The document root for <code>static.askapache.com</code></li>
<li><code>/tmp/</code> - Only need this if your host doesn't already have a /tmp folder</li>
</ul>
<hr class="HR0" />



<h2>Strong Security, Top to Bottom</h2>
<p><img class="IFL" src="http://uploads.askapache.com/2008/09/1023103_warning_icon_32.jpg" width="150" alt="Optimize a Website for Speed, Security, and Easy Management" title="Site Security with Apache" />Simply by implementing correct access permissions, file permissions, password protection and segmenting various folders and services we are already ahead of the game.  I've always taken security extremely seriously, so you can benefit from alot of the simple solutions I'm recommending for a really locked down site.<br class="C" /></p>
<p>Indeed, security is a major part of every step of this setup process, as security concerns are what drives a lot of the motivations I have for coming up with this setup in the first place.  We will be doing very simple but very effective site security like the following items, which is a short list compared to everything we will be doing.</p>
<ul>
<li>Fixing file permissions automatically</li>
<li>Searching for modified files on the server</li>
<li>Encrypting your backups</li>
<li>Get alerted to breakin attempts</li>
<li>Block tons of bad clients</li>
<li>Disallowing cgi scripts or any other handlers, just serve files.</li>
<li>Configuring PHP</li>
<li>Password Protection for certain areas</li>
</ul>

<h3>Ready for Warfare?</h3>
<p>My past work for an Internet Service Provider, followed by 4 years of auditing the security of organizations external/internal networks has given me a fresh perspective on website security, and I think it allows me to see what would really be effective at preventing and killing attacks.  In fact just last night I was once again doing some research into some off-the-wall security topics, and I discovered a new defense method that I will be writing about very soon.  I believe that this new method,  could be quickly adopted and implemented by hosting providers and software developers, which would result in us finally taking the Internet back from all those zombies and robots.  This method will be discussed in great detail soon, and will be a core part of this site setups security and optimization.</p>
<hr class="HR0" />


<h2>Built to <span style="color:red">Bleed Speed</span></h2>
<p><img class="IFL" src="http://uploads.askapache.com/2008/09/speedontheroadimg.jpg" width="150" alt="Optimize a Website for Speed, Security, and Easy Management" title="326255_speed_on_the_road" />Serve's files as fast and efficiently as possible using advanced caching, HTTP Protocols, php/server configurations.<br class="C" /></p>
<p>Many of the articles and research on this blog is about improving the speed and efficiency of your website.  In fact that is why I am helping develop open-source software to block spammers from WordPress blogs... not because I'm bothered by the spam, but because they make the net slow!  So lets look at some of the ideas we'll be implementing.</p>

<p>Many techniques I've been using and tweaking for several years, and recently many of them were included in the high-performance websites list.  Of course we will be taking a look at this list in practical terms, meaning almost all of it, the caching, compression, etc., will be automated in keeping with our "comfort" goal, which is to say we want to make the Web Developer and Server Admin's lives as easy and comfy as possible.  After all, we do the work right?</p>
<ol>
<li>Reduce HTTP requests - <a href="http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html" title="304 If Modified article">Reducing 304 requests with Cache-Control Headers</a></li>
<li>Use a customized php.ini - <a href="http://www.askapache.com/php/custom-phpini-tips-and-tricks.html">Creating and using a custom PHP.ini</a></li>
<li>Add an Expires header - <a href="http://www.askapache.com/htaccess/speed-up-your-site-with-caching-and-cache-control.html#caching-with-mod_expires" title="mod_expires Caching article">Caching with mod_expires on Apache</a></li>
<li>Gzip components</li>
<li>Make CSS and unobtrusive Javascript as external files not inline</li>
<li>Reduce DNS lookups - Use Static IP address, use a subdomain with static IP address for static content.</li>
<li>Minimize Javascript - Refactor the code, compress with dojo</li>
<li>Avoid external redirects - <a href="http://www.askapache.com/htaccess/mod_rewrite-tips-and-tricks.html" title="mod_rewrite internal redirection and rewrites">Use internal redirection with mod_rewrite</a>, <a href="http://www.askapache.com/htaccess/301-redirect-with-mod_rewrite-or-redirectmatch.html" title="301 Redirect with mod_rewrite or RedirectMatch">The correct way to redirect with 301</a></li>
<li>Turn off ETags - <a href="http://www.askapache.com/htaccess/using-http-headers-with-htaccess.html#prevent-caching-with-htaccess">Prevent Caching with htaccess</a></li>
<li>Make AJAX cacheable and small</li>
</ol>

<h3>AskApache.com, Fastest Site Ever!</h3>
<p>Ok it <em>might</em> not be the #1, but surely the top 10.. ;)</p>
<p>I'm very proud of the performance I am able to achieve on this site.  Very proud.  I started looking for ways to improve the wp-cache and wp-super-cache WordPress plugins, and came up with hacks for both of them.. but they still didn't do what I wanted so I started from scratch and wrote my own caching plugin.</p>
<p>With much more advanced caching options and unquestionably higher performance and lower time usage on the machine.  I'm hesitant to release it to the public until I get faded on it.. I just really love it.. it has been running my site for several months now and I keep finding ways to improve it.. Stay tuned.</p>
<p>One feature it has is the ability to allow negotiation of a resource between apache and the client.  Think almost transparent mutli-lingual blogs, mutliple formats per document (look at the rdf for this page for an example*). But that plugin is the future and this is the present.. so back to it we go.</p>
<hr class="HR0" />



<h2>Pamper the Webmaster with Extreme Comfort</h2>
<p><img class="IFL" src="http://uploads.askapache.com/2008/09/wwwonthebeachimg.jpg" width="150" alt="Optimize a Website for Speed, Security, and Easy Management" title="Low Maintenance Web Development" />This section alone would make this setup appealing.  I have developed all types of techniques and methods to make my life as easy as possible.  I could literally DIE right now and this blog would continue to run and operate for years on its own.   The general philosophy that I have used to get to where I can goto the beach with my laptop and do all this crazy stuff is <strong>the idea of perfection</strong>.  That may sound a little put-offish, but it basically means I will focus in on one very specific area for improvement or research and just get sick with it.  Most of this blogs articles are enlightening examples of this in action.  I will take a relatively unknown or unused piece of code or software and experiment with it until I feel I have it down, then I move on to the next item of never-ending research.  Mostly I think this is just plain habit from when I was studying security.  I'm much better at this then that :)</p>

<h3>Apache ErrorDocuments</h3>
<p>The <a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html">57 HTTP Status Codes and Apache ErrorDocuments</a> article is a prime example.  I was simply searching for an authoritative list of HTTP status codes, an issue not many web people find worth their time, and that search led to some of the most useful stuff I've found about the Web<br /><br />This "Comfort" article will include multi-language, intelligent, and optimized error documents for handling any type of HTTP error with class and allow us to stop spammers, save bandwidth, redirect correctly, etc..  You will probably be surprised at all the uses an Apache ErrorDocument can have.. It IS one of the foundations of the HTTP-based Net after all.<br class="C" /></p>

<h3>Emphasis on Easy Upgrades</h3>
<p>The whole setup is geared to make hassle-free WordPress/PHP/application upgrades possible by keeping different types of files in separate places, keeping backups, other misc tricks and since all of these files are in /home/askapache.com, your FTP connection can still access every file easily.  Sometimes security and optimizing your server can lead to it being more of a pain to do updates, backups, and general maintenance.  This article tries to overwhelm the balance with a trifecta of goals.</p>

<h3>Move to a new host? Ok!</h3>
<p>Comfort to me also means being able to pack up the whole website and database and move to another web host in under an hour.  I can move the whole AskApache site to one of several other hosting providers accounts I have in about 30minutes.  If this was a clients site or I was getting paid more, I'd also be focused on round-robin DNS technology, balance-load setups, and just go crazy making it fast.</p>

<h3>Staying Online, Improving Uptime</h3>
<p>Ever since I started sharing information and software to stop all these resource hogging zombies attacking everything I've been attacked several times.  Normally I get over 10K exploit attempts or requests per day, which I pretty much block 100%.  But a few times they've actually tried to DDOS me off the net in a distributed attack.  I have implemented several "poor mans" techniques to put up your best effort at surviving, which I did.  Basically you want to configure your server to KILL connections just as fast as possible and prevent your server resources from skyrocketing and surpassing your quotas.  A skilled attacker could easily shut you down even without the use of a widespread botnet if they are clever, which could be devastating to your small blog or site if it goes down at a crucial instant.</p>
<hr class="HR0" />





<h2>Organization with Templates and Systems</h2>
<p>I used to work with a guy who did alot of the coldfusion programming for us, and I used to cringe every  time I was called in to upgrade a site or do a re-design.  Files and folders EVERYWHERE!  Literally images in every folder, multiple index.html, index1.html, index-old.html, and on and on it went.. It would take me hours just to reverse-engineer the site enough so I could modify files on it without having some unkown consequence happen.</p>

<h3>Do You Have a Cluttered Desktop?</h3>
<p>Everyone has this problem, what I do all the time is just grab everything on my desktop and put it in a folder named with the date.  Then the process repeats itself and invariably a few months later I'm looking at a cluttered screen again.</p>

<p>This absolutely is the worst thing that can happen to a website, worst for security, comfort for webmaster, and speed.  So this setup addresses that issue completely heads on.  With all the different pages, tools, and resources available on this blog, I can almost promise you that my site has less files than yours.  No small feat to be sure, but worth every second I spent researching how to do it now that its on and popping.</p>
<hr class="HR0" />




<h2>What's a Website really?</h2>
<p>All hosts are different, but any host worth their salt is running some kind of <a href="http://www.askapache.com/linux/">BSD/Linux</a> operating system, and that is good news because those operating systems all use very similarly excellent file/folder structures with huge organization systems.  If your web hosting provider is running on a Windows based operating system or other locked/proprietary software than this article is not for you and I would recommend switching hosts to a BSD/Linux open-source operating system.</p>

<h3>Listening for Requests with Web Hosting and DNS</h3>
<p>First you set your website up so it can start serving.</p>
<ol>
<li>You buy your domain name, which just gives you the right to use it.</li>
<li>You pay your webhost for an account on their machine running a Server connected to the Net <em>via a fast connection link</em>.</li>
<li>You pay a DNS provider to redirect requests for your domain  name to be sent to your webhosts machine running the server.</li>
</ol>



<h2>Sub-Domain for Serving Assets</h2>
<p>This is a very cool method I've been using more and more frequently because it makes updates, upgrades, and changes so much easier to manage.  And segmenting various parts of the site is smart security, and even smarter in the way of speeding up a website and keeping your <strong>servers running mean and lean</strong>.</p>

<h2>Full Site Structure Expanded</h2>
<pre>/home/askapache.com
|-- /home/askapache.com/backups/
|-- /home/askapache.com/public_html/
|   |-- /home/askapache.com/public_html/about/
|   |-- /home/askapache.com/public_html/admin/
|   |-- /home/askapache.com/public_html/cgi-bin/
|   |-- /home/askapache.com/public_html/.htaccess
|   |-- /home/askapache.com/public_html/index.php
|   `-- /home/askapache.com/public_html/robots.txt
|-- /home/askapache.com/inc/
|   |-- /home/askapache.com/inc/config.inc.php
|   `-- /home/askapache.com/inc/settings.inc.php
|-- /home/askapache.com/logs/
|   |-- /home/askapache.com/logs/access.log
|   |-- /home/askapache.com/logs/error.log
|   |-- /home/askapache.com/logs/logins.log
|   |-- /home/askapache.com/logs/modsec_audit.log
|   |-- /home/askapache.com/logs/modsec_debug.log
|   `-- /home/askapache.com/logs/php_error.log
|-- /home/askapache.com/static/
|   |-- /home/askapache.com/static/css/
|   |-- /home/askapache.com/static/flv/
|   |-- /home/askapache.com/static/img/
|   |-- /home/askapache.com/static/js/
|   |-- /home/askapache.com/static/mp3/
|   |-- /home/askapache.com/static/pdf/
|   |-- /home/askapache.com/static/swf/
|   |-- /home/askapache.com/static/.htaccess
|   |-- /home/askapache.com/static/index.html
|   `-- /home/askapache.com/static/robots.txt
|-- /home/askapache.com/tmp/
|-- /home/askapache.com/.htpasswd-basic
`-- /home/askapache.com/.htpasswd-digest</pre>


<h2>Full Expanded Structure</h2>
<pre>/home/askapache.com
|-- /home/askapache.com/backups/
|-- /home/askapache.com/public_html/
|   |-- /home/askapache.com/public_html/about/
|   |   `-- /home/askapache.com/public_html/about/index.html
|   |-- /home/askapache.com/public_html/admin/
|   |   |-- /home/askapache.com/public_html/admin/.htaccess
|   |   `-- /home/askapache.com/public_html/admin/index.html
|   |-- /home/askapache.com/public_html/cgi-bin/
|   |   |-- /home/askapache.com/public_html/cgi-bin/bin/
|   |   |   |-- /home/askapache.com/public_html/cgi-bin/bin/.htaccess
|   |   |   |-- /home/askapache.com/public_html/cgi-bin/bin/php.cgi*
|   |   |   |-- /home/askapache.com/public_html/cgi-bin/bin/php.ini
|   |   |   |-- /home/askapache.com/public_html/cgi-bin/bin/php4.cgi*
|   |   |   `-- /home/askapache.com/public_html/cgi-bin/bin/php5.cgi*
|   |   |-- /home/askapache.com/public_html/cgi-bin/private/
|   |   |   |-- /home/askapache.com/public_html/cgi-bin/private/.htaccess
|   |   |   |-- /home/askapache.com/public_html/cgi-bin/private/debug.php
|   |   |   `-- /home/askapache.com/public_html/cgi-bin/private/stats.php
|   |   |-- /home/askapache.com/public_html/cgi-bin/.htaccess
|   |   |-- /home/askapache.com/public_html/cgi-bin/login.php
|   |   |-- /home/askapache.com/public_html/cgi-bin/printenv.cgi*
&nbsp;
|   |   `-- /home/askapache.com/public_html/cgi-bin/redir.cgi*
|   |-- /home/askapache.com/public_html/.htaccess
|   |-- /home/askapache.com/public_html/index.php
|   `-- /home/askapache.com/public_html/robots.txt
|-- /home/askapache.com/inc/
|   |-- /home/askapache.com/inc/config.php
|   `-- /home/askapache.com/inc/functions.php
|-- /home/askapache.com/logs/
|   |-- /home/askapache.com/logs/access.log
|   |-- /home/askapache.com/logs/error.log
|   |-- /home/askapache.com/logs/logins.log
|   |-- /home/askapache.com/logs/modsec_audit.log
|   |-- /home/askapache.com/logs/modsec_debug.log
|   `-- /home/askapache.com/logs/php_error.log
|-- /home/askapache.com/static/
|   |-- /home/askapache.com/static/css/
|   |   `-- /home/askapache.com/static/css/apache.css
|   |-- /home/askapache.com/static/flv/
|   |   `-- /home/askapache.com/static/flv/apache.flv
|   |-- /home/askapache.com/static/img/
|   |   |-- /home/askapache.com/static/img/apache.gif
|   |   |-- /home/askapache.com/static/img/apache.jpg
|   |   `-- /home/askapache.com/static/img/apache.png
|   |-- /home/askapache.com/static/js/
|   |   `-- /home/askapache.com/static/js/apache.js
|   |-- /home/askapache.com/static/mp3/
|   |   `-- /home/askapache.com/static/mp3/apache.mp3
|   |-- /home/askapache.com/static/pdf/
|   |   `-- /home/askapache.com/static/pdf/apache.pdf
|   |-- /home/askapache.com/static/swf/
|   |   `-- /home/askapache.com/static/swf/apache.swf
|   |-- /home/askapache.com/static/.htaccess
|   |-- /home/askapache.com/static/index.html
|   `-- /home/askapache.com/static/robots.txt
|-- /home/askapache.com/tmp/
|-- /home/askapache.com/.htpasswd-basic
`-- /home/askapache.com/.htpasswd-digest</pre>

<h2>Merchant Account Services</h2>
<p>If you want to make it easier for your customers to shop at your site, check out <a href="http://www.networksolutions.com/merchant-accounts/index.jsp" title="Merchant Account Services from Network Solutions">merchant account services</a> from Network Solutions. Services like these can help bring credibility and security to your online business.</p>

<h2>Apache is Open-Source</h2>
<p>The buzz about apache and open-source is very real, apache is becoming more of a discussed topic as people realize the power and importance of <q cite="LL Cool J">Doing it and Doing it and Doing it well.</q> -  <small><a href="http://www.webmonkey.com/blog/Jumpbox_Offers_an_Easier_Way_to_Install_Movable_Type">Movable Type Apache Installs made easy</a>, <a href="http://www.ubuntugeek.com/webalizer-apache-web-server-log-file-analysis-tool.html">Checking out Apache Web logs</a>, <a href="http://eventurebiz.com/blog/securing-securing-your-wordpress-blog-post-6-protecting-the-wp-configphp-file/">Securing WordPress with .htaccess</a>, <a href="http://marketingdefined.com/blog/wordpress/using-wordpress-permalink-redirect-plugins-correctly/">WordPress Permalinks and .htaccess</a>, <a href="http://corpocrat.com/2008/09/19/install-apache-mod_substitute/">New search and replace module for apache!</a>, <a href="http://www.csskarma.com/blog/creating-an-htaccess-template/">creating an .htaccess template</a>, <a href="http://www.thelinuxblog.com/htaccess-allow-from/">.htaccess allow directive</a></small></p>

<p class="anote">Check back in a week for the first article, or better yet subscribe to my <a href="http://www.askapache.com/feed/">rss feed</a> or use the comment form below to get notified.</p><p><a href="http://www.askapache.com/hosting/optimize-website-files-cache-security.html"></a><a href="http://www.askapache.com/hosting/optimize-website-files-cache-security.html">Optimize a Website for Speed, Security, and Easy Management</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/hosting/optimize-website-files-cache-security.html/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Notes from Apache HTTPD Source Code</title>
		<link>http://www.askapache.com/hacking/notes-apache-httpd.html</link>
		<comments>http://www.askapache.com/hacking/notes-apache-httpd.html#comments</comments>
		<pubDate>Tue, 12 Aug 2008 07:08:35 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Hacking]]></category>

		<guid isPermaLink="false">http://www.askapache.com/?p=1094</guid>
		<description><![CDATA[<p>thought I'd take a break from coding and post about how open-source is such a great tool for finding the best answers to the toughest questions,</p>
<pre>
/** is the status code informational */
#define ap_is_HTTP_INFO(x)         (((x) >= 100)&#038;&((x) < 200))
/** is the status code OK ?*/

#define ap_is_HTTP_SUCCESS(x)      (((x) >= 200)&#038;&((x) < 300))
/** is the status code a redirect */
#define ap_is_HTTP_REDIRECT(x)     (((x) >= 300)&#038;&((x) < 400))

/** is the status code a error (client or server) */
#define ap_is_HTTP_ERROR(x)        (((x) >= 400)&#038;&((x) < 600))
/** is the status code a client error  */

#define ap_is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&#038;&((x) < 500))
/** is the status code a server error  */
#define ap_is_HTTP_SERVER_ERROR(x) (((x) >= 500)&#038;&((x) < 600))

/** is the status code a (potentially) valid response code?  */
#define ap_is_HTTP_VALID_RESPONSE(x) (((x) >= 100)&#038;&((x) < 600))
</pre>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/hacking/notes-apache-httpd.html"></a><a href="http://www.askapache.com/hacking/notes-apache-httpd.html"><cite>AskApache.com</cite></a></p><p>A nameless tech company leads the world in the anti-piracy / anti-personal-privacy movement while being the 6th most cash rich in the USA. And they've given me.. $499 Upgrades of the same product 15 years in a row?  I bought a laptop yesterday so my brush with piracy is still very fresh.</p>

<p class="cnote">Don't let the economic vultures steal your dreams.  <a href="http://www.gnu.org/">Contribute to the open-source software movement.</a></p>

<p>A shortcut past difficult coding questions is by looking for someone else who's already done it.  The best.  So when I am dealing with technical questions that just don't have published answers.. I want to look at the code and see for myself what is going on.  I almost always have one editor or another running to paste bits of code or comments I find in, to look at in more detail later.  I'm all about finding solutions as fast as I can, I'm used to obstacles on the net.</p>

<p>For many years I learned about networking technology from the outside in.  Instead of say learning about Apache by administrating servers like I do today, I learned about them in reverse. I wasn't building servers or programming daemons, I was learning about the flaws they had and what made them work.</p>

<p>Open source is the best learning tool on the planet, and some of the best can be found in all the various work done by Apache... Especially the Server project, which has a lonnnnnnng history of the best programmers and researchers on the planet helping to build a free product that single-handedly sparked a revolution that has powered our world the last 15 years.  <strong>Free.</strong>  <strong>Open Source.</strong> Copied by others.   This organization is responsible in large part for the evolution of the Internet and our interaction with it daily.. Apache servers are exhanging bitts and transmitting bytes at this very second.</p>


<h3>So I found these notes</h3>
<p>15min ago I was asking the Apache source code for some answers for the this password plugin, and thought I'd take a break from coding and post about how open-source is such a great tool for finding the best answers to the toughest questions, for me and this site only apache can answer many of the questions and answers dealth with here.</p>

<p class="anote">In fact, that's exactly the reason I'm so fond of saying, <strong>Ask</strong> <strong>Apache</strong>.  Just check out these Notes!</p>


<hr class="C" />
<pre>request_rec
    ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
    apr_array_header_t *rewriteconds;
    rewritecond_entry *conds;
    int i, rc;
    char *newuri = NULL;
    request_rec *r = ctx-&gt;r;
    int is_proxyreq = 0;
&nbsp;
/* Information to which an extension can be mapped
 */
typedef struct extension_info {
    char *forced_type;                /* Additional AddTyped stuff */
    char *encoding_type;              /* Added with AddEncoding... */
    char *language_type;              /* Added with AddLanguage... */
    char *handler;                    /* Added with AddHandler... */
    char *charset_type;               /* Added with AddCharset... */
    char *input_filters;              /* Added with AddInputFilter... */
    char *output_filters;             /* Added with AddOutputFilter... */
&nbsp;
static const command_rec mime_cmds[] =
{
    AP_INIT_ITERATE2("AddCharset", add_extension_info,
        (void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO,
        "a charset (e.g., iso-2022-jp), followed by one or more "
        "file extensions"),
    AP_INIT_ITERATE2("AddEncoding", add_extension_info,
        (void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO,
        "an encoding (e.g., gzip), followed by one or more file extensions"),
    AP_INIT_ITERATE2("AddHandler", add_extension_info,
        (void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO,
        "a handler name followed by one or more file extensions"),
    AP_INIT_ITERATE2("AddInputFilter", add_extension_info,
        (void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO,
        "input filter name (or ; delimited names) followed by one or "
        "more file extensions"),
    AP_INIT_ITERATE2("AddLanguage", add_extension_info,
        (void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO,
        "a language (e.g., fr), followed by one or more file extensions"),
    AP_INIT_ITERATE2("AddOutputFilter", add_extension_info,
        (void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO,
        "output filter name (or ; delimited names) followed by one or "
        "more file extensions"),
    AP_INIT_ITERATE2("AddType", add_extension_info,
        (void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO,
        "a mime type followed by one or more file extensions"),
    AP_INIT_TAKE1("DefaultLanguage", ap_set_string_slot,
        (void*)APR_OFFSETOF(mime_dir_config, default_language), OR_FILEINFO,
        "language to use for documents with no other language file extension"),
    AP_INIT_ITERATE("MultiviewsMatch", multiviews_match, NULL, OR_FILEINFO,
        "NegotiatedOnly (default), Handlers and/or Filters, or Any"),
    AP_INIT_ITERATE("RemoveCharset", remove_extension_info,
        (void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO,
        "one or more file extensions"),
    AP_INIT_ITERATE("RemoveEncoding", remove_extension_info,
        (void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO,
        "one or more file extensions"),
    AP_INIT_ITERATE("RemoveHandler", remove_extension_info,
        (void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO,
        "one or more file extensions"),
    AP_INIT_ITERATE("RemoveInputFilter", remove_extension_info,
        (void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO,
        "one or more file extensions"),
    AP_INIT_ITERATE("RemoveLanguage", remove_extension_info,
        (void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO,
        "one or more file extensions"),
    AP_INIT_ITERATE("RemoveOutputFilter", remove_extension_info,
        (void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO,
        "one or more file extensions"),
    AP_INIT_ITERATE("RemoveType", remove_extension_info,
        (void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO,
        "one or more file extensions"),
    AP_INIT_TAKE1("TypesConfig", set_types_config, NULL, RSRC_CONF,
        "the MIME types config file"),
    AP_INIT_FLAG("ModMimeUsePathInfo", ap_set_flag_slot,
        (void *)APR_OFFSETOF(mime_dir_config, use_path_info), ACCESS_CONF,
        "Set to &#039;yes&#039; to allow mod_mime to use path info for type checking"),
    {NULL}
};
&nbsp;
   /**
     *  &#039;allowed&#039; is a bitvector of the allowed methods.
     *
     *  A handler must ensure that the request method is one that
     *  it is capable of handling.  Generally modules should DECLINE
     *  any request methods they do not handle.  Prior to aborting the
     *  handler like this the handler should set r-&gt;allowed to the list
     *  of methods that it is willing to handle.  This bitvector is used
     *  to construct the "Allow:" header required for OPTIONS requests,
     *  and HTTP_METHOD_NOT_ALLOWED and HTTP_NOT_IMPLEMENTED status codes.
     *
     *  Since the default_handler deals with OPTIONS, all modules can
     *  usually decline to deal with OPTIONS.  TRACE is always allowed,
     *  modules don&#039;t need to set it explicitly.
     *
     *  Since the default_handler will always handle a GET, a
     *  module which does *not* implement GET should probably return
     *  HTTP_METHOD_NOT_ALLOWED.  Unfortunately this means that a Script GET
     *  handler can&#039;t be installed by mod_actions.
     */
&nbsp;
/**
 * @defgroup Methods List of Methods recognized by the server
 * @ingroup APACHE_CORE_DAEMON
 * @{
 *
 * @brief Methods recognized (but not necessarily handled) by the server.
 *
 * These constants are used in bit shifting masks of size int, so it is
 * unsafe to have more methods than bits in an int.  HEAD == M_GET.
 * This list must be tracked by the list in http_protocol.c in routine
 * ap_method_name_of().
 *
 */
&nbsp;
#define M_GET                   0       /** RFC 2616:
HTTP */
#define M_PUT                   1       /*  :
*/
#define M_POST                  2
#define M_DELETE                3
#define M_CONNECT               4
#define M_OPTIONS               5
#define M_TRACE                 6       /** RFC 2616:
HTTP */
#define M_PATCH                 7       /** no rfc(!)
### remove this one? */
#define M_PROPFIND              8       /** RFC 2518:
WebDAV */
#define M_PROPPATCH             9       /*  :
*/
#define M_MKCOL                 10
#define M_COPY                  11
#define M_MOVE                  12
#define M_LOCK                  13
#define M_UNLOCK                14      /** RFC 2518:
WebDAV */
#define M_VERSION_CONTROL       15      /** RFC 3253:
WebDAV Versioning */
#define M_CHECKOUT              16      /*  :
*/
#define M_UNCHECKOUT            17
#define M_CHECKIN               18
#define M_UPDATE                19
#define M_LABEL                 20
#define M_REPORT                21
#define M_MKWORKSPACE           22
#define M_MKACTIVITY            23
#define M_BASELINE_CONTROL      24
#define M_MERGE                 25
#define M_INVALID               26      /** RFC 3253:
WebDAV Versioning */
&nbsp;
{
    methods_registry = apr_hash_make(p);
    apr_pool_cleanup_register(p, NULL,
                              ap_method_registry_destroy,
                              apr_pool_cleanup_null);
&nbsp;
    /* put all the standard methods into the registry hash to ease the
       mapping operations between name and number */
    register_one_method(p, "GET", M_GET);
    register_one_method(p, "PUT", M_PUT);
    register_one_method(p, "POST", M_POST);
    register_one_method(p, "DELETE", M_DELETE);
    register_one_method(p, "CONNECT", M_CONNECT);
    register_one_method(p, "OPTIONS", M_OPTIONS);
    register_one_method(p, "TRACE", M_TRACE);
    register_one_method(p, "PATCH", M_PATCH);
    register_one_method(p, "PROPFIND", M_PROPFIND);
    register_one_method(p, "PROPPATCH", M_PROPPATCH);
    register_one_method(p, "MKCOL", M_MKCOL);
    register_one_method(p, "COPY", M_COPY);
    register_one_method(p, "MOVE", M_MOVE);
    register_one_method(p, "LOCK", M_LOCK);
    register_one_method(p, "UNLOCK", M_UNLOCK);
    register_one_method(p, "VERSION-CONTROL", M_VERSION_CONTROL);
    register_one_method(p, "CHECKOUT", M_CHECKOUT);
    register_one_method(p, "UNCHECKOUT", M_UNCHECKOUT);
    register_one_method(p, "CHECKIN", M_CHECKIN);
    register_one_method(p, "UPDATE", M_UPDATE);
    register_one_method(p, "LABEL", M_LABEL);
    register_one_method(p, "REPORT", M_REPORT);
    register_one_method(p, "MKWORKSPACE", M_MKWORKSPACE);
    register_one_method(p, "MKACTIVITY", M_MKACTIVITY);
    register_one_method(p, "BASELINE-CONTROL", M_BASELINE_CONTROL);
    register_one_method(p, "MERGE", M_MERGE);
&nbsp;
/**
 * @defgroup HTTP_Status HTTP Status Codes
 * @{
 */
/**
 * The size of the static array in http_protocol.c for storing
 * all of the potential response status-lines (a sparse table).
 * A future version should dynamically generate the apr_table_t at startup.
 */
#define RESPONSE_CODES 57
&nbsp;
#define HTTP_CONTINUE                      100
#define HTTP_SWITCHING_PROTOCOLS           101
#define HTTP_PROCESSING                    102
#define HTTP_OK                            200
#define HTTP_CREATED                       201
#define HTTP_ACCEPTED                      202
#define HTTP_NON_AUTHORITATIVE             203
#define HTTP_NO_CONTENT                    204
#define HTTP_RESET_CONTENT                 205
#define HTTP_PARTIAL_CONTENT               206
#define HTTP_MULTI_STATUS                  207
#define HTTP_MULTIPLE_CHOICES              300
#define HTTP_MOVED_PERMANENTLY             301
#define HTTP_MOVED_TEMPORARILY             302
#define HTTP_SEE_OTHER                     303
#define HTTP_NOT_MODIFIED                  304
#define HTTP_USE_PROXY                     305
#define HTTP_TEMPORARY_REDIRECT            307
#define HTTP_BAD_REQUEST                   400
#define HTTP_UNAUTHORIZED                  401
#define HTTP_PAYMENT_REQUIRED              402
#define HTTP_FORBIDDEN                     403
#define HTTP_NOT_FOUND                     404
#define HTTP_METHOD_NOT_ALLOWED            405
#define HTTP_NOT_ACCEPTABLE                406
#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407
#define HTTP_REQUEST_TIME_OUT              408
#define HTTP_CONFLICT                      409
#define HTTP_GONE                          410
#define HTTP_LENGTH_REQUIRED               411
#define HTTP_PRECONDITION_FAILED           412
#define HTTP_REQUEST_ENTITY_TOO_LARGE      413
#define HTTP_REQUEST_URI_TOO_LARGE         414
#define HTTP_UNSUPPORTED_MEDIA_TYPE        415
#define HTTP_RANGE_NOT_SATISFIABLE         416
#define HTTP_EXPECTATION_FAILED            417
#define HTTP_UNPROCESSABLE_ENTITY          422
#define HTTP_LOCKED                        423
#define HTTP_FAILED_DEPENDENCY             424
#define HTTP_UPGRADE_REQUIRED              426
#define HTTP_INTERNAL_SERVER_ERROR         500
#define HTTP_NOT_IMPLEMENTED               501
#define HTTP_BAD_GATEWAY                   502
#define HTTP_SERVICE_UNAVAILABLE           503
#define HTTP_GATEWAY_TIME_OUT              504
#define HTTP_VERSION_NOT_SUPPORTED         505
#define HTTP_VARIANT_ALSO_VARIES           506
#define HTTP_INSUFFICIENT_STORAGE          507
#define HTTP_NOT_EXTENDED                  510
&nbsp;
/* The max method number. Method numbers are used to shift bitmasks,
 * so this cannot exceed 63, and all bits high is equal to -1, which is a
 * special flag, so the last bit used has index 62.
 */
#define METHOD_NUMBER_LAST  62
&nbsp;
static const char * status_lines[RESPONSE_CODES] =
#else
static const char * const status_lines[RESPONSE_CODES] =
#endif
{
    "100 Continue",
    "101 Switching Protocols",
    "102 Processing",
#define LEVEL_200  3
    "200 OK",
    "201 Created",
    "202 Accepted",
    "203 Non-Authoritative Information",
    "204 No Content",
    "205 Reset Content",
    "206 Partial Content",
    "207 Multi-Status",
#define LEVEL_300 11
    "300 Multiple Choices",
    "301 Moved Permanently",
    "302 Found",
    "303 See Other",
    "304 Not Modified",
    "305 Use Proxy",
    "306 unused",
    "307 Temporary Redirect",
#define LEVEL_400 19
    "400 Bad Request",
    "401 Authorization Required",
    "402 Payment Required",
    "403 Forbidden",
    "404 Not Found",
    "405 Method Not Allowed",
    "406 Not Acceptable",
    "407 Proxy Authentication Required",
    "408 Request Time-out",
    "409 Conflict",
    "410 Gone",
    "411 Length Required",
    "412 Precondition Failed",
    "413 Request Entity Too Large",
    "414 Request-URI Too Large",
    "415 Unsupported Media Type",
    "416 Requested Range Not Satisfiable",
    "417 Expectation Failed",
    "418 unused",
    "419 unused",
    "420 unused",
    "421 unused",
    "422 Unprocessable Entity",
    "423 Locked",
    "424 Failed Dependency",
    /* This is a hack, but it is required for ap_index_of_response
     * to work with 426.
     */
    "425 No code",
    "426 Upgrade Required",
#define LEVEL_500 46
    "500 Internal Server Error",
    "501 Method Not Implemented",
    "502 Bad Gateway",
    "503 Service Temporarily Unavailable",
    "504 Gateway Time-out",
    "505 HTTP Version Not Supported",
    "506 Variant Also Negotiates",
    "507 Insufficient Storage",
    "508 unused",
    "509 unused",
    "510 Not Extended"
};
&nbsp;
/** is the status code informational */
#define ap_is_HTTP_INFO(x)         (((x) &gt;= 100)&amp;&amp;((x) &lt; 200))
/** is the status code OK ?*/
#define ap_is_HTTP_SUCCESS(x)      (((x) &gt;= 200)&amp;&amp;((x) &lt; 300))
/** is the status code a redirect */
#define ap_is_HTTP_REDIRECT(x)     (((x) &gt;= 300)&amp;&amp;((x) &lt; 400))
/** is the status code a error (client or server) */
#define ap_is_HTTP_ERROR(x)        (((x) &gt;= 400)&amp;&amp;((x) &lt; 600))
/** is the status code a client error  */
#define ap_is_HTTP_CLIENT_ERROR(x) (((x) &gt;= 400)&amp;&amp;((x) &lt; 500))
/** is the status code a server error  */
#define ap_is_HTTP_SERVER_ERROR(x) (((x) &gt;= 500)&amp;&amp;((x) &lt; 600))
/** is the status code a (potentially) valid response code?  */
#define ap_is_HTTP_VALID_RESPONSE(x) (((x) &gt;= 100)&amp;&amp;((x) &lt; 600))
&nbsp;
/** should the status code drop the connection */
#define ap_status_drops_connection(x)
                                   (((x) == HTTP_BAD_REQUEST)           ||
                                    ((x) == HTTP_REQUEST_TIME_OUT)      ||
                                    ((x) == HTTP_LENGTH_REQUIRED)       ||
                                    ((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) ||
                                    ((x) == HTTP_REQUEST_URI_TOO_LARGE) ||
                                    ((x) == HTTP_INTERNAL_SERVER_ERROR) ||
                                    ((x) == HTTP_SERVICE_UNAVAILABLE) ||
                                    ((x) == HTTP_NOT_IMPLEMENTED))
&nbsp;
/*
&nbsp;
 * mod_headers.c: Add/append/remove HTTP response headers
 *     Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996
 *
 * The Header directive can be used to add/replace/remove HTTP headers
 * within the response message.  The RequestHeader directive can be used
 * to add/replace/remove HTTP headers before a request message is processed.
&nbsp;
 * Valid in both per-server and per-dir configurations.
 *
 * Syntax is:
 *
 *   Header action header value
 *   RequestHeader action header value
&nbsp;
 *
 * Where action is one of:
 *     set    - set this header, replacing any old value
 *     add    - add this header, possible resulting in two or more
 *              headers with the same name
 *     append - append this text onto any existing header of this same
&nbsp;
 *     unset  - remove this header
 *
 * Where action is unset, the third argument (value) should not be given.
 * The header name can include the colon, or not.
 *
 * The Header and RequestHeader directives can only be used where allowed
&nbsp;
 * by the FileInfo override.
 *
 * When the request is processed, the header directives are processed in
 * this order: firstly, the main server, then the virtual server handling
 * this request (if any), then any &lt;directory&gt; sections (working downwards
&nbsp;
 * from the root dir), then an &lt;location&gt; sections (working down from
 * shortest URL component), the any &lt;file&gt; sections. This order is
 * important if any &#039;set&#039; or &#039;unset&#039; actions are used. For example,
 * the following two directives have different effect if applied in
&nbsp;
 * the reverse order:
 *
 *   Header append Author "John P. Doe"
 *   Header unset Author
 *
 * Examples:
&nbsp;
 *
 *  To set the "Author" header, use
 *     Header add Author "John P. Doe"
 *
 *  To remove a header:
 *     Header unset Author
&nbsp;
 *
 */
    register_format_tag_handler("D", (const void *)header_request_duration);
    register_format_tag_handler("t", (const void *)header_request_time);
    register_format_tag_handler("e", (const void *)header_request_env_var);
    register_format_tag_handler("s", (const void *)header_request_ssl_var);
&nbsp;
typedef enum {
    hdr_add = &#039;a&#039;,              /* add header (could mean multiple hdrs) */
    hdr_set = &#039;s&#039;,              /* set (replace old value) */
&nbsp;
    hdr_append = &#039;m&#039;,           /* append (merge into any old value) */
    hdr_unset = &#039;u&#039;,            /* unset header */
&nbsp;
    hdr_echo = &#039;e&#039;,             /* echo headers from request to response */
    hdr_edit = &#039;r&#039;              /* change value by regexp */
&nbsp;
} hdr_actions;
&nbsp;
/*
 * magic cmd-&gt;info values
 */
static char hdr_in  = &#039;0&#039;;  /* RequestHeader */
&nbsp;
static char hdr_out = &#039;1&#039;;  /* Header onsuccess */
static char hdr_err = &#039;2&#039;;  /* Header always */
&nbsp;
/*
 * A format string consists of white space, text and optional format
 * tags in any order. E.g.,
 *
 * Header add MyHeader "Free form text %D %t more text"
&nbsp;
 *
 * Decompose the format string into its tags. Each tag (struct format_tag)
 * contains a pointer to the function used to format the tag. Then save each
 * tag in the tag array anchored in the header_entry.
 */
&nbsp;
        return "first argument must be &#039;add&#039;, &#039;set&#039;, &#039;append&#039;, &#039;unset&#039;, "
               "&#039;echo&#039; or &#039;edit&#039;.";
&nbsp;
    if (new-&gt;action == hdr_edit) {
        if (subs == NULL) {
            return "Header edit requires a match and a substitution";
        }
&nbsp;
 if (new-&gt;action == hdr_edit) {
        if (subs == NULL) {
            return "Header edit requires a match and a substitution";
        }
        new-&gt;regex = ap_pregcomp(cmd-&gt;pool, value, AP_REG_EXTENDED);
        if (new-&gt;regex == NULL) {
            return "Header edit regex could not be compiled";
        }
        new-&gt;subs = subs;
    }
    else {
        /* there&#039;s no subs, so envclause is really that argument */
&nbsp;
        if (envclause != NULL) {
            return "Too many arguments to directive";
        }
        envclause = subs;
    }
    if (new-&gt;action == hdr_unset) {
        if (value) {
            if (envclause) {
                return "header unset takes two arguments";
            }
            envclause = value;
            value = NULL;
        }
    }
    else if (new-&gt;action == hdr_echo) {
        ap_regex_t *regex;
&nbsp;
        if (value) {
            if (envclause) {
                return "Header echo takes two arguments";
            }
            envclause = value;
            value = NULL;
        }
        if (cmd-&gt;info != &amp;hdr_out &amp;&amp; cmd-&gt;info != &amp;hdr_err)
            return "Header echo only valid on Header "
&nbsp;
                   "directives";
        else {
            regex = ap_pregcomp(cmd-&gt;pool, hdr, AP_REG_EXTENDED | AP_REG_NOSUB);
            if (regex == NULL) {
                return "Header echo regex could not be compiled";
            }
        }
        new-&gt;regex = regex;
    }
    else if (!value)
        return "Header requires three arguments";
   /* Handle the envclause on Header */
&nbsp;
    if (envclause != NULL) {
        if (strcasecmp(envclause, "early") == 0) {
            condition_var = condition_early;
        }
        else {
            if (strncasecmp(envclause, "env=", 4) != 0) {
                return "error: envclause should be in the form env=envar";
            }
            if ((envclause[4] == &#039;\0&#039;)
                || ((envclause[4] == &#039;!&#039;) &amp;&amp; (envclause[5] == &#039;\0&#039;))) {
                return "error: missing environment variable name. "
&nbsp;
                    "envclause should be in the form env=envar ";
&nbsp;
    AP_INIT_RAW_ARGS("Header", header_cmd, &amp;hdr_out, OR_FILEINFO,
                     "an optional condition, an action, header and value "
                     "followed by optional env clause"),
    AP_INIT_RAW_ARGS("RequestHeader", header_cmd, &amp;hdr_in, OR_FILEINFO,
                     "an action, header and value followed by optional env "
                     "clause"),
&nbsp;
    else if (!r-&gt;content_type || strcmp(r-&gt;content_type, ct)) {
        r-&gt;content_type = ct;
&nbsp;
        /* Insert filters requested by the AddOutputFiltersByType
&nbsp;
         * configuration directive. Content-type filters must be
         * inserted after the content handlers have run because
         * only then, do we reliably know the content-type.
         */
        ap_add_output_filters_by_type(r);
    }
}
&nbsp;
/* construct and return the default error message for a given
&nbsp;
 * HTTP defined error code
 */
static const char *get_canned_error_string(int
status,
                                           request_rec *r,
                                           const char *location)
{
    apr_pool_t *p = r-&gt;pool;
    const char *error_notes, *h1, *s1;
&nbsp;
    switch (status) {
    case HTTP_MOVED_PERMANENTLY:
    case HTTP_MOVED_TEMPORARILY:
    case HTTP_TEMPORARY_REDIRECT:
        return(apr_pstrcat(p,
                           "&lt;p&gt;The document has moved &lt;a href=\"",
                           ap_escape_html(r-&gt;pool, location),
                           "\"&gt;here&lt;/a&gt;.&lt;/p&gt;\n",
                           NULL));
    case HTTP_SEE_OTHER:
        return(apr_pstrcat(p,
                           "&lt;p&gt;The answer to your request is located "
&nbsp;
                           "&lt;a href=\"",
                           ap_escape_html(r-&gt;pool, location),
                           "\"&gt;here&lt;/a&gt;.&lt;/p&gt;\n",
                           NULL));
    case HTTP_USE_PROXY:
        return(apr_pstrcat(p,
                           "&lt;p&gt;This resource is only accessible "
&nbsp;
                           "through the proxy\n",
                           ap_escape_html(r-&gt;pool, location),
                           "&lt;br /&gt;\nYou will need to configure "
                           "your client to use that proxy.&lt;/p&gt;\n",
                           NULL));
    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
    case HTTP_UNAUTHORIZED:
        return("&lt;p&gt;This server could not verify that you\n"
&nbsp;
               "are authorized to access the document\n"
               "requested.  Either you supplied the wrong\n"
               "credentials (e.g., bad password), or your\n"
               "browser doesn&#039;t understand how to supply\n"
&nbsp;
               "the credentials required.&lt;/p&gt;\n");
    case HTTP_BAD_REQUEST:
        return(add_optional_notes(r,
                                  "&lt;p&gt;Your browser sent a request that "
                                  "this server could not understand.&lt;br /&gt;\n",
                                  "error-notes",
                                  "&lt;/p&gt;\n"));
    case HTTP_FORBIDDEN:
        return(apr_pstrcat(p,
                           "&lt;p&gt;You don&#039;t have permission to access ",
                           ap_escape_html(r-&gt;pool, r-&gt;uri),
                           "\non this server.&lt;/p&gt;\n",
                           NULL));
    case HTTP_NOT_FOUND:
        return(apr_pstrcat(p,
                           "&lt;p&gt;The requested URL ",
                           ap_escape_html(r-&gt;pool, r-&gt;uri),
                           " was not found on this server.&lt;/p&gt;\n",
                           NULL));
    case HTTP_METHOD_NOT_ALLOWED:
        return(apr_pstrcat(p,
                           "&lt;p&gt;The requested method ", r-&gt;method,
                           " is not allowed for the URL ",
                           ap_escape_html(r-&gt;pool, r-&gt;uri),
                           ".&lt;/p&gt;\n",
                           NULL));
    case HTTP_NOT_ACCEPTABLE:
        s1 = apr_pstrcat(p,
                         "&lt;p&gt;An appropriate representation of the "
&nbsp;
                         "requested resource ",
                         ap_escape_html(r-&gt;pool, r-&gt;uri),
                         " could not be found on this server.&lt;/p&gt;\n",
                         NULL);
        return(add_optional_notes(r, s1, "variant-list", ""));
    case HTTP_MULTIPLE_CHOICES:
        return(add_optional_notes(r, "", "variant-list", ""));
    case HTTP_LENGTH_REQUIRED:
        s1 = apr_pstrcat(p,
                         "&lt;p&gt;A request of the requested method ",
                         r-&gt;method,
                         " requires a valid Content-length.&lt;br /&gt;\n",
                         NULL);
        return(add_optional_notes(r, s1, "error-notes", "&lt;/p&gt;\n"));
    case HTTP_PRECONDITION_FAILED:
        return(apr_pstrcat(p,
                           "&lt;p&gt;The precondition on the request "
&nbsp;
                           "for the URL ",
                           ap_escape_html(r-&gt;pool, r-&gt;uri),
                           " evaluated to false.&lt;/p&gt;\n",
                           NULL));
    case HTTP_NOT_IMPLEMENTED:
        s1 = apr_pstrcat(p,
                         "&lt;p&gt;",
                         ap_escape_html(r-&gt;pool, r-&gt;method), " to ",
                         ap_escape_html(r-&gt;pool, r-&gt;uri),
                         " not supported.&lt;br /&gt;\n",
                         NULL);
        return(add_optional_notes(r, s1, "error-notes", "&lt;/p&gt;\n"));
    case HTTP_BAD_GATEWAY:
        s1 = "&lt;p&gt;The proxy server received an invalid" CRLF
            "response from an upstream server.&lt;br /&gt;" CRLF;
        return(add_optional_notes(r, s1, "error-notes", "&lt;/p&gt;\n"));
    case HTTP_VARIANT_ALSO_VARIES:
        return(apr_pstrcat(p,
                           "&lt;p&gt;A variant for the requested "
&nbsp;
                           "resource\n&lt;pre&gt;\n",
                           ap_escape_html(r-&gt;pool, r-&gt;uri),
                           "\n</pre>\nis
itself a negotiable resource. "
                           "This indicates a configuration error.</p>\n",
                           NULL));
    case HTTP_REQUEST_TIME_OUT:
        return("<p>Server timeout waiting for the HTTP request from the client.</p>\n");
    case HTTP_GONE:
        return(apr_pstrcat(p,
                           "<p>The requested resource<br />",
                           ap_escape_html(r->pool, r->uri),
                           "<br />\nis no longer available on this server "

                           "and there is no forwarding address.\n"
                           "Please remove all references to this "
                           "resource.</p>\n",
                           NULL));
    case HTTP_REQUEST_ENTITY_TOO_LARGE:
        return(apr_pstrcat(p,
                           "The requested resource<br />",
                           ap_escape_html(r->pool, r->uri), "<br />\n",
                           "does not allow request data with ",
                           r->method,
                           " requests, or the amount of data provided in\n"

                           "the request exceeds the capacity limit.\n",
                           NULL));
    case HTTP_REQUEST_URI_TOO_LARGE:
        s1 = "<p>The requested URL's length exceeds the capacity\n"
             "limit for this server.<br />\n";
        return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
    case HTTP_UNSUPPORTED_MEDIA_TYPE:
        return("<p>The supplied request data is not in a format\n"

               "acceptable for processing by this resource.</p>\n");
    case HTTP_RANGE_NOT_SATISFIABLE:
        return("<p>None of the range-specifier values in the Range\n"

               "request-header field overlap the current extent\n"
               "of the selected resource.</p>\n");
    case HTTP_EXPECTATION_FAILED:
        return(apr_pstrcat(p,
                           "<p>The expectation given in the Expect "

                           "request-header"
                           "\nfield could not be met by this server.</p>\n"
                           "<p>The client sent<pre>\n    Expect: ",
                           ap_escape_html(r-&gt;pool, apr_table_get(r-&gt;headers_in, "Expect")),
                           "\n</pre>\n"

                           "but we only allow the 100-continue "
                           "expectation.</p>\n",
                           NULL));
    case HTTP_UNPROCESSABLE_ENTITY:
        return("<p>The server understands the media type of the\n"

               "request entity, but was unable to process the\n"
               "contained instructions.</p>\n");
    case HTTP_LOCKED:
        return("<p>The requested resource is currently locked.\n"

               "The lock must be released or proper identification\n"
               "given before the method can be applied.</p>\n");
    case HTTP_FAILED_DEPENDENCY:
        return("<p>The method could not be performed on the resource\n"

               "because the requested action depended on another\n"
               "action and that other action failed.</p>\n");
    case HTTP_UPGRADE_REQUIRED:
        return("<p>The requested resource can only be retrieved\n"

               "using SSL.  The server is willing to upgrade the current\n"
               "connection to SSL, but your client doesn't support it.\n"
               "Either upgrade your client, or try requesting the page\n"
               "using https://\n");
    case HTTP_INSUFFICIENT_STORAGE:
        return("<p>The method could not be performed on the resource\n"

               "because the server is unable to store the\n"
               "representation needed to successfully complete the\n"
               "request.  There is insufficient free space left in\n"
               "your storage allocation.</p>\n");
    case HTTP_SERVICE_UNAVAILABLE:
        return("<p>The server is temporarily unable to service your\n"

               "request due to maintenance downtime or capacity\n"
               "problems. Please try again later.</p>\n");
    case HTTP_GATEWAY_TIME_OUT:
        return("<p>The proxy server did not receive a timely response\n"

               "from the upstream server.</p>\n");
    case HTTP_NOT_EXTENDED:
        return("<p>A mandatory extension policy in the request is not\n"

               "accepted by the server for this resource.</p>\n");
    default:                    /* HTTP_INTERNAL_SERVER_ERROR */
        /*
         * This comparison to expose error-notes could be modified to

         * use a configuration directive and export based on that
         * directive.  For now "*" is used to designate an error-notes
         * that is totally safe for any user to see (ie lacks paths,
         * database passwords, etc.)
         */
        if (((error_notes = apr_table_get(r->notes,
                                          "error-notes")) != NULL)
            && (h1 = apr_table_get(r->notes, "verbose-error-to")) != NULL

            && (strcmp(h1, "*") == 0)) {
            return(apr_pstrcat(p, error_notes, "<p />\n",
NULL));
        }
        else {
            return(apr_pstrcat(p,
                               "<p>The server encountered an internal "

                               "error or\n"
                               "misconfiguration and was unable to complete\n"
                               "your request.</p>\n"
                               "<p>Please contact the server "

                               "administrator,\n ",
                               ap_escape_html(r->pool,
                                              r->server->server_admin),
                               " and inform them of the time the "
                               "error occurred,\n"
                               "and anything you might have done that "

                               "may have\n"
                               "caused the error.</p>\n"
                               "<p>More information about this error "
                               "may be available\n"

                               "in the server error log.</p>\n",
                               NULL));
        }




        /* For all HTTP/1.x responses for which we generate the message,
         * we need to avoid inheriting the "normal status" header fields
         * that may have been set by the request handler before the

         * error or redirect, except for Location on external redirects.
         */
        r->headers_out = r->err_headers_out;
        r->err_headers_out = tmp;
        apr_table_clear(r->err_headers_out);

        if (ap_is_HTTP_REDIRECT(status) || (status == HTTP_CREATED)) {
            if ((location != NULL) && *location) {
                apr_table_setn(r->headers_out, "Location", location);
            }
            else {
                location = "";   /* avoids coredump when printing, below */

            }
        }

        r->content_languages = NULL;
        r->content_encoding = NULL;

        if ((status == HTTP_METHOD_NOT_ALLOWED)
            || (status == HTTP_NOT_IMPLEMENTED)) {
            apr_table_setn(r->headers_out, "Allow", make_allow(r));
        }



    if ((custom_response = ap_response_code_string(r, idx))) {
        /*

         * We have a custom response output. This should only be
         * a text-string to write back. But if the ErrorDocument
         * was a local redirect and the requested resource failed
         * for any reason, the custom_response will still hold the
         * redirect URL. We don't really want to output this URL
         * as a text message, so first check the custom response

         * string to ensure that it is a text-string (using the
         * same test used in ap_die(), i.e. does it start with a ").
         *
         * If it's not a text string, we've got a recursive error or
         * an external redirect.  If it's a recursive error, ap_die passes
         * us the second error code so we can write both, and has already

         * backed up to the original error.  If it's an external redirect,
         * it hasn't happened yet; we may never know if it fails.
         */
        if (custom_response[0] == '\"') {
            ap_rputs(custom_response + 1, r);
            ap_finalize_request_protocol(r);
            return;
        }
    }
    {
        const char *title = status_lines[idx];
        const char *h1;

        /* Accept a status_line set by a module, but only if it begins

         * with the 3 digit status code
         */
        if (r->status_line != NULL
            && strlen(r->status_line) > 4       /* long enough */

            && apr_isdigit(r->status_line[0])
            && apr_isdigit(r->status_line[1])
            && apr_isdigit(r->status_line[2])
            && apr_isspace(r->status_line[3])
            && apr_isalnum(r->status_line[4])) {
            title = r->status_line;
        }

        /* folks decided they didn't want the error code in the H1 text */

        h1 = &title[4];

        /* can't count on a charset filter being in place here,
         * so do ebcdic->ascii translation explicitly (if needed)
         */

        ap_rvputs_proto_in_ascii(r,
                  DOCTYPE_HTML_2_0
                  "<html><head>\n<title>", title,
                  "</title>\n</head><body>\n<h1>", h1, "</h1>\n",
                  NULL);

        ap_rvputs_proto_in_ascii(r,
                                 get_canned_error_string(status, r, location),
                                 NULL);

        if (recursive_error) {
            ap_rvputs_proto_in_ascii(r, "<p>Additionally, a ",
                      status_lines[ap_index_of_response(recursive_error)],
                      "\nerror was encountered while trying to use an "

                      "ErrorDocument to handle the request.</p>\n", NULL);
        }
        ap_rvputs_proto_in_ascii(r, ap_psignature("<hr />\n", r), NULL);
        ap_rvputs_proto_in_ascii(r, "<a rel="bookmark" href="http://www.askapache.com/"
title="Web Development, Programming, Web Design, Security, Web Hosting and Apache .htaccess, Server Articles">AskApache Web Development</a></body></html>\n", NULL);

    }
    ap_finalize_request_protocol(r);
}







static const command_rec command_table[] = {

    AP_INIT_FLAG(    "RewriteEngine",   cmd_rewriteengine,  NULL, OR_FILEINFO,
                     "On or Off to enable or disable (default) the whole "
                     "rewriting engine"),
    AP_INIT_ITERATE( "RewriteOptions",  cmd_rewriteoptions,  NULL, OR_FILEINFO,
                     "List of option strings to set"),
    AP_INIT_TAKE1(   "RewriteBase",     cmd_rewritebase,     NULL, OR_FILEINFO,
                     "the base URL of the per-directory context"),
    AP_INIT_RAW_ARGS("RewriteCond",     cmd_rewritecond,     NULL, OR_FILEINFO,
                     "an input string and a to be applied regexp-pattern"),
    AP_INIT_RAW_ARGS("RewriteRule",     cmd_rewriterule,     NULL, OR_FILEINFO,
                     "an URL-applied regexp-pattern and a substitution URL"),
    AP_INIT_TAKE2(   "RewriteMap",      cmd_rewritemap,      NULL, RSRC_CONF,
                     "a mapname and a filename"),
    AP_INIT_TAKE1(   "RewriteLock",     cmd_rewritelock,     NULL, RSRC_CONF,
                     "the filename of a lockfile used for inter-process "

                     "synchronization"),
#ifndef REWRITELOG_DISABLED
    AP_INIT_TAKE1(   "RewriteLog",      cmd_rewritelog,      NULL, RSRC_CONF,
                     "the filename of the rewriting logfile"),
    AP_INIT_TAKE1(   "RewriteLogLevel", cmd_rewriteloglevel, NULL, RSRC_CONF,
                     "the level of the rewriting logfile verbosity "

                     "(0=none, 1=std, .., 9=max)"),
#else
    AP_INIT_TAKE1(   "RewriteLog", fake_rewritelog, NULL, RSRC_CONF,
                     "[DISABLED] the filename of the rewriting logfile"),
    AP_INIT_TAKE1(   "RewriteLogLevel", fake_rewritelog, NULL, RSRC_CONF,
                     "[DISABLED] the level of the rewriting logfile verbosity"),

#endif




















/*
 * mod_actions.c: executes scripts based on MIME type or HTTP method
 *
 * by Alexei Kosut; based on mod_cgi.c, mod_mime.c and mod_includes.c,

 * adapted by rst from original NCSA code by Rob McCool
 *
 * Usage instructions:
 *
 * Action mime/type /cgi-bin/script
 *

 * will activate /cgi-bin/script when a file of content type mime/type is
 * requested. It sends the URL and file path of the requested document using
 * the standard CGI PATH_INFO and PATH_TRANSLATED environment variables.
 *
 * Script PUT /cgi-bin/script
 *

 * will activate /cgi-bin/script when a request is received with the
 * HTTP method "PUT".  The available method names are defined in httpd.h.
 * If the method is GET, the script will only be activated if the requested
 * URI includes query information (stuff after a ?-mark).
 */











        if (!data) {
            char *exp_time = NULL;

            expires = apr_strtok(NULL, ":", &tok_cntx);
            path = expires ? apr_strtok(NULL, ":", &tok_cntx) : NULL;

            if (expires) {

                apr_time_exp_t tms;
                apr_time_exp_gmt(&tms, r->request_time
                                     + apr_time_from_sec((60 * atol(expires))));
                exp_time = apr_psprintf(r->pool, "%s, %.2d-%s-%.4d "

                                                 "%.2d:%.2d:%.2d GMT",
                                        apr_day_snames[tms.tm_wday],
                                        tms.tm_mday,
                                        apr_month_snames[tms.tm_mon],
                                        tms.tm_year+1900,
                                        tms.tm_hour, tms.tm_min, tms.tm_sec);
            }

            cookie = apr_pstrcat(rmain->pool,
                                 var, "=", val,
                                 "; path=", path ? path : "/",
                                 "; domain=", domain,
                                 expires ? "; expires=" : NULL,
                                 expires ? exp_time : NULL,
                                 NULL);

            apr_table_addn(rmain->err_headers_out, "Set-Cookie", cookie);
            apr_pool_userdata_set("set", notename, NULL, rmain->pool);
            rewritelog((rmain, 5, NULL, "setting cookie '%s'", cookie));
        }

        else {
            rewritelog((rmain, 5, NULL, "skipping already set cookie '%s'",
                        var));
        }

    }





rewriteloglevel
rewritelogfile
REWRITELOGFP
REWRITEMAPS
REWRITECONDS
REWRITERULES
REWRITELOCK
REWRITEBASE
MaxRedirects=



                        case 'f': newcond->ptype = CONDPAT_FILE_EXISTS; break;
            case 's': newcond->ptype = CONDPAT_FILE_SIZE;   break;
            case 'l': newcond->ptype = CONDPAT_FILE_LINK;   break;
            case 'd': newcond->ptype = CONDPAT_FILE_DIR;    break;
            case 'x': newcond->ptype = CONDPAT_FILE_XBIT;   break;
            case 'U': newcond->ptype = CONDPAT_LU_URL;      break;
            case 'F': newcond->ptype = CONDPAT_LU_FILE;     break;
                        case '>': newcond->ptype = CONDPAT_STR_GT; break;
            case '<': newcond->ptype = CONDPAT_STR_LT; break;
            case '=': newcond->ptype = CONDPAT_STR_EQ;
                /* "" represents an empty string */

                C CHAIN|COOKIE
                E ENV
                F FORBIDDEN
                G GONE
                H HANDLER
                L LAST
                N NOESCAPE|NEXT|NOSUBREQ|NOCASE
                P PROXY|PASSTHROUGH
                Q QSAPPEND
                S SKIP
                T TYPE
                R REDIRECT (PERMANENT, TEMP, SEEOTHER)

                else if (apr_isdigit(*val)) {
                    status = atoi(val);
                    if (status != HTTP_INTERNAL_SERVER_ERROR) {

                        int idx =
                            ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);

                        if (ap_index_of_response(status) == idx) {
                            return apr_psprintf(p, "RewriteRule: invalid HTTP "
                                                   "response code '%s' for "

                                                   "flag 'R'",
                                                val);



               /* arg3: optional flags field */
    newrule->forced_mimetype     = NULL;
    newrule->forced_handler      = NULL;
    newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY;
    newrule->flags  = RULEFLAG_NONE;
    newrule->env = NULL;
    newrule->cookie = NULL;
    newrule->skip   = 0;



case CONDPAT_LU_URL:
        if (*input && subreq_ok(r)) {
            rsub = ap_sub_req_lookup_uri(input, r, NULL);
            if (rsub->status < 400) {
                rc = 1;
            }
            rewritelog((r, 5, NULL, "RewriteCond URI (-U) check: "

                        "path=%s -> status=%d", input, rsub->status));
            ap_destroy_sub_req(rsub);
        }
        break;



/*
 * Apply a single RewriteRule

 */
static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
{
    ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
    apr_array_header_t *rewriteconds;
    rewritecond_entry *conds;
    int i, rc;
    char *newuri = NULL;
    request_rec *r = ctx->r;
    int is_proxyreq = 0;

    ctx->uri = r->filename;

    if (ctx->perdir) {
        apr_size_t dirlen = strlen(ctx->perdir);

        /*

         * Proxy request?
         */
        is_proxyreq = (   r->proxyreq && r->filename
                       && !strncmp(r->filename, "proxy:", 6));

        /* Since we want to match against the (so called) full URL, we have

         * to re-add the PATH_INFO postfix
         */
        if (r->path_info && *r->path_info) {
            rewritelog((r, 3, ctx->perdir, "add path info postfix: %s -> %s%s",
                        ctx->uri, ctx->uri, r->path_info));
            ctx->uri = apr_pstrcat(r->pool, ctx->uri, r->path_info, NULL);
        }

        /* Additionally we strip the physical path from the url to match

         * it independent from the underlaying filesystem.
         */
        if (!is_proxyreq && strlen(ctx->uri) >= dirlen &&
            !strncmp(ctx->uri, ctx->perdir, dirlen)) {




    /* expand [E=var:val] and [CO=<cookie>] */

    do_expand_env(p->env, ctx);
    do_expand_cookie(p->cookie, ctx);



    /* If this rule is explicitly forced for HTTP redirection
     * (`RewriteRule .. .. [R]') then force an external HTTP
     * redirect. But make sure it is a fully-qualified URL. (If
     * not it is qualified with ourself).

     */
    if (p->flags & RULEFLAG_FORCEREDIRECT) {
        fully_qualify_uri(r);

        rewritelog((r, 2, ctx->perdir, "explicitly forcing redirect with %s",
                    r->filename));

        r->status = p->forced_responsecode;
        return 1;
    }


   /*

             * The rule sets the response code (implies match-only)
             */
            if (p->flags & RULEFLAG_STATUS) {
                return ACTION_STATUS;
            }


    rewrite_ssl_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup);
    rewrite_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https);







    /*

     *  add the SCRIPT_URL variable to the env. this is a bit complicated
     *  due to the fact that apache uses subrequests and internal redirects
     */

    if (r->main == NULL) {
         var = apr_table_get(r->subprocess_env, REDIRECT_ENVVAR_SCRIPT_URL);
         if (var == NULL) {
             apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, r->uri);
         }
         else {
             apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
         }
    }
    else {
         var = apr_table_get(r->main->subprocess_env, ENVVAR_SCRIPT_URL);
         apr_table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
    }

    /*

     *  create the SCRIPT_URI variable for the env
     */

    /* add the canonical URI of this URL */
    thisserver = ap_get_server_name(r);
    port = ap_get_server_port(r);
    if (ap_is_default_port(port, r)) {
        thisport = "";
    }
    else {
        thisport = apr_psprintf(r->pool, ":%u", port);
    }
    thisurl = apr_table_get(r->subprocess_env, ENVVAR_SCRIPT_URL);




            /* now do the redirection */

            apr_table_setn(r->headers_out, "Location", r->filename);
            rewritelog((r, 1, NULL, "redirect to %s [REDIRECT/%d]", r->filename,
                        n));

            return n;







    /*

     *  Do the Options check after engine check, so
     *  the user is able to explicitely turn RewriteEngine Off.
     */
    if (!(ap_allow_options(r) & (OPT_SYM_LINKS | OPT_SYM_OWNER))) {
        /* FollowSymLinks is mandatory! */

        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                     "Options FollowSymLinks or SymLinksIfOwnerMatch is off "
                     "which implies that RewriteRule directive is forbidden: "
                     "%s", r->filename);
        return HTTP_FORBIDDEN;
    }
















        bodyoff = bodyread = apr_palloc(r->pool, bodybuf);

        /* only while we have enough for a chunked header */

        while ((!bodylen || bodybuf >= 32) &&
               (res = ap_get_client_block(r, bodyoff, bodybuf)) > 0) {
            bodylen += res;
            bodybuf -= res;
            bodyoff += res;
        }
        if (res > 0 && bodybuf < 32) {
            /* discard_rest_of_request_body into our buffer */

            while (ap_get_client_block(r, bodyread, bodylen) > 0)
                ;
            apr_table_setn(r->notes, "error-notes",
                   "Extended TRACE request bodies cannot exceed 64k\n");
            return HTTP_REQUEST_ENTITY_TOO_LARGE;
        }

        if (res < 0) {
            return HTTP_BAD_REQUEST;
        }
    }

    ap_set_content_type(r, "message/http");

    /* Now we recreate the request, and echo it back */

    bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
    apr_brigade_putstrs(bb, NULL, NULL, r->the_request, CRLF, NULL);
    h.pool = r->pool;




    if (r->status == HTTP_NOT_MODIFIED) {
        apr_table_do((int (*)(void *, const char *,
const char *)) form_header_field,
                     (void *) &h, r->headers_out,
                     "Connection",
                     "Keep-Alive",
                     "ETag",
                     "Content-Location",
                     "Expires",
                     "Cache-Control",
                     "Vary",
                     "Warning",
                     "WWW-Authenticate",
                     "Proxy-Authenticate",
                     "Set-Cookie",
                     "Set-Cookie2",
                     NULL);





/* Here we deal with getting the request message body from the client.
 * Whether or not the request contains a body is signaled by the presence
 * of a non-zero Content-Length or by a Transfer-Encoding: chunked.
 *
 * Note that this is more complicated than it was in Apache 1.1 and prior
 * versions, because chunked support means that the module does less.

 *
 * The proper procedure is this:
 *
 * 1. Call ap_setup_client_block() near the beginning of the request
 *    handler. This will set up all the necessary properties, and will
 *    return either OK, or an error code. If the latter, the module should

 *    return that error code. The second parameter selects the policy to
 *    apply if the request message indicates a body, and how a chunked
 *    transfer-coding should be interpreted. Choose one of
 *
 *    REQUEST_NO_BODY          Send 413 error if message has any body
 *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length

 *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
 *    REQUEST_CHUNKED_PASS     If chunked, pass the chunk headers with body.
 *
 *    In order to use the last two options, the caller MUST provide a buffer
 *    large enough to hold a chunk-size line, including any extensions.
 *

 * 2. When you are ready to read a body (if any), call ap_should_client_block().
 *    This will tell the module whether or not to read input. If it is 0,
 *    the module should assume that there is no message body to read.
 *
 * 3. Finally, call ap_get_client_block in a loop. Pass it a buffer and its size.
 *    It will put data into the buffer (not necessarily a full buffer), and

 *    return the length of the input block. When it is done reading, it will
 *    return 0 if EOF, or -1 if there was an error.
 *    If an error occurs on input, we force an end to keepalive.
 *
 *    This step also sends a 100 Continue response to HTTP/1.1 clients if appropriate.
 */





    /* The following convoluted conditional determines whether or not
     * the current connection should remain persistent after this response
     * (a.k.a. HTTP Keep-Alive) and whether or not the output message
     * body should use the HTTP/1.1 chunked transfer-coding.  In English,

     *
     *   IF  we have not marked this connection as errored;
     *   and the response body has a defined length due to the status code
     *       being 304 or 204, the request method being HEAD, already
     *       having defined Content-Length or Transfer-Encoding: chunked, or
     *       the request version being HTTP/1.1 and thus capable of being set

     *       as chunked [we know the (r->chunked = 1) side-effect is ugly];
     *   and the server configuration enables keep-alive;
     *   and the server configuration has a reasonable inter-request timeout;
     *   and there is no maximum # requests or the max hasn't been reached;
     *   and the response status does not require a close;
     *   and the response generator has not already indicated close;

     *   and the client did not request non-persistence (Connection: close);
     *   and    we haven't been configured to ignore the buggy twit
     *       or they're a buggy twit coming through a HTTP/1.1 proxy
     *   and    the client is requesting an HTTP/1.0-style keep-alive
     *       or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
     *   THEN we can be persistent, which requires more headers be output.

     *
     * Note that the condition evaluation order is extremely important.


AP_DECLARE(int) ap_meets_conditions(request_rec *r)
{
    const char *etag;
    const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch;

    apr_time_t tmp_time;
    apr_int64_t mtime;
    int not_modified = 0;

    /* Check for conditional requests --- note that we only want to do
     * this if we are successful so far and we are not processing a

     * subrequest or an ErrorDocument.
     *
     * The order of the checks is important, since ETag checks are supposed
     * to be more accurate than checks relative to the modification time.
     * However, not all documents are guaranteed to *have* ETags, and some
     * might have Last-Modified values w/o ETags, so this gets a little

     * complicated.
     */

    if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) {
        return OK;
    }

    etag = apr_table_get(r->headers_out, "ETag");

    /* All of our comparisons must be in seconds, because that's the

     * highest time resolution the HTTP specification allows.
     */
    /* XXX: we should define a "time unset"
constant */
    tmp_time = ((r->mtime != 0) ? r->mtime : apr_time_now());
    mtime =  apr_time_sec(tmp_time);

    /* If an If-Match request-header field was given

     * AND the field value is not "*" (meaning match anything)
     * AND if our strong ETag does not match any entity tag in that field,
     *     respond with a status of 412 (Precondition Failed).
     */
    if ((if_match = apr_table_get(r->headers_in, "If-Match")) != NULL) {
        if (if_match[0] != '*'

            && (etag == NULL || etag[0] == 'W'
                || !ap_find_list_item(r->pool, if_match, etag))) {
            return HTTP_PRECONDITION_FAILED;
        }
    }
    else {
        /* Else if a valid If-Unmodified-Since request-header field was given

         * AND the requested resource has been modified since the time
         * specified in this field, then the server MUST
         *     respond with a status of 412 (Precondition Failed).
         */
        if_unmodified = apr_table_get(r->headers_in, "If-Unmodified-Since");
        if (if_unmodified != NULL) {
            apr_time_t ius = apr_date_parse_http(if_unmodified);

            if ((ius != APR_DATE_BAD) && (mtime > apr_time_sec(ius))) {
                return HTTP_PRECONDITION_FAILED;
            }
        }
    }

    /* If an If-None-Match request-header field was given

     * AND the field value is "*" (meaning match anything)
     *     OR our ETag matches any of the entity tags in that field, fail.
     *
     * If the request method was GET or HEAD, failure means the server
     *    SHOULD respond with a 304 (Not Modified) response.
     * For all other request methods, failure means the server MUST

     *    respond with a status of 412 (Precondition Failed).
     *
     * GET or HEAD allow weak etag comparison, all other methods require
     * strong comparison.  We can only use weak if it's not a range request.
     */
    if_nonematch = apr_table_get(r->headers_in, "If-None-Match");
    if (if_nonematch != NULL) {
        if (r->method_number == M_GET) {
            if (if_nonematch[0] == '*') {
                not_modified = 1;
            }





/* Build the Allow field-value from the request handler method mask.
 * Note that we always allow TRACE, since it is handled below.
 */
static char *make_allow(request_rec *r)
{
    char *list;
    apr_int64_t mask;
    apr_array_header_t *allow = apr_array_make(r->pool, 10, sizeof(char *));
    apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry);
    /* For TRACE below */

    core_server_config *conf =
        ap_get_module_config(r->server->module_config, &core_module);

    mask = r->allowed_methods->method_mask;

    for (; hi; hi = apr_hash_next(hi)) {
        const void *key;
        void *val;

        apr_hash_this(hi, &key, NULL, &val);
        if ((mask & (AP_METHOD_BIT << *(int *)val)) != 0) {
            *(const char **)apr_array_push(allow) = key;

            /* the M_GET method actually refers to two methods */

            if (*(int *)val == M_GET)
                *(const char **)apr_array_push(allow) = "HEAD";
        }
    }

    /* TRACE is tested on a per-server basis */

    if (conf->trace_enable != AP_TRACE_DISABLE)
        *(const char **)apr_array_push(allow) = "TRACE";

    list = apr_array_pstrcat(r->pool, allow, ',');

    /* ### this is rather annoying. we should enforce registration of

       ### these methods */
    if ((mask & (AP_METHOD_BIT << M_INVALID))
        && (r->allowed_methods->method_list != NULL)
        && (r->allowed_methods->method_list->nelts != 0)) {
        int i;
        char **xmethod = (char **) r->allowed_methods->method_list->elts;

        /*

         * Append all of the elements of r->allowed_methods->method_list
         */
        for (i = 0; i < r->allowed_methods->method_list->nelts; ++i) {
            list = apr_pstrcat(r->pool, list, ",", xmethod[i], NULL);
        }
    }

    return list;
}

AP_DECLARE(int) ap_send_http_options(request_rec *r)
{
    if (r->assbackwards) {
        return DECLINED;
    }

    apr_table_setn(r->headers_out, "Allow", make_allow(r));

    /* the request finalization will send an EOS, which will flush all

     * the headers out (including the Allow header)
     */

    return OK;
}







/**
 * Get the server banner in a form suitable for sending over the

 * network, with the level of information controlled by the
 * ServerTokens directive.
 * @return The server banner
 */
AP_DECLARE(const char *) ap_get_server_banner(void);
</pre><p><a href="http://www.askapache.com/hacking/notes-apache-httpd.html"></a><a href="http://www.askapache.com/hacking/notes-apache-httpd.html">Notes from Apache HTTPD Source Code</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/hacking/notes-apache-httpd.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Preloading .flv and .mp3 files with Flash</title>
		<link>http://www.askapache.com/optimize/preloading-caching-flv-mp3.html</link>
		<comments>http://www.askapache.com/optimize/preloading-caching-flv-mp3.html#comments</comments>
		<pubDate>Tue, 05 Aug 2008 16:30:16 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Optimization]]></category>

		<guid isPermaLink="false">http://www.askapache.com/flash/preloading-caching-flv-mp3.html</guid>
		<description><![CDATA[<p><a class="IFL" rel="lb" href='http://www.askapache.com/flash/preloading-caching-flv-mp3.html' title='Preload/Cache .mp3 .flv files with Flash Actionscript'><img src='http://uploads.askapache.com/2008/02/myflash1.thumbnail.jpg' alt='Preload/Cache .mp3 .flv files with Flash Actionscript' /></a>If you want to pre-load <code>.flv</code> / <code>.mp3</code> files into a visitors browser cache using flash, here's the actionscript I use to do it, and some ideas behind a good javascript implementation using swfobject or ufo.<br class="C" /></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/optimize/preloading-caching-flv-mp3.html"></a><a href="http://www.askapache.com/optimize/preloading-caching-flv-mp3.html"><cite>AskApache.com</cite></a></p><p><a class="IFL" rel="lb" href='http://www.askapache.com/flash/preloading-caching-flv-mp3.html' title='Preload/Cache .mp3 .flv files with Flash Actionscript'><img src='http://uploads.askapache.com/2008/02/myflash1.thumbnail.jpg' alt='Preload/Cache .mp3 .flv files with Flash Actionscript' title="myflash1.thumbnail optimize" /></a>The company I work for does <em>tons</em> of online videos for our clients, and being the lead web designer I am responsible for making the videos work flawlessly and instantly.  Fortunately for my clients, I am a little obsessive about finding the best of the best of the best way to do things.  I have a LONG way to go, especially when it comes to flash, but here are a few choice tips and tricks that currently work for my clients.<br class="C" /></p>


<p class="anote">You can read an alternate/older explanation of this <a href="http://www.askapache.com/htaccess/preload-and-cache-flash-flv-files.html">method here</a>.</p>


<h2>Preloading files into Browser Cache</h2>
<p>One thing I like to do that no-one can appreciate except me and maybe you is to preload the sites various .flv and .mp3 files into the site visitors cache.  Let me give you an example.  Site.com has 12 videos spread out on multiple pages, all are .flv files controlled by a single .swf flash video player.  Most visitors arrive at the home page which has 1 of the 12 videos on it.  So the trick is to preload the other 11 .flv video files from the home page.  Then when the visitor goes to a different page with a different video, it loads instantly.</p>

<h2>Preloading .flv files with Actionscript</h2>
<p>The actionscript is easy, it opens a connection to the .flv file, sets the buffertime to 0, plays the video and immediately pauses, then seeks the position back to 0.</p>
<p>Its relatively easy to get this to work, heres all the actionscript you will need to preload any .flv file.  Just create a new flash document, and on frame 1 enter in this actionscript.  You can also search your flash help for "preloading" for more help.</p>
<pre>var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
//attach videodisplay
_level0.attachVideo(ns);
ns.setBufferTime(0);
ns.play(&#039;http://static.askapache.com/f/flv/create-boot-ini.flv&#039;);
ns.pause();
ns.seek(0);</pre>


<h2>Preloading .mp3 files with Actionscript</h2>
<p>This is even easier than .flv!  This is all you need and the mp3 file will be requested from the browser and added to the browsers cache.</p>
<pre>var songTrack:Sound = new Sound();
songTrack.loadSound("http://static.askapache.com/f/mp3/ga-urchin-speed.mp3", true);</pre>


<h2>Little Tricks and Tips</h2>

<h3>Passing filenames with flashvars</h3>
<p>So now you have the actionscript and files, but what if you want to pass the file using flashvars?  So <code>/preloader.swf?file=http://static.askapache.com/f/flv/create-boot-ini.flv</code> will work?</p>
<pre>if (!_root.file) {
  file = &#039;http://static.askapache.com/f/flv/create-boot-ini.flv&#039;;
} else {
  file = _root.file;
}
&nbsp;
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
//attach videodisplay
_level0.attachVideo(ns);
ns.setBufferTime(0);
ns.play(file);
ns.pause();
ns.seek(0);</pre>


<h3>Using javascript to time the downloads</h3>
<p>Now, you may think you are a hotshot if you preload 12 .flv files from the homepage using swfobject or ufo, but the problem with doing that all at once is that flash has some real serious issues with running multiple instances like that.  Meaning the movie that IS on your homepage might very well FREEZE or stutter mid-play if you are trying to preload all these files in the background.  I won't get into advanced stuff here but to start with you should at least utilize something like a setTimeout function.  I rely heavily on javascript loops to do this.</p>
<pre>setTimeout(function(){swfobject or ufo code;},10000); // 10 second wait</pre>

<h3>Waiting till fully buffered</h3>
<p>Depending on your .flv video player .swf, you may or may not have the capability to receive information on whether or not a file has been loaded or is fully buffered.  So an additional step that I personally take is I don't start the preloading loop code until the 1st movie on the home-page has fully buffered.  Sometimes I wait until its done playing.</p>


<h2>Apache .htaccess</h2>
<p>Of course, I can't forget this bit of .htaccess</p>
<pre>AddType video/x-flv .flv
AddType application/x-shockwave-flash .swf
&nbsp;
&lt;filesMatch "\.(flv|swf|mp3)$"&gt;
Header unset Pragma
FileETag None
Header unset ETag
Header unset P3P
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
&lt;/filesMatch&gt;</pre>





<h2>Feeling Lucky?</h2>
<p>If by lucky you mean you dig learning how to make your sites FAST, heres some money.</p>
<p><strong>Easy Apache Speed Tips Articles</strong></p>
<ul>
<li><a href="http://www.askapache.com/htaccess/apache-speed-compression.html" title="Turn On gzip Compression to Speed Up Apache">Turn On Compression</a></li>

<li><a href="http://www.askapache.com/htaccess/apache-speed-expires.html" title="Add Far Future Expires Headers to Speed Up Your Site">Add Future Expires Header</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-cache-control.html" title="Cache-Control Headers using Apache and .htaccess">Add Cache-Control Headers</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-etags.html" title="Remove ETag Headers to Speed up Apache">Turn Off ETags</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-last-modified.html" title="Remove the Last-Modified Header from Files to Speed Apache">Remove Last-Modified Header</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-subdomains.html" title="Multiple Subdomains for a Quicker and Faster Web Site">Use Multiple SubDomains</a></li>
</ul><p><a href="http://www.askapache.com/optimize/preloading-caching-flv-mp3.html"></a><a href="http://www.askapache.com/optimize/preloading-caching-flv-mp3.html">Preloading .flv and .mp3 files with Flash</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/optimize/preloading-caching-flv-mp3.html/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
<enclosure url="http://static.askapache.com/f/flv/create-boot-ini.flv" length="1027853" type="video/x-flv" />
<enclosure url="http://static.askapache.com/f/mp3/ga-urchin-speed.mp3" length="49152" type="audio/mpeg" />
<enclosure url="http://static.askapache.com/f/flv/create-boot-ini.flv" length="1027853" type="video/x-flv" />
<enclosure url="http://static.askapache.com/f/mp3/ga-urchin-speed.mp3" length="49152" type="audio/mpeg" />
		</item>
		<item>
		<title>Hack WP-Cache for Maximum Speed</title>
		<link>http://www.askapache.com/optimize/wp-cache-speed-hack.html</link>
		<comments>http://www.askapache.com/optimize/wp-cache-speed-hack.html#comments</comments>
		<pubDate>Tue, 11 Mar 2008 06:37:43 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Optimization]]></category>

		<guid isPermaLink="false">http://www.askapache.com/wordpress/wp-cache-speed-hack.html</guid>
		<description><![CDATA[<p><a class="IFL" rel="lb" href='http://uploads.askapache.com/2007/09/wp-cache-hack2.png' title='WP-Cache with Full AskApache Hack'><img src='http://uploads.askapache.com/2007/09/wp-cache-hack2.thumbnail.png' alt='WP-Cache with Full AskApache Hack' /></a><strong>If you desire SPEED from your WordPress blog</strong>, the #1 speed improvement comes from using the <a href="http://wordpress.org/extend/plugins/wp-cache/">WP-Cache Plugin</a>.  <strong>If you still desire SPEED after installing the Plugin, you can modify the WP-Cache Plugin code to make your blog even faster!</strong><br class="C" /></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/optimize/wp-cache-speed-hack.html"></a><a href="http://www.askapache.com/optimize/wp-cache-speed-hack.html"><cite>AskApache.com</cite></a></p><p class="anote">If you desire SPEED from your WordPress blog, the #1 speed improvement comes from using the <a href="http://wordpress.org/extend/plugins/wp-cache/">WP-Cache Plugin</a>.  <strong>However,</strong> if you still desire even more speed after installing the Plugin, you can modify the WP-Cache Plugin code run even faster!</p>

<h2>WP-Cache Speed Hack Results</h2>
<p><strong>WP-Cache Off</strong><br /><img class="IBRD" src='http://uploads.askapache.com/2007/09/wp-cache-off.png' alt='WP-Cache Off' title="wp cache off optimize" /></p>
<p><strong>WP-Cache Default Settings</strong><br /><img class="IBRD" src='http://uploads.askapache.com/2007/09/wp-cache-default.png' alt='WP-Cache On Defaults' title="wp cache default optimize" /></p>
<p><strong>WP-Cache With wp-cache-phase1.php Hack</strong><br /><img class="IBRD" src='http://uploads.askapache.com/2007/09/wp-cache-hack1.png' alt='WP-Cache With wp-cache-phase1.php Hack' title="wp cache hack1 optimize" /></p>
<p><strong>WP-Cache With Full Hack</strong><br /><img class="IBRD" src='http://uploads.askapache.com/2007/09/wp-cache-hack2.png' alt='WP-Cache with Full AskApache Hack' title="wp cache hack2 optimize" /></p>
<p>These results came from the Cacheability Checker.  <a href="http://www.askapache.com/tools/firefox-firebug-yslow.html">Yslow for firefox</a> is what you need today.</p>


<h2>Manual Instructions for hacking wp-cache</h2>
<p>First you should download and activate the <a href="http://wordpress.org/extend/plugins/wp-cache/">WP-Cache Plugin</a>, then enable it in your Options Configuration Panel for WP-Cache.</p>
<h3>Open wp-cache-phase1.php</h3>
<h4>Find</h4>
<pre>      /* No used to avoid problems with some PHP installations
      $content_size += strlen($log);
      header("Content-Length: $content_size");
      */</pre>
<h4>Replace with</h4>
<pre>
      // BEGIN AskApache WP-Cache hack
      $content_size += strlen($log);
      header("Content-Length: $content_size");
      // END AskApache WP-Cache hack
</pre>
<h3>Open wp-cache-phase2.php</h3>
<h4>Find</h4>
<pre>  /* Not used because it gives problems with some
   * PHP installations
  if (!$response{&#039;Content-Length&#039;}) {
  // WP does not set content size
    $content_size = ob_get_length();
    @header("Content-Length: $content_size");
    array_push($wp_cache_meta_object-&gt;headers, "Content-Length: $content_size");
  }
  */</pre>
<h4>Replace with</h4>
<pre>
  // BEGIN AskApache WP-Cache Hack
  if (!$response{&#039;Content-Length&#039;}) {
    $content_size = ob_get_length();
    @header("Content-Length: $content_size");
    array_push($wp_cache_meta_object-&gt;headers, "Content-Length: $content_size");
  }
  // END AskApache WP-Cache Hack
</pre>
<h4>Find</h4>
<pre>  if (!$response{&#039;Content-Type&#039;}) {
    $value =  "text/html; charset=\\"" . get_settings(&#039;blog_charset&#039;)  . "\\"";
    @header("Content-Type: $value");
    array_push($wp_cache_meta_object-&gt;headers, "Content-Type: $value");
  }</pre>
<h4>After Add</h4>
<pre>
  // BEGIN AskApache WP-Cache Hack
  if (!$response{&#039;Cache-Control&#039;}) {
      $value = "max-age=$cache_max_time, public";
      @header("Cache-Control: $value");
      array_push($wp_cache_meta_object-&gt;headers, "Cache-Control: $value");
  }
  // END AskApache WP-Cache Hack
</pre>


<h3>Download the Modified WP-Cache Plugin</h3>
<p>Just download and install as if it were the actual <a href="http://wordpress.org/extend/plugins/wp-cache/">WP-Cache Plugin</a>.<a href="http://uploads.askapache.com/wp-cache.zip">wp-cache.zip</a> | <a href="http://uploads.askapache.com/wp-cache.rar">wp-cache.rar</a></p>




<h2>Want More Speed?</h2>
<p>Then check out the other speed articles on AskApache.</p>
<ul>
<li><a href="http://www.askapache.com/htaccess/apache-speed-compression.html">Turn On Compression</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-expires.html">Add Future Expires Header</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-cache-control.html">Add Cache-Control Headers</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-etags.html">Turn Off ETags</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-last-modified.html">Remove Last-Modified Header</a></li>
</ul>
<p>Or just add this to your <a href="http://www.askapache.com/htaccess/htaccess.html">blogs .htaccess file</a>.</p>
<pre>#           HEADERS and CACHING
# 1 YEAR
&lt;filesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$"&gt;
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Pragma
Header unset Last-Modified
Header unset ETag
FileETag None
&lt;/filesMatch&gt;
&nbsp;
# 2 DAYS
&lt;filesMatch "\.(xml|txt)$"&gt;
Header set Cache-Control "max-age=172800, public, must-revalidate"
Header unset Pragma
Header unset Last-Modified
Header unset ETag
FileETag None
&lt;/filesMatch&gt;
&nbsp;
# 2 HOURS
&lt;filesMatch "\.(html|htm)$"&gt;
Header set Cache-Control "max-age=7200, must-revalidate"
Header unset Pragma
Header unset ETag
FileETag None
&lt;/filesMatch&gt;
&nbsp;
# COMPRESSION
&lt;filesMatch "\.(js|css)$"&gt;
SetOutputFilter DEFLATE
&lt;/filesMatch&gt;</pre><p><a href="http://www.askapache.com/optimize/wp-cache-speed-hack.html"></a><a href="http://www.askapache.com/optimize/wp-cache-speed-hack.html">Hack WP-Cache for Maximum Speed</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/optimize/wp-cache-speed-hack.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Speed Tips: Add Cache-Control Headers</title>
		<link>http://www.askapache.com/htaccess/apache-speed-cache-control.html</link>
		<comments>http://www.askapache.com/htaccess/apache-speed-cache-control.html#comments</comments>
		<pubDate>Tue, 11 Mar 2008 03:53:16 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Htaccess]]></category>

		<guid isPermaLink="false">http://www.askapache.com/htaccess/apache-speed-cache-control.html</guid>
		<description><![CDATA[<p><a class="IFL" rel="lb" href='http://uploads.askapache.com/2007/09/speed-cache-control-on.png' title='Cache-Control Headers On'><img src='http://uploads.askapache.com/2007/09/speed-cache-control-on.thumbnail.png' alt='Cache-Control Headers On' width='128' height='42'  /></a><strong>Using Cache-Control headers you can specify which types of proxies can cache certain content, and how long files should be cached</strong>.<br class="C" /></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/htaccess/apache-speed-cache-control.html"></a><a href="http://www.askapache.com/htaccess/apache-speed-cache-control.html"><cite>AskApache.com</cite></a></p><p><a class="IFL" rel="lb" href='http://uploads.askapache.com/2007/09/speed-cache-control-on.png' title='Cache-Control Headers On'><img src='http://uploads.askapache.com/2007/09/speed-cache-control-on.thumbnail.png' width='128' height='42' alt='Cache-Control Headers On' title="speed cache control on.thumbnail htaccess" /></a><strong>Using Cache-Control headers you can specify which types of proxies can cache certain content, and how long files should be cached.</strong>  You can also add the <code>must-revalidate</code> header to force checking the <code>ETag</code> and or <code>Last-Modified</code> for the file to make sure the cache is using the current version.<br class="C" /></p>
<p><strong>Easy Apache Speed Tips Articles</strong></p>
<ul>
<li><a href="http://www.askapache.com/htaccess/apache-speed-compression.html" title="Turn On gzip Compression to Speed Up Apache">Turn On Compression</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-expires.html" title="Add Far Future Expires Headers to Speed Up Your Site">Add Future Expires Header</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-cache-control.html" title="Cache-Control Headers using Apache and .htaccess">Add Cache-Control Headers</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-etags.html" title="Remove ETag Headers to Speed up Apache">Turn Off ETags</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-last-modified.html" title="Remove the Last-Modified Header from Files to Speed Apache">Remove Last-Modified Header</a></li>
<li><a href="http://www.askapache.com/htaccess/apache-speed-subdomains.html" title="Multiple Subdomains for a Quicker and Faster Web Site">Use Multiple SubDomains</a></li>
</ul>
<p class="anote">Keep in mind, if you use a <strong>far future Expires header</strong> you have to change the component's filename whenever the file changes.  So please add must-revalidate to your Cache-Control header for your .html files.</p>
<h2>Add Cache-Control Headers</h2>
<p>This goes in your root <a href="http://www.askapache.com/htaccess/htaccess.html">.htaccess file</a> but if you have access to <code>httpd.conf</code> that is better.</p>
<p>This code uses the <a href="http://www.askapache.com/htaccess/using-filesmatch-and-files-in-htaccess.html">FilesMatch directive</a> and the <a href="http://askapache.info/trunk/mod/mod_headers.html#header">Header</a> directive to add Cache-Control Headers to certain files.</p>
<pre># 480 weeks
&lt;filesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$"&gt;
Header set Cache-Control "max-age=290304000, public"
&lt;/filesMatch&gt;
&nbsp;
# 2 DAYS
&lt;filesMatch "\.(xml|txt)$"&gt;
Header set Cache-Control "max-age=172800, public, must-revalidate"
&lt;/filesMatch&gt;
&nbsp;
# 2 HOURS
&lt;filesMatch "\.(html|htm)$"&gt;
Header set Cache-Control "max-age=7200, must-revalidate"
&lt;/filesMatch&gt;</pre>
<p>If you are using <a href="http://www.askapache.com/htaccess/apache-speed-expires.html">far Future Expires Headers</a> and Cache-Control <em>(recommended)</em>, you can do this for these files.</p>
<pre>&lt;filesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$"&gt;
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
&lt;/filesMatch&gt;</pre>


<h3>Without Cache-Control Headers</h3>
<p><img src='http://uploads.askapache.com/2007/09/speed-cache-control-off.png' alt='No Cache-Control Headers' width="627" height="208" title="speed cache control off htaccess" /></p>

<h3>With Cache-Control Headers</h3>
<p><img src='http://uploads.askapache.com/2007/09/speed-cache-control-on.png' alt='Cache-Control Headers On' width="627" height="208" title="speed cache control on htaccess" /></p>



<h2>Currently AskApache.com Uses</h2>
<p>You can use the <a href="http://www.askapache.com/online-tools/http-headers-tool">HTTP Header Viewer Tool</a> to check it.</p>
<pre>Header unset Pragma
FileETag None
Header unset ETag
&nbsp;
# 1 YEAR
&lt;filesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|swf|mp3|mp4)$"&gt;
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Last-Modified
&lt;/filesMatch&gt;
&nbsp;
# 2 HOURS
&lt;filesMatch "\.(html|htm|xml|txt|xsl)$"&gt;
Header set Cache-Control "max-age=7200, must-revalidate"
&lt;/filesMatch&gt;
&nbsp;
# CACHED FOREVER
# MOD_REWRITE TO RENAME EVERY CHANGE
&lt;filesMatch "\.(js|css)$"&gt;
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Last-Modified
&lt;/filesMatch&gt;</pre><p><a href="http://www.askapache.com/htaccess/apache-speed-cache-control.html"></a><a href="http://www.askapache.com/htaccess/apache-speed-cache-control.html">Speed Tips: Add Cache-Control Headers</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/htaccess/apache-speed-cache-control.html/feed</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
	</channel>
</rss>

