<?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;  mod_include</title>
	<atom:link href="http://www.askapache.com/search/mod_include/feed/rss2/" 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>An AskApache Plugin Upgrade to Rule them All</title>
		<link>http://www.askapache.com/wordpress/an-askapache-plugin-upgrade-to-rule-them-all.html</link>
		<comments>http://www.askapache.com/wordpress/an-askapache-plugin-upgrade-to-rule-them-all.html#comments</comments>
		<pubDate>Wed, 29 Jul 2009 17:59:07 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.askapache.com/?p=3062</guid>
		<description><![CDATA[<p><a class="IFL" href="http://uploads.askapache.com/2009/07/apache-server-status.png"><img src="http://uploads.askapache.com/2009/07/apache-server-status-350x164.png" alt="apache-server-status" title="apache-server-status" width="350" height="164" class="alignnone size-medium wp-image-3070" /></a>So my blog as been rather quiet for almost a year now, and very few updates if any have been released for my Password Protection PLugin, my Google 404 Plugin, and definately not for my AskApache CrazyCache plugin, which I will be releasing last...  So for all of you who've helped me out by sending me suggestions and notifying me of errors and sticking with it...  Just wanted to <strong>say sorry about that, and thanks for all the great ideas.. </strong> Well, I've been sticking with it as well believe it our not.  I manage to get free days once in a while, and then its <strong>time to jam</strong>.<br class="C" /></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/wordpress/an-askapache-plugin-upgrade-to-rule-them-all.html"></a><a href="http://www.askapache.com/wordpress/an-askapache-plugin-upgrade-to-rule-them-all.html"><cite>AskApache.com</cite></a></p><p><a class="IFL" href="http://uploads.askapache.com/2009/07/apache-server-status.png"><img src="http://uploads.askapache.com/2009/07/apache-server-status-350x164.png" alt="An AskApache Plugin Upgrade to Rule them All" title="apache-server-status" width="350" height="164" class="alignnone size-medium wp-image-3070" /></a>So my blog as been rather quiet for almost a year now, and very few updates if any have been released for my Password Protection PLugin, my Google 404 Plugin, and definately not for my AskApache CrazyCache plugin, which I will be releasing last...  So for all of you who've helped me out by sending me suggestions and notifying me of errors and sticking with it...  Just wanted to <strong>say sorry about that, and thanks for all the great ideas.. </strong> Well, I've been sticking with it as well believe it our not.  I manage to get free days once in a while, and then its <strong>time to jam</strong>.</p>
 <p>I've used just about every CMS/Blog/Forum/Trac/Gallery/etc) and really didn't like a lot of the way they coded...  I could use php but I didn't KNOW php.. so I've had to learn php also, and it was tough to learn the advanced class usage and all the other language specific (but similar) constructs for php.  It was especially difficult (but fun and challenging) to program so as to be compatible with php4 and php5 (Such is WordPress).    But I kept at it, and soon you can decide for yourself what to make of it.</p>
<p>I can code in plenty of languages (bash, lua, windows .bat and vbs,  ocaml, big fan of all things shell) and can work my way through C and even sorta somewhat with assembly.  Assembly is the hardest, by far,  I'm into easy and powerful languages like Python, Javascript, perl, php, ruby, and CGI. I've used PHP for a long time to do various things,  but never to build software projects like this.  Once I noticed WordPress's core .php files and the excellent programming I wanted to try and learn hot to do it.   The WordPress code is some of the best I've seen.  It appears the way they built it was planned, and not just dreamt up while typing that I can't help but do.    Every time I read through the core code I learn a new trick or very nice way to do something.  Those guys are really good, and I think WordPress is going to dominate for a long long time.</p>


<h2>The Strategy</h2>
<p>The Password Protection (passpro) plugin has a lot of complex stuff going on, especially for a newbie to PHP and WordPress like me, so after refactoring the whole thing at least 5 times I decided to modify my approach, and wrote the AskApache Google 404 Plugin as a way to practice on a simpler piece of code, while at the same time providing a plugin of value.   Eventually I stopped thinking I could just code the whole thing in one sit-down with a stream-of-consciousness, and had to instead modularize the code and focus in on each part before moving to the next (I go without a plan because its fun, just not the most productive, but again, I'm not a programmer in the scientific sense.).</p>
<p>So I decided I had to really learn how WordPress Plugins work, filters, hooks, actions, and basically comfortability at reverse-engineering code, (Im a beginner for the last time), and so with the upcoming release of the AskApache Google 404 Plugin I have succeeded in making an incredibly stable plugin.  That way I only have to worry about what the aapasspro plugin is doing, instead of trying to fit it into a framework.  </p>


<h2>AskApache Google 404 Upgrade</h2>
<p>I think its rather unusual to develop a nice plugin like this 404 handler merely for the purpose of improving upon another plugin, but hey it worked.  As of <em>08/03/2009 14:06PM EST</em> I have about 1 hour left of finishing touches to release this upgrade.  But as you cantell by my badly edited posts, I don't have a lot of time to myself.  An hour here and there is about it.  So it could be up to 2 weeks before I actually have the time to commit the release to the repo.  On a sidenote, have you checked out <a href="http://windows7news.com/" title="Windows 7 News">Windows 7 News</a>?  I've been contracted to do some technical work for them and thought they had an excellent site.</p>
<p><a href="http://uploads.askapache.com/2009/07/askapache-google-upgrade-ss1.png"><img src="http://uploads.askapache.com/2009/07/askapache-google-upgrade-ss1-344x350.png" alt="An AskApache Plugin Upgrade to Rule them All" title="askapache-google-upgrade-ss1" width="344" height="350" class="alignnone size-medium wp-image-3139" /></a></p>
<p><a href="http://uploads.askapache.com/2009/07/askapache-google-upgrade-ss2.png"><img src="http://uploads.askapache.com/2009/07/askapache-google-upgrade-ss2-293x350.png" alt="An AskApache Plugin Upgrade to Rule them All" title="askapache-google-upgrade-ss2" width="293" height="350" class="alignnone size-medium wp-image-3138" /></a></p>
<p>But keep in mind, the 404 PLugin is just where I practice for the passpro plugin, which truly does have features that no other software like it has ever had.  I understand the technology behind this plugin, and know it would really have a great impact on improving the Web (esp. WordPress) for all of us, I've just had to learn how to make it.</p>

<h2>AskApache Password Protection</h2>
<p>Probably still a couple weeks away, this plugin is the ultimate culmination of apache hackers dreams, at least those on shared servers (who may be interested in learning how to bypass security of said servers)..  So this is something I have much too fun with doing what I like to do.. network/protocol-level security.  I've examined the source code for many software packages that I use or have used to audit a server's security, and this simple php plugin in most instances can enumerate with accuraccy most of the server's setup in about a minute.  The catch (and the file permission problems I had to find a workaround too) is that this software is launched on the server, not remotely against the server.</p>
<p>Some of the software I examined was whiskers, nessus, nmap, hping, mozilla source, wireshark, ncftp, netcat, etc..  The closest comparison to the socket-level class I've hacked together to those is wireshark.  Except that wireshark only interprets (captures) the data passing over the wire, while this class does that and in fact sends and receives the data like netcat or nmap.  Its really more similar to metasploit, and can easily be used to send hex, binary, ascii, or any type of payload to the remote or local host.</p>


<h2>The Upgrades Begin</h2>
<p>Well I started working on them a long time ago.  Both the Password Protection plugin and the Google 404 plugin needed serious work.   And I finally have it all figured out.  Essentially I would work on one and finish an upgrade, but I just wasn't happy with it and I wold start all over again, refactoring the code.   So as I put the finishing touches on those 2 plugins keep an eye out.  They are major upgrades.   I was able to meet all the goals I had for them, and came up with a lot of more improvements during the process.One of the main things I needed was a socket-level class to perform all kinds of checks and tests on.  I need this also for my crazy cache plugin, which my blog is currently using ,  and I have a 2 more really nice pplugins I use that also needed  access to a network class.  I wrote about what I was doing with fsockopen, and I've been improving on that example ever since.  I use this class to do some really powerful and exciting stuff, but you'll see it soon enough.  As an indication of 'getting it right' for the Password Protection plugin, the plugin will now work on Windows, Apache, IIS, Lighthttpd, and will even work running on a blackberry web server.  So now everyone using wordpress can at least get some security()



<p class="enote">Many of the the other improvements focus on using the fsockopen class and .htaccess tricks to basically enumerate and discover all the different capabilities of your particular server;  That way you can learn about all the features and security that are possible for your specific server, and the securty modules wi8ll be geared for that as well.  FINALLY this plugin is going to be stable, and I just cant wait to see how people react when they learn all great capability their Apache-based Server has that they didn't have a clue about.   Its amazing in that sense, and hackers will love theh way it works.. but your server admins will love it even more because its entirely 100% focused on helping you to set your site up (if you have Apache) to keep spammers out, to keep virii-serving robots and their log-hogging exploit requests and CPU/Mem robiing 404 errors off of your servers for real.  This will have a noticeable affect to whoever is running the server.   As you can tell.. I am pumped!</br></p>


<hr class="C" />
Apache is easy to configure and use, but only when you have root access.  Most people on shared and private hosting aren't even able to view the main config file, let alone execute the Apache binaries to see what features are available and what configuration is being used.<br class="C" /></p>

<p>Apache can only be influenced by the main server configs and by .htaccess files.  Not by php, not by perl, and the main configs are almost never accessible to the masses.  But .htaccess files are.  And many hosting providers allow and enable .htaccess files, a configuration file for your web server.  The advanced features and capabilities of Apache were out of reach for most of us, it just wasn't possible to enumerate or access, and most hosting providers are infamous for their lack of .htaccess (customer) support.  This plugin goes around those problems to give the power back to the people.<br class="C" /></p>y creating custom .htaccess files containing unpublished .htaccess tricks and techniques and combining that with the use of socket-level networking from WordPress (PHP) using <a href="http://www.askapache.com/php/fsockopen-socket.html">fsockopen</a>, we can effectively enumerate and discover an incredible amount of features and settings you will be able to control and use with this plugin.</p>

<p>Here are a few examples of the capabilities of this plugin, some of which I believe no other software can do..  <em>(Open source free to copy!)</em>.</p>
<ol>
<li>Current Version of Apache (<strong>Down to the API Version</strong>)</li>
<li>List of <strong>ALL Modules currently enabled</strong> by Apache (Such as Mod_Rewrite)</li>
<li>List of <strong>ALL Directives enabled by EACH enabled Module.</strong></li>
<li>Enumerate .htaccess Overrides, Context Permissions</li>
<li>Test for any builtin Handlers (like the <a href="http://uploads.askapache.com/2009/07/apache-server-status.png">status handler screenshot</a>)</li>
<li>Configure SSI (<a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-security">http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-security</a>)</li>
</ol>


<blockquote cite="http://www.askapache.com/htaccess/password-protection-plugin-status.html"><div class="inote"><cite><a href="http://www.askapache.com/htaccess/password-protection-plugin-status.html"></a></cite><p><strong>March 1, 2009</strong><br /><strong>I would focus on the method that WordPress uses</strong>.  The code they have now (2.8 bleeding-edge) still isn't where it needs to be, but this is some difficult stuff and <strong>they have a brilliant start, it'll work.. just a question of when</strong>.</p>
<p><a class="IFL" href="http://uploads.askapache.com/2009/03/apache-security-model-tall1.png"><img src="http://uploads.askapache.com/2009/03/apache-security-model-tall1-250x123.png" alt="Apache Security Model - In Color" title="apache-security-model-wide" width="250" height="123" /></a><strong>The main issue</strong> with the password protection plugin working for some people and not others is due to <a title="detailed file permission article" href="http://www.askapache.com/security/chmod-stat.html">file permission configurations</a>.  The plugin attempts to write/modify files in your blog's root directory.<br class="C" /></p></div></blockquote>
<hr class="C" />

<blockquote cite="http://www.askapache.com/htaccess/htaccess-plugin-blocks-spam-hackers-and-password-protects-blog.html"><div class="inote"><cite><a href="http://www.askapache.com/htaccess/htaccess-plugin-blocks-spam-hackers-and-password-protects-blog.html"></a></cite><p><strong>November 05, 2008</strong><br />To make a long story short, I downloaded each major release of the apache httpd source code starting at version 1.3.0 and finishing with version 2.2.11, I then compiled each version and built a HTTPD from source for all these apache versions.</p>
<div><div style="width:100px;overflow:hidden;float:left;"><ul><li>1.3.0</li><li>1.3.1</li><li>1.3.11</li><li>1.3.12</li><li>1.3.14</li><li>1.3.17</li><li>1.3.19</li><li>1.3.2</li><li>1.3.20</li><li>1.3.22</li><li>1.3.23</li><li>1.3.24</li><li>1.3.27</li><li>1.3.28</li></ul></div><div style="width:100px;overflow:hidden;float:left;"><ul><li>1.3.29</li><li>1.3.3</li><li>1.3.31</li><li>1.3.32</li><li>1.3.33</li><li>1.3.34</li><li>1.3.35</li><li>1.3.36</li><li>1.3.37</li><li>1.3.39</li><li>1.3.4</li><li>1.3.41</li><li>1.3.6</li><li>1.3.9</li></ul></div>
<div style="width:100px;overflow:hidden;float:left;"><ul><li>2.0.35</li><li>2.0.36</li><li>2.0.39</li><li>2.0.40</li><li>2.0.42</li><li>2.0.43</li><li>2.0.44</li><li>2.0.45</li><li>2.0.46</li><li>2.0.47</li><li>2.0.48</li><li>2.0.49</li><li>2.0.50</li><li>2.0.51</li></ul></div><div style="width:150px;overflow:hidden;float:left;"><ul><li>2.0.52</li><li>2.0.53</li><li>2.0.54</li><li>2.0.55</li><li>2.0.58</li><li>2.0.59</li><li>2.0.61</li><li>2.0.63</li><li>2.1.3-beta</li><li>2.1.6-alpha</li><li>2.1.7-beta</li><li>2.1.8-beta</li><li>2.1.9-beta</li></ul></div><div style="width:100px;overflow:hidden;float:left;"><ul><li>2.2.0</li><li>2.2.10</li><li>2.2.2</li><li>2.2.3</li><li>2.2.4</li><li>2.2.6</li><li>2.2.8</li><li>2.2.9</li><li><strong>2.2.10</strong></li><li><strong>2.2.11</strong></li></ul></div><br class="C" /></div>
<p>Then I went through each version and determined the compatible modules for that version, and I'm pretty confident that I was also able to find each and every directive allowed by the compatible modules for that version (including core directives).  See <a href="http://www.askapache.com/htaccess/htaccess.html#htaccess-directives">.htaccess directive list</a>.  Basically I can now test a server using a variety of methods and determine almost 100% accurately what version of Apache (down to the API) is running, what modules (and versions) are enabled, and each and every directive that is allowed or disallowed for that version.  So this is so awesome because now we can enable all sorts of additional security features.</p>
</div>
</blockquote>
<hr class="C" />




<blockquote cite="http://www.askapache.com/htaccess/htaccess.html#htaccess-modules"><cite><a href="http://www.askapache.com/htaccess/htaccess.html#htaccess-modules">Htaccess enabled Modules</a></cite><p>Here are most of the modules that come with Apache.  Each one can have new commands that can be used in .htaccess file scopes.</p>
<p><a href="http://www.askapache.com/servers/mod_actions.c.html">mod_actions</a>, <a href="http://www.askapache.com/servers/mod_alias.c.html">mod_alias</a>, <a href="http://www.askapache.com/servers/mod_asis.c.html">mod_asis</a>, <a href="http://www.askapache.com/servers/mod_auth_basic.c.html">mod_auth_basic</a>, <a href="http://www.askapache.com/servers/mod_auth_digest.c.html">mod_auth_digest</a>, <a href="http://www.askapache.com/servers/mod_authn_anon.c.html">mod_authn_anon</a>, <a href="http://www.askapache.com/servers/mod_authn_dbd.c.html">mod_authn_dbd</a>, <a href="http://www.askapache.com/servers/mod_authn_dbm.c.html">mod_authn_dbm</a>, <a href="http://www.askapache.com/servers/mod_authn_default.c.html">mod_authn_default</a>, <a href="http://www.askapache.com/servers/mod_authn_file.c.html">mod_authn_file</a>, <a href="http://www.askapache.com/servers/mod_authz_dbm.c.html">mod_authz_dbm</a>, <a href="http://www.askapache.com/servers/mod_authz_default.c.html">mod_authz_default</a>, <a href="http://www.askapache.com/servers/mod_authz_groupfile.c.html">mod_authz_groupfile</a>, <a href="http://www.askapache.com/servers/mod_authz_host.c.html">mod_authz_host</a>, <a href="http://www.askapache.com/servers/mod_authz_owner.c.html">mod_authz_owner</a>, <a href="http://www.askapache.com/servers/mod_authz_user.c.html">mod_authz_user</a>, <a href="http://www.askapache.com/servers/mod_autoindex.c.html">mod_autoindex</a>, <a href="http://www.askapache.com/servers/mod_cache.c.html">mod_cache</a>, <a href="http://www.askapache.com/servers/mod_cern_meta.c.html">mod_cern_meta</a>, <a href="http://www.askapache.com/servers/mod_cgi.c.html">mod_cgi</a>, <a href="http://www.askapache.com/servers/mod_dav.c.html">mod_dav</a>, <a href="http://www.askapache.com/servers/mod_dav_fs.c.html">mod_dav_fs</a>, <a href="http://www.askapache.com/servers/mod_dbd.c.html">mod_dbd</a>, <a href="http://www.askapache.com/servers/mod_deflate.c.html">mod_deflate</a>, <a href="http://www.askapache.com/servers/mod_dir.c.html">mod_dir</a>, <a href="http://www.askapache.com/servers/mod_disk_cache.c.html">mod_disk_cache</a>, <a href="http://www.askapache.com/servers/mod_dumpio.c.html">mod_dumpio</a>, <a href="http://www.askapache.com/servers/mod_env.c.html">mod_env</a>, <a href="http://www.askapache.com/servers/mod_expires.c.html">mod_expires</a>, <a href="http://www.askapache.com/servers/mod_ext_filter.c.html">mod_ext_filter</a>, <a href="http://www.askapache.com/servers/mod_file_cache.c.html">mod_file_cache</a>, <a href="http://www.askapache.com/servers/mod_filter.c.html">mod_filter</a>, <a href="http://www.askapache.com/servers/mod_headers.c.html">mod_headers</a>, <a href="http://www.askapache.com/servers/mod_ident.c.html">mod_ident</a>, <a href="http://www.askapache.com/servers/mod_imagemap.c.html">mod_imagemap</a>, <a href="http://www.askapache.com/servers/mod_include.c.html">mod_include</a>, <a href="http://www.askapache.com/servers/mod_info.c.html">mod_info</a>, <a href="http://www.askapache.com/servers/mod_log_config.c.html">mod_log_config</a>, <a href="http://www.askapache.com/servers/mod_log_forensic.c.html">mod_log_forensic</a>, <a href="http://www.askapache.com/servers/mod_logio.c.html">mod_logio</a>, <a href="http://www.askapache.com/servers/mod_mem_cache.c.html">mod_mem_cache</a>, <a href="http://www.askapache.com/servers/mod_mime.c.html">mod_mime</a>, <a href="http://www.askapache.com/servers/mod_mime_magic.c.html">mod_mime_magic</a>, <a href="http://www.askapache.com/servers/mod_negotiation.c.html">mod_negotiation</a>, <a href="http://www.askapache.com/servers/mod_proxy.c.html">mod_proxy</a>, <a href="http://www.askapache.com/servers/mod_proxy_ajp.c.html">mod_proxy_ajp</a>, <a href="http://www.askapache.com/servers/mod_proxy_balancer.c.html">mod_proxy_balancer</a>, <a href="http://www.askapache.com/servers/mod_proxy_connect.c.html">mod_proxy_connect</a>, <a href="http://www.askapache.com/servers/mod_proxy_ftp.c.html">mod_proxy_ftp</a>, <a href="http://www.askapache.com/servers/mod_proxy_http.c.html">mod_proxy_http</a>, <a href="http://www.askapache.com/servers/mod_rewrite.c.html">mod_rewrite</a>, <a href="http://www.askapache.com/servers/mod_setenvif.c.html">mod_setenvif</a>, <a href="http://www.askapache.com/servers/mod_speling.c.html">mod_speling</a>, <a href="http://www.askapache.com/servers/mod_ssl.c.html">mod_ssl</a>, <a href="http://www.askapache.com/servers/mod_status.c.html">mod_status</a>, <a href="http://www.askapache.com/servers/mod_substitute.c.html">mod_substitute</a>, <a href="http://www.askapache.com/servers/mod_unique_id.c.html">mod_unique_id</a>, <a href="http://www.askapache.com/servers/mod_userdir.c.html">mod_userdir</a>, <a href="http://www.askapache.com/servers/mod_usertrack.c.html">mod_usertrack</a>, <a href="http://www.askapache.com/servers/mod_version.c.html">mod_version</a>, <a href="http://www.askapache.com/servers/mod_vhost_alias.c.html">mod_vhost_alias</a></p></blockquote>
<hr class="C" /><hr class="C" />




<h2>Debugging HTTP protocol</h2>
<p>Check this out!  I'm particularly happy about this feature, which outputs an exact trace of any requests made by the plugin (such as during the testing phase) by saving the actual raw data sent out on the wire using fsockopen, RX and TX.  This is useful for a number of reasons, viewing your headers, finding Redirect Loops, testing RewriteRules, and following the request hop-by-hop for debugging.  The below example shows 2 requests for 2 URIs.  The first URI is protected using Digest Authentication, the 2nd shows Basic.</p>
<pre> ______________
|  RAW TRACE   |
==================================================================================================================================
GET /htaccess/index.txt?testing=query HTTP/1.1
Host: www.askapache.com
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1) AA_PassPro/1.9 (http://www.askapache.com/)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://www.askapache.com/
&nbsp;
HTTP/1.1 401 Authorization Required
Date: Wed, 22 Jul 2009 06:29:58 GMT
Server: Apache
WWW-Authenticate: Digest realm="do or die", nonce="03328f3ec7c7b", algorithm=MD5, domain="/", qop="auth"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 882
Connection: close
Content-Type: text/html; charset=UTF-8
&nbsp;
GET /htaccess/index.txt?testing=query HTTP/1.1
Host: www.askapache.com
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1) AA_PassPro/1.9 (http://www.askapache.com/)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://www.askapache.com/
Authorization: Digest username="test",realm="do or die",nonce="03328f3ec7c7b",uri="/htaccess/index.txt?testing=query",
cnonce="82d057852a9dc497",nc=00000001,algorithm=MD5,response="9d476e9ea3",qop="auth"
&nbsp;
HTTP/1.1 200 OK
Date: Wed, 22 Jul 2009 06:29:58 GMT
Server: Apache
Authentication-Info: rspauth="9051b01ee26dd62b3e2b40dada694f45", cnonce="82d057852a9dc497", nc=00000001, qop=auth
Last-Modified: Tue, 21 Jul 2009 23:56:00 GMT
Accept-Ranges: bytes
Cache-Control: max-age=3600
Expires: Wed, 22 Jul 2009 07:29:58 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 27
Connection: close
Content-Type: text/plain; charset=UTF-8
```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````
&nbsp;
 ______________
|  RAW TRACE   |
==================================================================================================================================
GET /htaccess/po.txt?testing=query HTTP/1.1
Host: www.askapache.com
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1) AA_PassPro/1.9 (http://www.askapache.com/)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://www.askapache.com/
&nbsp;
HTTP/1.1 401 Authorization Required
Date: Wed, 22 Jul 2009 06:29:58 GMT
Server: Apache
WWW-Authenticate: Basic realm="Po Pimping"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 878
Connection: close
Content-Type: text/html; charset=UTF-8
&nbsp;
GET /htaccess/po.txt?testing=query HTTP/1.1
Host: www.askapache.com
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1) AA_PassPro/1.9 (http://www.askapache.com/)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://www.askapache.com/
Authorization: Basic adfAGAltcA==
&nbsp;
HTTP/1.1 200 OK
Date: Wed, 22 Jul 2009 06:29:58 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 05:54:39 GMT
Accept-Ranges: bytes
Cache-Control: max-age=3600
Expires: Wed, 22 Jul 2009 07:29:58 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 27
Connection: close
Content-Type: text/plain; charset=UTF-8
```````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````</pre>














<h2>.htaccess Directives</h2>
<p>AcceptFilter, AcceptMutex, AcceptPathInfo, AccessFileName, Action, AddAlt, AddAltByEncoding, AddAltByType, AddCharset, AddDefaultCharset, AddDescription, AddEncoding, AddHandler, AddIcon, AddIconByEncoding, AddIconByType, AddInputFilter, AddLanguage, AddModuleInfo, AddOutputFilter, AddOutputFilterByType, AddType, Alias, AliasMatch, AllowCONNECT, AllowEncodedSlashes, AllowOverride, Anonymous, Anonymous_Authoritative, Anonymous_LogEmail, Anonymous_MustGiveEmail, Anonymous_NoUserID, Anonymous_NoUserId, Anonymous_VerifyEmail, AssignUserId, AuthAuthoritative, AuthBasicAuthoritative, AuthBasicProvider, AuthDBDUserPWQuery, AuthDBDUserRealmQuery, AuthDBM, AuthDBMAuthoritative, AuthDBMGroupFile, AuthDBMType, AuthDBMUserFile, AuthDefaultAuthoritative, AuthDigestAlgorithm, AuthDigestDomain, AuthDigestFile, AuthDigestGroupFile, AuthDigestNcCheck, AuthDigestNonceFormat, AuthDigestNonceLifetime, AuthDigestProvider, AuthDigestQop, AuthDigestShmemSize, AuthGroupFile, AuthLDAPAuthzEnabled, AuthLDAPBindDN, AuthLDAPBindON, AuthLDAPBindPassword, AuthLDAPCharsetConfig, AuthLDAPCompareDNOnServer, AuthLDAPDereferenceAliases, AuthLDAPEnabled, AuthLDAPFrontPageHack, AuthLDAPGroupAttribute, AuthLDAPGroupAttributeIsDN, AuthLDAPRemoteUserAttribute, AuthLDAPRemoteUserIsDN, AuthLDAPStartTLS, AuthLDAPURL, AuthLDAPUrl, AuthName, AuthType, AuthUserFile, AuthzDBMAuthoritative, AuthzDBMType, AuthzDefaultAuthoritative, AuthzGroupFileAuthoritative, AuthzLDAPAuthoritative, AuthzOwnerAuthoritative, AuthzUserAuthoritative, BS2000Account, BalancerMember, BrowserMatch, BrowserMatchNoCase, BufferedLogs, CGIMapExtension, CacheDefaultExpire, CacheDirLength, CacheDirLevels, CacheDisable, CacheEnable, CacheExpiryCheck, CacheFile, CacheForceCompletion, CacheGcClean, CacheGcDaily, CacheGcInterval, CacheGcMemUsage, CacheGcUnused, CacheIgnoreCacheControl, CacheIgnoreHeaders, CacheIgnoreNoLastMod, CacheLastModifiedFactor, CacheMaxExpire, CacheMaxFileSize, CacheMaxStreamingBuffer, CacheMinFileSize, CacheNegotiatedDocs, CacheRoot, CacheSize, CacheStoreNoStore, CacheStorePrivate, CacheTimeMargin, CharsetDefault, CharsetOptions, CharsetSourceEnc, CheckCaseOnly, CheckSpelling, ChildPerUserId, ContentDigest, CookieDomain, CookieExpires, CookieLog, CookieName, CookieStyle, CookieTracking, CoreDumpDirectory, CustomLog, DAV, DAVDepthInfinity, DAVGenericLockDB, DAVMinTimeout, DBDExptime, DBDKeep, DBDMax, DBDMin, DBDParams, DBDPersist, DBDPrepareSQL, DBDriver, Dav, DavDepthInfinity, DavGenericLockDB, DavLockDB, DavMinTimeout, DefaultIcon, DefaultLanguage, DefaultType, DeflateBufferSize, DeflateCompressionLevel, DeflateFilterNote, DeflateMemLevel, DeflateWindowSize, Directory, DirectoryIndex, DirectoryMatch, DirectorySlash, DocumentRoot, DumpIOInput, DumpIOOutput, EnableExceptionHook, EnableMMAP, EnableSendfile, ErrorDocument, ErrorLog, Example, ExpiresActive, ExpiresByType, ExpiresDefault, ExtFilterDefine, ExtFilterOptions, ExtendedStatus, FancyIndexing, FileETag, Files, FilesMatch, FilterChain, FilterDeclare, FilterProtocol, FilterProvider, FilterTrace, ForceLanguagePriority, ForceType, ForensicLog, GprofDir, GracefulShutdownTimeout, Group, Header, HeaderName, HostNameLookups, HostnameLookups, ISAIPFakeAsync, ISAPIAppendLogToErrors, ISAPIAppendLogToQuery, ISAPICacheFile, ISAPIFakeAsync, ISAPILogNotSupported, ISAPIReadAheadBuffer, IdentityCheck, IdentityCheckTimeout, IfDefine, IfModule, IfVersion, ImapBase, ImapDefault, ImapMenu, Include, IndexIgnore, IndexOptions, IndexOrderDefault, IndexStyleSheet, KeepAlive, KeepAliveTimeout, LDAPCacheEntries, LDAPCacheTTL, LDAPCertDBPath, LDAPConnectionTimeout, LDAPOpCacheEntries, LDAPOpCacheTTL, LDAPSharedCacheFile, LDAPSharedCacheSize, LDAPTrustedClientCert, LDAPTrustedGlobalCert, LDAPTrustedMode, LDAPVerifyServerCert, LanguagePriority, Limit, LimitExcept, LimitInternalRecursion, LimitRequestBody, LimitRequestFields, LimitRequestFieldsize, LimitRequestLine, LimitXMLRequestBody, Listen, ListenBacklog, LoadFile, LoadModule, Location, LocationMatch, LockFile, LogFormat, LogLevel, MCacheMaxObjectCount, MCacheMaxObjectSize, MCacheMaxStreamingBuffer, MCacheMinObjectSize, MCacheRemovalAlgorithm, MCacheSize, MMapFile, MaxClients, MaxKeepAliveRequests, MaxMemFree, MaxRequestsPerChild, MaxSpareServers, MaxSpareThreads, MaxSpareThreadsPerChild, MaxThreads, MetaDir, MetaFiles, MetaSuffix, MimeMagicFile, MinSpareServers, MinSpareThreads, ModMimeUsePathInfo, MultiviewsMatch, NWSSLTrustedCerts, NWSSLUpgradeable, NameVirtualHost, NoProxy, NumServers, Options, PassEnv, PerlAccessHandler, PerlAuthenHandler, PerlAuthzHandler, PerlChildExitHandler, PerlChildInitHandler, PerlCleanupHandler, PerlDispatchHandler, PerlFixupHandler, PerlFreshRestart, PerlHandler, PerlHeaderParserHandler, PerlInitHandler, PerlLogHandler, PerlModule, PerlPassEnv, PerlPostReadRequestHandler, PerlRequire, PerlRestartHandler, PerlSendHeader, PerlSetEnv, PerlSetVar, PerlSetupEnv, PerlTaintCheck, PerlTransHandler, PerlTypeHandler, PerlWarn, PidFile, Port, Protocol, ProtocolEcho, Proxy, ProxyBadHeader, ProxyBlock, ProxyDomain, ProxyErrorOverride, ProxyFtpDirCharset, ProxyIOBufferSize, ProxyMatch, ProxyMaxForwards, ProxyPass, ProxyPassInterpolateEnv, ProxyPassMatch, ProxyPassReverse, ProxyPassReverseCookieDomain, ProxyPassReverseCookiePath, ProxyPreserveHost, ProxyReceiveBufferSize, ProxyRemote, ProxyRemoteMatch, ProxyRequests, ProxySet, ProxyStatus, ProxyTimeout, ProxyVia, RLimitCPU, RLimitMEM, RLimitNPROC, ReadmeName, Redirect, RedirectMatch, RedirectPermanent, RedirectTemp, RemoveCharset, RemoveEncoding, RemoveHandler, RemoveInputFilter, RemoveLanguage, RemoveOutputFilter, RemoveType, RequestHeader, Require, RewriteBase, RewriteCond, RewriteEngine, RewriteLock, RewriteLog, RewriteLogLevel, RewriteMap, RewriteOptions, RewriteRule, SSIAccessEnable, SSIEndTag, SSIErrorMsg, SSIStartTag, SSITimeFormat, SSIUndefinedEcho, SSLCACertificateFile, SSLCACertificatePath, SSLCADNRequestFile, SSLCADNRequestPath, SSLCARevocationFile, SSLCARevocationPath, SSLCertificateChainFile, SSLCertificateFile, SSLCertificateKeyFile, SSLCipherSuite, SSLCryptoDevice, SSLEngine, SSLHonorCipherOrder, SSLLog, SSLLogLevel, SSLMutex, SSLOptions, SSLPassPhraseDialog, SSLProtocol, SSLProxyCACertificateFile, SSLProxyCACertificatePath, SSLProxyCARevocationFile, SSLProxyCARevocationPath, SSLProxyCipherSuite, SSLProxyEngine, SSLProxyMachineCertificateFile, SSLProxyMachineCertificatePath, SSLProxyProtocol, SSLProxyVerify, SSLProxyVerifyDepth, SSLRandomSeed, SSLRequire, SSLRequireSSL, SSLSessionCache, SSLSessionCacheTimeout, SSLUserName, SSLVerifyClient, SSLVerifyDepth, Satisfy, ScoreBoardFile, Script, ScriptAlias, ScriptAliasMatch, ScriptInterpreterSource, ScriptLog, ScriptLogBuffer, ScriptLogLength, ScriptStock, SecureListen, SendBufferSize, ServerAdmin, ServerAlias, ServerLimit, ServerName, ServerPath, ServerRoot, ServerSignature, ServerTokens, SetEnv, SetEnvIf, SetEnvIfNoCase, SetHandler, SetInputFilter, SetOutputFilter, StartServers, StartThreads, Substitute, SuexecUserGroup, ThreadLimit, ThreadStackSize, ThreadsPerChild, TimeOut, Timeout, TraceEnable, TransferLog, TypeAuthDBMUserFile, TypesConfig, UnsetEnv, UseCanonicalName, UseCanonicalPhysicalPort, User, UserDir, VirtualDocumentRoot, VirtualDocumentRootIP, VirtualHost, VirtualScriptAlias, VirtualScriptAliasIP, Win32DisableAcceptEx, XBitHack, allow, deny, order, php_admin_flag, php_admin_value, php_flag, php_value</p>



<p class="anote">You can view the <a href="http://www.askapache.com/htaccess/htaccess-security-block-spam-hackers.html">plugins home page</a>, <a href="http://www.askapache.com/wordpress/htaccess-password-protect.html#aadl">old</a>, or <a href="http://wordpress.org/extend/plugins/askapache-password-protect/">view it on the wordpress.org site</a>.</p><p><a href="http://www.askapache.com/wordpress/an-askapache-plugin-upgrade-to-rule-them-all.html"></a><a href="http://www.askapache.com/wordpress/an-askapache-plugin-upgrade-to-rule-them-all.html">An AskApache Plugin Upgrade to Rule them All</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/wordpress/an-askapache-plugin-upgrade-to-rule-them-all.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SSI in Htaccess for ErrorDocuments, DirectoryIndexing, SEO</title>
		<link>http://www.askapache.com/htaccess/advanced-htaccess-ssi.html</link>
		<comments>http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#comments</comments>
		<pubDate>Mon, 09 Mar 2009 08:02:02 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Htaccess]]></category>

		<guid isPermaLink="false">http://www.askapache.com/?p=2236</guid>
		<description><![CDATA[<p><a class="IFL" href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-directory" title="Improved Directory Listings and SEO"><img src="http://uploads.askapache.com/2009/03/htaccess-directory-index-116x76.png" alt="htaccess directory indexing" title="Improved Directory Listings and SEO" width="116" height="76" /></a><a class="IFL" style="border-bottom:15px solid #FFF;" href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-error" title="Enhanced Error Pages"><img src="http://uploads.askapache.com/2009/03/example-errordocument-116x67.png" alt="ErrorDocument from .htaccess" title="Enhanced Error Pages" width="116" height="67" /></a>3-Part article covering practical implementation of 3 advanced .htaccess features.   Discover an easy way to <a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-directory">boost your SEO the <dfn title="Design your site for Humans">AskApache way</dfn></a> (<em>focus on visitors</em>), a tip you might keep and use for life. <a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-security">Get some cool security tricks</a> to use against spammers, crackers, and other nefarious sorts.  <a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-error">Take your site's error handling to the next level</a>, enhanced ErrorDocuments that go beyond 404's. <br class="C" /></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html"></a><a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html"><cite>AskApache.com</cite></a></p><p><acronym title="Server Side Includes">SSI</acronym>, Server Side Includes, can be very useful to webmasters and visitors alike.  They are easily set up in an .htaccess file and require little to no maintaining.. the term "Set it and Forget it" applies here.  Before we look at how to implement SSI, and dig into the Apache module that makes them possible, lets look at few uses for SSI so you can quickly determine if you would like to read further.</p>
<ol>
	<li><a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-directory">Improved Directory Listings and SEO</a></li>
	<li><a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-error">Enhanced Error Pages</a></li>
	<li><a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html#htaccess-ssi-security">Dealing with Spam and Website Attacks</a></li>
</ol>



<hr class="C" />

<h2><a name="htaccess-ssi-directory" id="htaccess-ssi-directory"></a>Improved Directory Listings and SEO</h2>
<p><a class="IFL" href="http://uploads.askapache.com/2009/03/htaccess-directory-index.png" title="htaccess directory indexing"><img src="http://uploads.askapache.com/2009/03/htaccess-directory-index-116x76.png" alt="htaccess directory indexing" title="htaccess directory indexing" /></a>One way that I use SSI is for improved Directory Listing.  Anyone here like SEO?  Check out my <a href="http://uploads.askapache.com/">WordPress uploads directory</a> to get an idea.  Basically I can customize the header and footer of each directory..  Pretty sweet, thanks Apache!<br class="C" /></p>
<p>In your <code>/uploads/.htaccess</code></p>
<pre># turn on auto-indexing and turn off SSI&#039;s ability to exec
Options None
Options SymLinksIfOwnerMatch Indexes IncludesNOEXEC
&nbsp;
# we need to make sure files are displayed when requested, not executed or parsed
AddType text/plain .ini .sh .bsh .bash .csh .var .asc .md5 .sha .sha1 .cgi .pl .php .inc .asp .exe .bin
DefaultType text/plain
&nbsp;
# turn on auto-indexing, with askapache-optimized options
IndexOptions FancyIndexing SuppressColumnSorting SuppressHTMLPreamble IconHeight=22 IconWidth=20
IndexOptions IgnoreClient NameWidth=40 DescriptionWidth=* XHTML FoldersFirst
&nbsp;
# don&#039;t show these files and folders
IndexIgnore .htaccess .ht* *_notes *.log feed inc HEADER.html FOOTER.html feed*.gif
&nbsp;
# the SSI files used for the header and footer
HeaderName /ssi/HEADER.html
ReadmeName /ssi/FOOTER.html
&nbsp;
# used to determine the time and for SSI output
SetEnv TZ America/Indianapolis
SetEnv SERVER_ADMIN webmaster@askapache.com</pre>

<p>In your <code>/ssi/.htaccess</code></p>
<pre># makes files ending in .html be filtered through the INCLUDES filter before being sent to client
AddOutputFilter Includes html</pre>

<p>My <code>HEADER.html</code></p>
<pre>&lt;!--#set var="PAGETITLE" value="-- static.askapache.com" --&gt;
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;&lt;!--#echo encoding="none" var="REQUEST_URI" --&gt; &lt;!--#echo encoding="none" var="PAGETITLE" --&gt;&lt;/title&gt;
  &lt;meta http-equiv="content-type" content="text/html; charset=UTF-8" /&gt;
  &lt;link rel="stylesheet" href="http://static.askapache.com/c/error.css" /&gt;
  &lt;link rev="made" href="mailto:&lt;!--#echo encoding="url" var="SERVER_ADMIN" --&gt;" /&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;&lt;a href="http://www.askapache.com/" title="AskApache Home" accesskey="1"&gt;
&lt;img src="http://www.askapache.com/nlogo.jpg" height="75" alt="AskApache" /&gt;
&lt;/a&gt; &lt;!--#echo encoding="url" var="REQUEST_URI" --&gt; &lt;!--#echo encoding="none" var="PAGETITLE" --&gt;&lt;/h1&gt;
&lt;hr /&gt;</pre>

<p>My <code>FOOTER.html</code></p>
<pre>&lt;p&gt;Find the information you are looking for on the &lt;a href="http://www.askapache.com/"&gt;AskApache Home page&lt;/a&gt;
or the &lt;a href="http://www.askapache.com/search&lt;!--#echo encoding="url" var="REQUEST_URI" --&gt;"&gt;
AskApache search page&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;address&gt;
  &lt;small&gt;$Id:&lt;!--#echo encoding="none" var="UNIQUE_ID" --&gt; E:&lt;!--#echo encoding="none" var="REDIRECT_STATUS" --&gt;,v 1.30
&lt;!--#config timefmt="%c" --&gt;&lt;!--#echo var="DATE_LOCAL" --&gt;&lt;/small&gt;&lt;br /&gt;
  &lt;small&gt;&lt;!--#echo var="SERVER_SOFTWARE" --&gt;&lt;/small&gt;&lt;br /&gt;&lt;br /&gt;
  static.askapache.com -- AskApache | &lt;a href="http://www.askapache.com/about/"&gt;Webmaster&lt;/a&gt;
| Copyright &amp;copy; 2009 AskApache&lt;br /&gt;
&lt;/address&gt;
&lt;!--#if expr="$REMOTE_ADDR = 10.10.10.10" --&gt;
&lt;pre &gt;&lt;!--#printenv --&gt;&lt;/ pre&gt;
&lt;!--#endif --&gt;
&lt;script src="http://static.askapache.com/j/apache-0780.js" type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;var pageTracker = _gat._getTracker("UA-7"+"321"+"53-38");
pageTracker._initData();pageTracker._trackPageview();&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>



<h2><a name="htaccess-ssi-error id="htaccess-ssi-error></a>Enhanced Error Pages</h2>
<p><a class="IFL" href="http://uploads.askapache.com/2009/03/example-errordocument.png" title="htaccess-errordocument"><img src="http://uploads.askapache.com/2009/03/example-errordocument-116x67.png" alt="ErrorDocument from .htaccess" title="htaccess-errordocument" /></a>If you are using WordPress, I'm sure you are using my <a href="http://www.askapache.com/seo/404-google-wordpress-plugin.html">AskApache Google 404 Plugin</a>, but whatever your <a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html">error pages</a> may be, using SSI you can make them better.  My 404 Error Page is handled by WordPress and PHP, but all of my other error pages (codes 4xx to 5xx) are handled using SSI.  You can check out any of them: <a href="http://www.askapache.com/show-error-400">/show-error-400</a>, <a href="http://www.askapache.com/show-error-400">/show-error-403</a>, <a href="http://www.askapache.com/show-error-500">/show-error-503</a>, etc..<br class="C" /></p>
<p>Notice the email note which has the subject prefilled?  Thats one of the main uses for SSI, you can add forms to your errordocuments and get notified of problems which mean you can fix them.</p>

<p>Add this to your <code>/.htaccess</code> for each <code>ErrorDocument</code> you make.</p>
<pre>ErrorDocument 503 /errordocs/503.html</pre>

<p>My <code>/errordocs/.htaccess</code></p>
<pre># turn on symlinks for rewrites and turn off SSI&#039;s ability to exec
Options None
Options SymLinksIfOwnerMatch IncludesNOEXEC
&nbsp;
# makes files ending in .html be filtered through the INCLUDES filter before being sent to client
AddOutputFilter Includes html
&nbsp;
# this internal apache variable prevents your errordocs from allowing keep-alive connections
SetEnv nokeepalive
&nbsp;
# used to determine the time and for SSI output
SetEnv TZ America/Indianapolis
SetEnv SERVER_ADMIN webmaster@askapache.com</pre>

<p>My <code>/errordocs/503.html</code></p>
<pre>&lt;!--#set var="TITLE" value="Service Temporarily Unavailable" --&gt;
&lt;!--#include virtual="/errordocs/TOP.html" --&gt;
&lt;p&gt;The server is temporarily unable to service your
request due to &lt;strong&gt;maintenance downtime&lt;/strong&gt;
or super-crazy-extreme capacity problems. Please try
again later... Or &lt;a href="mailto:&lt;!--#echo encoding="url" var="SERVER_ADMIN" --&gt;"&gt;send me an email&lt;/a&gt; and let me know about it..&lt;/p&gt;
&lt;!--#include virtual="/errordocs/BOTTOM.html" --&gt;</pre>

<p>My <code>/errordocs/TOP.html</code></p>
<pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;&lt;!--#echo encoding="none" var="REQUEST_URI" --&gt; &lt;!--#echo encoding="none" var="TITLE" --&gt;&lt;/title&gt;
  &lt;meta http-equiv="content-type" content="text/html; charset=UTF-8" /&gt;
  &lt;link rel="stylesheet" href="http://static.askapache.com/c/error.css" /&gt;
  &lt;link rev="made" href="mailto:&lt;!--#echo encoding="url" var="SERVER_ADMIN" --&gt;" /&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;&lt;a href="http://www.askapache.com/" title="AskApache Home" accesskey="1"&gt;&lt;img src="http://www.askapache.com/nlogo.jpg" height="75" alt="AskApache" /&gt;
&lt;/a&gt; &lt;!--#echo encoding="url" var="REQUEST_URI" --&gt; &lt;!--#echo encoding="none" var="TITLE" --&gt;&lt;/h1&gt;
&lt;hr /&gt;</pre>


<p>My <code>/errordocs/BOTTOM.html</code></p>
<pre>&lt;p&gt;If this should not be an error please &lt;a href="mailto:webmaster@askapache.com?subject=ID#&lt;!--#echo encoding="none" var="UNIQUE_ID" --&gt;"&gt;email&lt;/a&gt; me right away.&lt;/p&gt;
&lt;!--#if expr="$HTTP_REFERER" --&gt;
&lt;p&gt;You came from &lt;!--#echo var="HTTP_REFERER"--&gt;&lt;/p&gt;
&lt;!--#endif --&gt;
&lt;p&gt;If you still have a question, please try to find the information you are looking
for on the &lt;a href="http://www.askapache.com/"&gt;AskApache Home page&lt;/a&gt; or
the &lt;a href="http://www.askapache.com/search/"&gt;AskApache search page&lt;/a&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;address&gt;
  &lt;a href="http://www.askapache.com/about/"&gt;Webmaster&lt;/a&gt;
  $Id:&lt;!--#echo encoding="none" var="UNIQUE_ID" --&gt; Error-&lt;!--#echo encoding="none" var="REDIRECT_STATUS" --&gt;,v 1.30 &lt;!--#config timefmt="%c" --&gt;&lt;!--#echo var="DATE_LOCAL" --&gt;&lt;br /&gt;
  &lt;!--#echo var="SERVER_SOFTWARE" --&gt;
&lt;/address&gt;
&lt;!--#if expr="$REMOTE_ADDR = 10.10.10.10" --&gt;
&lt;pre &gt;&lt;!--#printenv --&gt;&lt;/ pre&gt;
&lt;!--#endif --&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>


<h2><a name="htaccess-ssi-security" id="htaccess-ssi-security"></a>Dealing with Spam and Website Attacks</h2>
<p><a class="IFL" href="http://uploads.askapache.com/2009/03/htaccess-f-off.png" title="htaccess f-off"><img src="http://uploads.askapache.com/2009/03/htaccess-f-off-350x273.png" alt="htaccess SSI to scare spammers and crackers" title="htaccess f-off" /></a>Say you are using some nice <a href="http://www.askapache.com/htaccess/htaccess-plugin-blocks-spam-hackers-and-password-protects-blog.html">.htaccess rewrite</a> rules to block offending bots, web scrapers, and other nefarious net characters.  Instead of just sending a 403 Denied, you could send them to be handled by an SSI document that could do any number of things.. From adding the offending bot's IP address to the .htaccess Deny List (blacklisting), emailing you with an alert, emailing the IP Block Owner, executing a denial-of-service response ala <a href="http://www.xav.com/scripts/guardian/help/1013.html">guardian</a> (<em>script will return an artificially high Content-Length, and will then spoon-feed content bytes back to the client at a rate of one byte per second, for single-threaded or fixed-threadpool clients, this will hang all of their requests and render the attack inoperable</em>), or just output a frightening looking message which usually does the trick if the bot is humanoid.<br class="C" /></p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\?\=?(http|ftp|ssl|https):/.*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\?\?.*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.(asp|ini|dll).*\ HTTP/ [NC]
RewriteRule .* - [F]
&nbsp;
ErrorDocument 403 /errordocs/f-off.html</pre>

<p>Example <code>/errordocs/f-off.html</code>  <a href="http://static.askapache.com/f-off">View it Live</a> (<em>Not Responsible for mental or physical harm caused by fright</em>)</p>
<pre>&lt;html&gt;&lt;head&gt;&lt;title&gt;WARNING &lt;!--#echo encoding="none" var="REMOTE_ADDR" --&gt;
- SECURITY TEAM ALERTED&lt;/title&gt;&lt;/head&gt;&lt;body&gt;
&lt;h2&gt;ATTENTION &lt;!--#echo encoding="none" var="REMOTE_ADDR" --&gt;&lt;/h2&gt;
&lt;p&gt;You have been flagged by our system as a potential threat.&lt;/p&gt;
&lt;p&gt;This request has been logged and the Security Team has been notified.&lt;br /&gt;
Repeated attempts from IP address &lt;strong&gt;&lt;!--#echo encoding="none" var="REMOTE_ADDR" --&gt;&lt;/strong&gt; will result &lt;br /&gt;
in the IP automatically being &lt;strong&gt;blacklisted&lt;/strong&gt; on this server&lt;br /&gt;
and sent to blacklists around the world.  Additionally, the Security Team&lt;br /&gt;
WILL alert the IP Address Block Owner and/or contact the authorities.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&nbsp;
&lt;h3&gt;LOGGED INFORMATION FROM THIS REQUEST&lt;/h3&gt;
&lt; pre&gt;
REMOTE_ADDR   :  &lt;!--#echo encoding="none" var="REMOTE_ADDR" --&gt;
REMOTE_PORT   :  &lt;!--#echo encoding="none" var="REMOTE_PORT" --&gt;
REQUEST_METHOD:  &lt;!--#echo encoding="none" var="REQUEST_METHOD" --&gt;&lt;!--#if expr="$HTTP_REFERER"
--&gt;
REFERER       :  &lt;!--#echo encoding="url" var="HTTP_REFERER" --&gt;&lt;!--#endif
--&gt;
REQUEST_URI   :  &lt;!--#echo encoding="url" var="REQUEST_URI" --&gt;&lt;!--#if expr="$HTTP_USER_AGENT"
--&gt;
USER_AGENT    :&lt;/ pre&gt;
&lt; pre style="white-space:normal;margin-left:150px;max-width:80%;"&gt;  &lt;!--#echo encoding="none" var="HTTP_USER_AGENT" --&gt;
&lt;/ pre&gt;
&lt; pre&gt;&lt;!--#endif
--&gt;&lt;!--#if expr="$HTTP_COOKIE"
--&gt;
COOKIES       :&lt;/ pre&gt;
&lt; pre style="white-space:normal;margin-left:150px;max-width:80%;"&gt;  &lt;!--#echo encoding="none" var="HTTP_COOKIE" --&gt;
&lt;/ pre&gt;
&lt; pre&gt;&lt;!--#endif
--&gt;&lt;!--#if expr="$QUERY_STRING"
--&gt;
QUERY_STRING  :  &lt;!--#echo encoding="url" var="QUERY_STRING" --&gt;&lt;!--#endif
--&gt;
&lt;/ pre&gt;&lt;/body&gt;&lt;/html&gt;</pre>

<hr class="C" />



<h2>Server Side Includes Detailed Info</h2>
<p>Ok now that we have the real-world usage out of the way, lets dig in a bit to the actual module <a style="color:#222;" href='http://static.askapache.com/servers/mod_include.c'>mod_include</a>, which if you want you can <a href="http://static.askapache.com/servers/mod_include.c.html">view the source code here</a>.</p>

<h3>Enabling Server-Side Includes</h3>
<p>Server Side Includes are implemented by the INCLUDES filter.  For backwards compatibility, the server-parsed handler also activates the INCLUDES filter. As well, Apache will activate the INCLUDES filter for any document with mime type text/x-server-parsed-html or text/x-server-parsed-html3 (and the resulting output will have the mime type text/html).  If documents containing server-side include directives are given the extension .shtml, the following directives will make Apache parse them and assign the resulting document the mime type of text/html:</p>
<pre>AddType text/html .shtml
AddOutputFilter INCLUDES .shtml</pre>
<p>The following directive must be given for the directories containing the shtml files (typically in a <directory> section, but this directive is also valid in <a href="http://www.askapache.com/htaccess/htaccess.html">.htaccess files</a> if AllowOverride Options is set):</p>
<pre>Options +Includes</pre>

<h3>Server-Side Include Directives</h3>
<p>These are the Directives allowed in .htaccess files that are handled by <a href="http://httpd.apache.org/docs/1.3/mod/mod_include.html">mod_include</a>.  Note that other modules may add additional directives, for instance the <code>exec</code> SSI Directive is supplied by <a href="http://httpd.apache.org/docs/trunk/mod/mod_cgi.html">mod_cgi</a>.  This is how mod_cgi registers with mod_include to provide processing of the <code>exec</code> directive.  This is the code required to handle the "exec" SSI directive.</p>
<pre>cgi_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
cgi_pfn_reg_with_ssi("exec", handle_exec);
static const char * const aszPre[] = { "mod_include.c", NULL };</pre>
<dl>
<dt><code>config</code></dt>
<dd>Controls various aspects of the parsing.</p>
<pre>&lt;!--#config [timefmt="..."] [sizefmt="..."] [errmsg="..."] --&gt;
&lt;!--#config [echomsg="..."] --&gt;
&lt;!--#config errmsg="[It appears that you don&#039;t know how to use SSI]" --&gt;</pre>
<dl>
<dt><code>echomsg</code></dt>
<dd>(<em>since 2.1</em>) The value is a message that is sent back to the client if the <code>&lt;a href="#element.echo"&gt;echo&lt;/a&gt;</code> element attempts to echo an undefined variable. This overrides any <code class='directive'>&lt;a href="#ssiundefinedecho"&gt;SSIUndefinedEcho&lt;/a&gt;</code> directives.</dd>
<dt><code>errmsg</code></dt>
<dd>The value is a message that is sent back to the client if an error occurs while parsing the document. This overrides any <code class='directive'>&lt;a href="#ssierrormsg"&gt;SSIErrorMsg&lt;/a&gt;</code> directives.</dd>
<dt><code>sizefmt</code></dt>
<dd>The value sets the format to be used which displaying the size of a file. Valid values are <code>bytes</code> for a count in bytes, or <code>abbrev</code> for a count in Kb or Mb as appropriate, for example a size of 1024 bytes will be printed as "1K".</dd>
<dt><code>timefmt</code></dt>
<dd>The value is a string to be used by the <code>strftime(3)</code> library routine when printing dates.</dd>
</dl>
</dd>
<dt><code>echo</code></dt>
<dd>Prints one of the include variables. If the variable is unset, the result is determined by the SSIUndefinedEcho directive.</p>
<pre class='a'>&lt;!--#echo [encoding="none|url|entity"] var="..." [encoding="none|url|entity"] var="..." ... --&gt;</pre>
<dl>
<dt><code>var</code></dt>
<dd>The value is the name of the variable to print.</dd>
<dt><code>encoding</code></dt>
<dd>
<p>Specifies how Apache should encode special characters contained in the variable before outputting them. If set to <code>none</code>, no encoding will be done. If set to <code>url</code>, then URL encoding (also known as %-encoding; this is appropriate for use within URLs in links, etc.) will be performed. The default is set to <code>entity</code>, resulting in entity encoding.</p>
</dd>
</dl>
</dd>
<dt><code>exec</code></dt>
<dd>Execute external programs</p>
<pre>&lt;!--#exec cgi="/cgi-bin/s.cgi" --&gt;
&lt;!--#exec cmd="ls" --&gt;
&lt;!--#include virtual="/cgi-bin/s.cgi?argument=value" --&gt;
&lt;!--#exec cmd="perl /cgi-bin/s.pl args" --&gt;</pre>
</dd>
<dt><code>include</code></dt>
<dd>Include a file</p>
<pre class='a'>&lt;!--#include virtual|file="..." [virtual|file="..."] ... --&gt;</pre>
</dd>
<dt><code>printenv</code></dt>
<dd>Print all available variables</p>
<pre>&lt;!--#printenv --&gt;</pre>
</dd>
<dt><code>set</code></dt>
<dd>Set a value of a variable.</p>
<pre class='a'>&lt;!--#set var="..." value="..." ... --&gt;
&lt;!--#set var="modified" value="$LAST_MODIFIED" --&gt;
&lt;!--#set var="name" value="AskApache" --&gt;
&lt;!--#set var="date" value="${DATE_LOCAL}_${DATE_GMT}" --&gt;</pre>
</dd>
<dt><code>flastmod</code></dt>
<dd>Prints the last modification date of the specified file, subject to the timefmt format specification.</p>
<pre>&lt;!--#flastmod virtual|file="..." [virtual|file="..."] ... --&gt;</pre>
</dd>
<dt><code>fsize</code></dt>
<dd>Prints the size of the specified file, subject to the sizefmt format specification.</p>
<pre class='a'>&lt;!--#fsize virtual|file="..." [virtual|file="..."] ... --&gt;</pre>
</dd>
<dt><code>if</code></dt>
<dd>The if element works like an if statement in a programming language. The test condition is evaluated and if the result is true, then the text until the next elif, else or endif element is included in the output stream.</p>
<pre>&lt;!--#if expr="..." --&gt;
&lt;!--#if expr="${REMOTE_USER} &amp;&amp; ${HTTP_USER_AGENT}" --&gt;</pre>
<pre>&lt;!--#if expr="test_condition" --&gt;
&lt;!--#elif expr="test_condition" --&gt;
&lt;!--#else --&gt;
&lt;!--#endif --&gt;</pre>
</dd>
<dt><code>elif</code></dt>
<dd>Used to put text into the output stream if the original test_condition was false. </p>
<pre class='a'>&lt;!--#elif expr="..." --&gt;</pre>
</dd>
<dt><code>else</code></dt>
<dd>Used to put text into the output stream if the original test_condition was false.</p>
<pre>&lt;!--#else --&gt;</pre>
</dd>
<dt><code>endif</code></dt>
<dd>Ends the if element and is required.</p>
<pre class='a'>&lt;!--#endif --&gt;</pre>
</dd>
</dl>


<h3>.htaccess directives</h3>
<ol>
<li>XBitHack</li>
<li>SSIErrorMsg</li>
<li>SSITimeFormat</li>
<li>SSIStartTag</li>
<li>SSIEndTag</li>
<li>SSIUndefinedEcho</li>
<li>SSIAccessEnable</li>
</ol>


<h3>mod_include Default SSI Values</h3>
<dl>
<dt><code>START_SEQUENCE</code></dt>
<dd><code>&lt;!--#</code> - The starting tag for mod_include to recognize and parse as SSI.</code></dd>
<dt><code>END_SEQUENCE</code></dt>
<dd><code>--&gt;</code> - The ending tag for mod_include to recognize and parse as SSI.</dd>
<dt><code>ERROR_MSG</code></dt>
<dd><code>[an error occurred while processing this directive]</code> - On Errors parsing SSI.</dd>
<dt><code>TIME_FORMAT</code></dt>
<dd><code>%A, %d-%b-%Y %H:%M:%S %Z</code> - Default Time format for DATE</dd>
<dt><code>UNDEFINED_ECHO</code></dt>
<dd><code>(none)</code> - When echoing an undefined variable.</dd>
</dl>

<h3>SSI Variables</h3>
<pre>DATE_GMT=Sun Mar  8 22:58:56 2009
DATE_LOCAL=Sun Mar  8 15:58:56 2009
DOCUMENT_NAME=FOOTER.html
DOCUMENT_ROOT=/root-srv/protected/askapache.com/sec
DOCUMENT_URI=/includes/FOOTER.html
GATEWAY_INTERFACE=CGI/1.1
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
HTTP_ACCEPT_CHARSET=ISO-8859-1,utf-8;q=0.7,*;q=0.7
HTTP_ACCEPT_ENCODING=gzip,deflate
HTTP_ACCEPT_LANGUAGE=en-us,en;q=0.5
HTTP_CACHE_CONTROL=max-age=0
HTTP_CONNECTION=keep-alive
HTTP_COOKIE=__qca=12298910-686528-46510;  __utmb=50625.1.0.11311
HTTP_HOST=www.askapache.com
HTTP_KEEP_ALIVE=300
HTTP_REFERER=http://www.askapache.com/htaccess/htaccess.html
HTTP_USER_AGENT=Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6 (.NET CLR 3.5.30729)
LAST_MODIFIED=Sun Mar  8 14:53:50 2009
PATH=/bin:/usr/bin:/sbin:/usr/sbin
QUERY_STRING=
REMOTE_ADDR=24.123.215.58
REMOTE_PORT=4785
REQUEST_METHOD=GET
REQUEST_URI=/htaccess/
SCRIPT_FILENAME=/root-srv/protected/askapache.com/sec/includes/FOOTER.html
SCRIPT_NAME=/includes/FOOTER.html
SCRIPT_URI=http://www.askapache.com/htaccess/
SCRIPT_URL=/htaccess/
SERVER_ADDR=64.111.114.111
SERVER_ADMIN=webmaster@askapache.com
SERVER_NAME=www.askapache.com
SERVER_PORT=80
SERVER_PROTOCOL=INCLUDED
SERVER_SIGNATURE=
SERVER_SOFTWARE=Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.63 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2
UNIQUE_ID=dnbtH0Bvcm8A2ZHqcAAAAM
USER_NAME=</pre>




<h3>More SSI Information</h3>
<ol>
<li><a href="http://httpd.apache.org/docs/trunk/mod/mod_include.html">mod_include</a></li>
<li><a href="http://httpd.apache.org/docs/trunk/filter.html">Apache Filters</a></li>
<li><a href="http://httpd.apache.org/docs/trunk/howto/ssi.html">Introduction to Server Side Includes</a></li>
<li><a href="http://httpd.apache.org/docs/trunk/handler.html">Apache Handlers</a></li>
</ol><p><a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html"></a><a href="http://www.askapache.com/htaccess/advanced-htaccess-ssi.html">SSI in Htaccess for ErrorDocuments, DirectoryIndexing, SEO</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/htaccess/advanced-htaccess-ssi.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>THE Ultimate Htaccess</title>
		<link>http://www.askapache.com/htaccess/htaccess.html</link>
		<comments>http://www.askapache.com/htaccess/htaccess.html#comments</comments>
		<pubDate>Sat, 10 Jan 2009 13:05:32 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Htaccess]]></category>

		<guid isPermaLink="false">http://www.askapache.com.com/htaccess/htaccesselite-ultimate-htaccess-article.html</guid>
		<description><![CDATA[<p><strong>Skip this - still under edit</strong></p>
<p>I discovered these tips and tricks mostly while working as a network security penetration specialist hired to find security holes in web hosting environments.  Shared hosting is the most common and cheapest form of web-hosting where multiple customers are placed on a single machine and "share" the resources (CPU/RAM/SPACE).  The machines are configured to basically ONLY do HTTP and FTP.  No shells or any interactive logins, no ssh, just FTP access.  That is when I started examining htaccess files in great detail and learned about the incredible untapped power of htaccess.  For 99% of the worlds best Apache admins, they don't use .htaccess much, if AT ALL.  It's much easier, safer, and faster to configure Apache using the httpd.conf file instead.  However, this file is almost never readable on shared-hosts, and I've never seen it writable.  So the only avenue left for those on shared-hosting was and is the .htaccess file, and holy freaking fiber-optics.. it's almost as powerful as httpd.conf itself!<br /><br />Most all .htaccess code works in the httpd.conf file, but not all httpd.conf code works in .htaccess files, around 50%.  So all the best Apache admins and programmers never used .htaccess files.  There was no incentive for those with access to httpd.conf to use htaccess, and the gap grew.  It's common to see "computer gurus" on forums and mailing lists rail against all uses and users of .htaccess files, smugly announcing the well known problems with .htaccess files compared with httpd.conf - I wonder if these "gurus" know the history of the htaccess file, like it's use in the earliest versions of the HTTP Server- NCSA's HTTPd, which BTW, became known as Apache HTTP.  So you could easily say that htaccess files predates Apache itself.<br /><br />Once I discovered what .htaccess files could do towards helping me enumerate and exploit security vulnerabilities even on big shared-hosts I focused all my research into .htaccess files, meaning I was reading the venerable Apache HTTP Source code 24/7!  I compiled every released version of the Apache Web Server, ever, even NCSA's, and focused on enumerating the most powerful htaccess directives. Good times! Because my focus was on protocol/file/network vulnerabilites instead of web dev I built up a nice toolbox of htaccess tricks to do unusual things.  When I switched over to webdev in 2005 I started using htaccess for websites, not research.  I documented most of my favorites and rewrote the htaccess guide for webdevelopers.  After some great encouragement on various forums and nets I decided to start a blog to share my work with everyone, AskApache.com was registered, I published my guide, and it was quickly plagiarized and scraped all over the net.  Information is freedom, and freedom is information, so this blog has the least restrictive copyright for you.  Feel free to modify, copy, republish, sell, or use anything on this site ;)</p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/htaccess/htaccess.html"></a><a href="http://www.askapache.com/htaccess/htaccess.html"><cite>AskApache.com</cite></a></p><p><dfn title="HyperText Access">.htaccess</dfn> is a very ancient configuration file that controls the Web Server running your website, and is one of the most powerful configuration files you will ever come across. Htaccess has the ability to control access of the <acronym title="World Wide Web">WWW</acronym>'s HyperText Transfer Protocol (<acronym title="HyperText Transfer Protocol">HTTP</acronym>) using Password Protection, 301 Redirects, rewrites, and much much more.  This is because this configuration file was coded in the earliest days of the web (HTTP), for one of the first Web Servers ever!  Eventually these Web Servers (configured with htaccess) became known as the World Wide Web, and eventually grew into the Internet we use today.</p>
<p><a class="IFL" href="/htaccess/htaccess.html"><img src="http://uploads.askapache.com/2008/08/htaccess-up.png" alt=".htaccess file tutorial" title=".htaccess file tutorial" width="141" height="144" /></a>This is not an <em>introduction to .htaccess</em>&hellip; This is the evolution of the best of the best <tt>.htaccess</tt> on the planet.  Its changed over the years with more and better <strong>.htaccess tricks</strong> using real <a href="#htaccess-code-examples">.htaccess example code</a>.  I add my favorite htaccess-related links and sites, results from my <a href="#best-htaccess-articles">htaccess research</a>, and frequently update this article.<br /><br />You've come to the right place if you are looking to acquire <strong>mad skills</strong> for using .htaccess files.<br /><br />Originally (2003) this guide was known in certain hacker circles and hidden corners of the net as an <em>ultimate .htaccess</em> due to the powerful <strong>htaccess tricks</strong> and tips to bypass security on a webhost, and also because many of the tricks and <a href="#htaccess-code-examples">examples</a> were pretty impressive back then in that group.<br class="C" /></p>

<h2>AskApache Htaccess Journey</h2>
<p><strong>Skip this - still under edit</strong></p>
<p>I discovered these tips and tricks mostly while working as a network security penetration specialist hired to find security holes in web hosting environments.  Shared hosting is the most common and cheapest form of web-hosting where multiple customers are placed on a single machine and "share" the resources (CPU/RAM/SPACE).  The machines are configured to basically ONLY do HTTP and FTP.  No shells or any interactive logins, no ssh, just FTP access.  That is when I started examining htaccess files in great detail and learned about the incredible untapped power of htaccess.  For 99% of the worlds best Apache admins, they don't use .htaccess much, if AT ALL.  It's much easier, safer, and faster to configure Apache using the httpd.conf file instead.  However, this file is almost never readable on shared-hosts, and I've never seen it writable.  So the only avenue left for those on shared-hosting was and is the .htaccess file, and holy freaking fiber-optics.. it's almost as powerful as httpd.conf itself!<br /><br />Most all .htaccess code works in the httpd.conf file, but not all httpd.conf code works in .htaccess files, around 50%.  So all the best Apache admins and programmers never used .htaccess files.  There was no incentive for those with access to httpd.conf to use htaccess, and the gap grew.  It's common to see "computer gurus" on forums and mailing lists rail against all uses and users of .htaccess files, smugly announcing the well known problems with .htaccess files compared with httpd.conf - I wonder if these "gurus" know the history of the htaccess file, like it's use in the earliest versions of the HTTP Server- NCSA's HTTPd, which BTW, became known as Apache HTTP.  So you could easily say that htaccess files predates Apache itself.<br /><br />Once I discovered what .htaccess files could do towards helping me enumerate and exploit security vulnerabilities even on big shared-hosts I focused all my research into .htaccess files, meaning I was reading the venerable Apache HTTP Source code 24/7!  I compiled every released version of the Apache Web Server, ever, even NCSA's, and focused on enumerating the most powerful htaccess directives. Good times! Because my focus was on protocol/file/network vulnerabilites instead of web dev I built up a nice toolbox of htaccess tricks to do unusual things.  When I switched over to webdev in 2005 I started using htaccess for websites, not research.  I documented most of my favorites and rewrote the htaccess guide for webdevelopers.  After some great encouragement on various forums and nets I decided to start a blog to share my work with everyone, AskApache.com was registered, I published my guide, and it was quickly plagiarized and scraped all over the net.  Information is freedom, and freedom is information, so this blog has the least restrictive copyright for you.  Feel free to modify, copy, republish, sell, or use anything on this site ;)</p>



<h2 class="htaccess" id="h21adf" style="font-weight:bold;">Htaccess - Evolved</h2>
<p>The Hyper Text Transfer Protocol (HTTP) was initiated at the CERN in Geneve (Switzerland), where it emerged (together with the HTML presentation language) from the need to exchange scientific information on a computer network in a simple manner. The first public HTTP implementation only allowed for plain text information, and almost instantaneously became a replacement of the GOPHER service. One of the first text-based browsers was LYNX which still exists today; a graphical HTTP client appeared very quickly with the name NCSA Mosaic. Mosaic was a popular browser back in 1994. Soon the need for a more rich multimedia experience was born, and the markup language provided support for a growing multitude of media types.</p>
<p>Htaccess file know-how will do several things for you:</p>
<ul><li>Make your website noticeably faster.</li><li>Allow you to debug your server with ease.</li><li>Make your life easier and more rewarding.</li><li>Allow you to work faster and more productively.</li></ul>


<h3>What Is .htaccess</h3>
<p>Specifically, <kbd>.htaccess</kbd> is the default file name of a special configuration file that provides a number of <a href="#htaccess-directives">directives</a> (commands) for controlling and configuring the <a href="http://httpd.apache.org/" title="open-source HTTP server running the WWW">Apache Web Server</a>, and also to control and configure <a href="#htaccess-modules">modules</a> that can be built into the Apache installation, or included at run-time like mod_rewrite (for htaccess rewrite), mod_alias (for htaccess redirects), and mod_ssl (for controlling SSL connections).</p>
<p><strong>Htaccess</strong> allows for decentralized management of Web Server configurations which makes life very easy for web hosting companies and especially their savvy consumers.  They set up and run "server farms" where many hundreds and thousands of web hosting customers are all put on the same Apache Server.  This type of hosting is called "virtual hosting" and without .htaccess files would mean that every customer must use the same exact settings as everyone else on their segment.  So that is why any half-decent web host allows/enables <em>(DreamHost, Powweb, MediaTemple, GoDaddy) .htaccess files</em>, though few people are aware of it.  Let's just say that if I was a customer on your server-farm, and .htaccess files were enabled, my websites would be a LOT faster than yours, as these configuration files allow you to fully take advantage of and utilize the resources allotted to you by your host.  If even 1/10 of the sites on a server-farm took advantage of what they are paying for, the providers would go out of business.</p>

<blockquote cite="http://httpd.apache.org/docs/1.3/misc/API.html">
<p>One of the design goals for this server was to maintain external compatibility with the NCSA 1.3 server --- that is, to read the same configuration files, to process all the directives therein correctly, and in general to be a drop-in replacement for NCSA. On the other hand, another design goal was to move as much of the server's functionality into modules which have as little as possible to do with the monolithic server core. The only way to reconcile these goals is to move the handling of most commands from the central server into the modules.</p>
<p>However, just giving the modules command tables is not enough to divorce them completely from the server core. The server has to remember the commands in order to act on them later. That involves maintaining data which is private to the modules, and which can be either per-server, or per-directory. Most things are per-directory, including in particular access control and authorization information, but also information on how to determine file types from suffixes, which can be modified by AddType and DefaultType directives, and so forth. In general, the governing philosophy is that anything which can be made configurable by directory should be; per-server information is generally used in the standard set of modules for information like Aliases and Redirects which come into play before the request is tied to a particular place in the underlying file system.</p>
<p>Another requirement for emulating the NCSA server is being able to handle the <strong>per-directory configuration files, generally called .htaccess files</strong>, though even in the NCSA server they can contain directives which have nothing at all to do with access control. Accordingly, after URI -> filename translation, but before performing any other phase, the server walks down the directory hierarchy of the underlying filesystem, following the translated pathname, to read any .htaccess files which might be present. The information which is read in then has to be merged with the applicable information from the server's own config files (either from the <code>&lt;directory&gt;</code> sections in access.conf, or from defaults in srm.conf, which actually behaves for most purposes almost exactly like <code>&lt;directory /&gt;</code>).</p>
<p>Finally, after having served a request which involved <strong>reading .htaccess files</strong>, we need to discard the storage allocated for handling them. That is solved the same way it is solved wherever else similar problems come up, by tying those structures to the per-transaction resource pool.</p>
</blockquote>


<h4 class="tic">Creating Htaccess Files</h4>
<p><a class="IFL" href="http://uploads.askapache.com/2009/01/htaccess-explorer.png"><img src="http://uploads.askapache.com/2009/01/htaccess-explorer.png" alt="What an Htaccess File Looks Like in Windows Explorer" title="What an Htaccess File Looks Like in Windows Explorer" width="243" height="322" /></a>Htaccess files use the default filename "<code>.htaccess</code>" but any unix-style file name can be specified from the <a href="#httpd-config-examples">main server config</a> using the <code>AccessFileName</code> directive.  The file isn't <code>.htaccess.txt</code>, its literally just named <code>.htaccess</code>.<br class="C" /></p>
<p><a class="IFR" href="http://uploads.askapache.com/2009/01/viewing-htaccess-files.png"><img src="http://uploads.askapache.com/2009/01/viewing-htaccess-files.png" alt="View .htaccess files" title="View .htaccess files" width="386" height="287" /></a>In a Windows Environment like the one I use for work, you can change how Windows opens and views .htaccess files by modifying the Folder Options in explorer.  As you can see, on my computer files ending in .htaccess are recognized as having the HTACCESS extension and are handled/opened by Adobe Dreamweaver CS4.<br class="C" /></p>

<h4>Htaccess Scope</h4>
<p>Unlike the main server configuration files like <a href="#httpd-config-examples">httpd.conf</a>, <strong>Htaccess files are read on every request</strong> therefore changes in these files take immediate effect.  Apache searches all directories and subdirectories that are htaccess-enabled for an .htaccess file which results in performance loss due to file accesses. I've never noticed a performance loss but OTOH, I know how to use them.  If you do have access to your main server configuration file, you should of course use that instead, and lucky for you ALL the .htaccess tricks and examples can be used there as well (just not vice versa).</p>


<h3>Htaccess File Syntax</h3>
<p>Htaccess files follow the same syntax as the main Apache configuration files, for powerusers here's an <a href='http://uploads.askapache.com/2009/01/apache.vim'>apache.vim</a> for VI. The one main difference is the <dfn title="Whether the directive is allowed in .htaccess files">context</dfn> of the directive, which means whether or not that directive is ALLOWED to be used inside of an .htaccess file.  Htaccess files are incredibly powerful, and can also be very dangerous as some directives allowed in the main configuration files would allow users/customers to completely bypass security/bandwidth-limits/resource-limits/file-permissions, etc..  About 1/4 of all Apache directives cannot be used inside an .htaccess file (also known as a per-directory context config).  The Apache Developers are well-regarded throughout the world as being among some of the best programmers, ever.  To enable a disallowed directive inside a .htaccess file would require modifying the source code and re-compiling the server (which they allow and encourage if you are the owner/admin).  Here's a taste of that famous Apache source code that builds the directives allowed in .htaccess file context, the key that tells whether its enabled in .htaccess context is the DIR_CMD_PERMS and then the OR_FILEINFO, which means a directive is enabled dependent on the AllowOverride directive that is only allowed in the main config.  First Apache 1.3.0, then Apache 2.2.10</p>

<h5>mod_autoindex</h5>
<pre>AddIcon, add_icon, BY_PATH, DIR_CMD_PERMS, an icon URL followed by one or more filenames
AddIconByType, add_icon, BY_TYPE, DIR_CMD_PERMS, an icon URL followed by one or more MIME types
AddIconByEncoding, add_icon, BY_ENCODING, DIR_CMD_PERMS, an icon URL followed by one or more content encodings
AddAlt, add_alt, BY_PATH, DIR_CMD_PERMS, alternate descriptive text followed by one or more filenames
AddAltByType, add_alt, BY_TYPE, DIR_CMD_PERMS, alternate descriptive text followed by one or more MIME types
AddAltByEncoding, add_alt, BY_ENCODING, DIR_CMD_PERMS, alternate descriptive text followed by one or more content encodings
IndexOptions, add_opts, DIR_CMD_PERMS, RAW_ARGS, one or more index options
IndexIgnore, add_ignore, DIR_CMD_PERMS, ITERATE, one or more file extensions
AddDescription, add_desc, BY_PATH, DIR_CMD_PERMS, Descriptive text followed by one or more filenames
HeaderName, add_header, DIR_CMD_PERMS, TAKE1, a filename
ReadmeName, add_readme, DIR_CMD_PERMS, TAKE1, a filename
FancyIndexing, fancy_indexing, DIR_CMD_PERMS, FLAG, Limited to &#039;on&#039; or &#039;off&#039; (superseded by IndexOptions FancyIndexing)
DefaultIcon, ap_set_string_slot, (void *) XtOffsetOf(autoindex_config_rec, default_icon), DIR_CMD_PERMS, TAKE1, an icon URL</pre>

<h5>mod_rewrite</h5>
<pre>// mod_rewrite
RewriteEngine, cmd_rewriteengine, OR_FILEINFO, On or Off to enable or disable (default)
RewriteOptions, cmd_rewriteoptions, OR_FILEINFO, List of option strings to set
RewriteBase, cmd_rewritebase, OR_FILEINFO, the base URL of the per-directory context
RewriteCond, cmd_rewritecond, OR_FILEINFO, an input string and a to be applied regexp-pattern
RewriteRule, cmd_rewriterule, OR_FILEINFO, an URL-applied regexp-pattern and a substitution URL
RewriteMap, cmd_rewritemap, RSRC_CONF, a mapname and a filename
RewriteLock, cmd_rewritelock, RSRC_CONF, the filename of a lockfile used for inter-process synchronization
RewriteLog, cmd_rewritelog, RSRC_CONF, the filename of the rewriting logfile
RewriteLogLevel, cmd_rewriteloglevel, RSRC_CONF, the level of the rewriting logfile verbosity (0=none, 1=std, .., 9=max)
RewriteLog, fake_rewritelog, RSRC_CONF, [DISABLED] the filename of the rewriting logfile
RewriteLogLevel, fake_rewritelog, RSRC_CONF, [DISABLED] the level of the rewriting logfile verbosity</pre>



<h3>Htaccess Directives</h3>
<p><strong>Don't ask why</strong>, but I personally downloaded each major/beta release of the Apache HTTPD source code from version 1.3.0 to version 2.2.10 (<dfn title="1.3.0, 1.3.1, 1.3.11, 1.3.12, 1.3.14, 1.3.17, 1.3.19, 1.3.2, 1.3.20, 1.3.22, 1.3.23, 1.3.24, 1.3.27, 1.3.28, 1.3.29, 1.3.3, 1.3.31, 1.3.32, 1.3.33, 1.3.34, 1.3.35, 1.3.36, 1.3.37, 1.3.39, 1.3.4, 1.3.41, 1.3.6, 1.3.9, 2.0.35, 2.0.36, 2.0.39, 2.0.40, 2.0.42, 2.0.43, 2.0.44, 2.0.45, 2.0.46, 2.0.47, 2.0.48, 2.0.49, 2.0.50, 2.0.51, 2.0.52, 2.0.53, 2.0.54, 2.0.55, 2.0.58, 2.0.59, 2.0.61, 2.0.63, 2.1.3-beta, 2.1.6-alpha, 2.1.7-beta, 2.1.8-beta, 2.1.9-beta, 2.2.0, 2.2.2, 2.2.3, 2.2.4, 2.2.6, 2.2.8, 2.2.9, 2.2.10">all 63 Apache versions</dfn>!), then I <strong>configured and compiled each version for a custom HTTPD installation built from source</strong>. This allowed me to find <strong><a href="#htaccess-directives-list">every directive allowed in .htaccess files</a></strong> for each particular version, which has never been done before, or since. <strong>YES!</strong> <em>I think that is so cool..</em></p>
<p><strong>An .htaccess directive</strong> is basically a command that is specific to a module or builtin to the core that performs a specific task or sets a specific setting for how Apache serves your WebSite.  Directives placed in Htaccess files <strong>apply to the directory they are in, and all sub-directories</strong>.  Here's the 3 top links (<em>official Apache Docs</em>) you will repeatedly use, bookmark/print/save them.</p>
<p><a href="http://uploads.askapache.com/2008/08/htaccess-up1.png"><img src="http://uploads.askapache.com/2008/08/htaccess-up1-350x178.png" alt="htaccess Context Legend" title="htaccess-up1" width="350" height="178" /></a></p>
<ol><li><a href="http://httpd.apache.org/docs/trunk/mod/directive-dict.html">Terms Used to Describe Directives</a></li><li><a href="http://httpd.apache.org/docs/trunk/mod/directives.html">Official List of Apache Directives</a></li><li><a href="http://httpd.apache.org/docs/trunk/mod/quickreference.html">Directive Quick-Reference -- with Context</a></li></ol>
<hr class="C" />


<h3>Litespeed Htaccess support</h3>
<p>Unlike other lightweight web servers, Apache compatible per-directory configuration overridden is fully supported by <a href="http://www.litespeedtech.com/">LiteSpeed Web Server</a>. With .htacess you can change configurations for any directory under document root on-the-fly, which in most cases is a mandatory feature in shared hosting environment.   It is worth noting that <em>enabling .htaccess support in LiteSpeed</em> Web Server will not degrade server's performance, comparing to Apache's 40% drop in performance. </p>







<h2>Main Server Config Examples</h2>
<p>Now lets take a look at some htaccess examples to get a feel for the syntax and some general ideas at the capabilities.  Some of the best examples for .htaccess files are included with Apache for <a href="http://httpd.apache.org/docs/trunk/configuring.html">main server config</a> files, so lets take a quick look at a couple of them on our way down to the actual .htaccess examples further down the page (this site has thousands, take your time).  As you can see, the basic syntax is a line starting with # is a comment, everything else are directives followed by the directive argument.</p>
<p><strong><a href="http://uploads.askapache.com/2008/08/httpd-multilang-errordocconf.in">httpd-multilang-errordoc.conf</a></strong>: The configuration below implements multi-language error documents through content-negotiation</p>
<pre>Options IncludesNoExec
AddOutputFilter Includes html
AddHandler type-map var
LanguagePriority en cs de es fr it ja ko nl pl pt-br ro sv tr
ForceLanguagePriority Prefer Fallback
ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var
ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var</pre>
<p><strong><a href="http://uploads.askapache.com/2008/08/httpd-manualconf.in">httpd-manual.conf</a></strong>: Provide local access to the server documentation on your server</p>
<pre>SetEnvIf Request_URI ^/manual/(de|en|es|fr|ja|ko|pt-br|ru|tr)/ prefer-language=$1
RedirectMatch 301 ^/manual(?:/(de|en|es|fr|ja|ko|pt-br|ru|tr)){2, }(/.*)?$ /manual/$1$2
LanguagePriority en de es fr ja ko pt-br ru tr
ForceLanguagePriority Prefer Fallback</pre>
<p><strong><a href="http://uploads.askapache.com/2008/08/httpd-languagesconf.in">httpd-languages.conf</a></strong>: Settings for hosting different languages.</p>
<pre>DefaultLanguage en
AddLanguage ca .ca
# Just list the languages in decreasing order of preference.
LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv tr zh-CN zh-TW
# Commonly used filename extensions to character sets.
AddCharset us-ascii.ascii .us-ascii
AddCharset ISO-8859-1  .iso8859-1  .latin1</pre>
<p><strong><a href="http://uploads.askapache.com/2008/08/httpd-autoindexconf.in">httpd-autoindex.conf</a></strong>: Directives controlling the display of server-generated directory listings.</p>
<pre># IndexOptions: Controls the appearance of server-generated directory listings.
IndexOptions FancyIndexing HTMLTable VersionSort
# AddIcon* directives tell the server which icon to show for different files or filename extensions.
AddIconByEncoding (CMP, /icons/compressed.gif) x-compress x-gzip
AddIconByType (TXT, /icons/text.gif) text/*
AddIcon /icons/folder.gif ^^DIRECTORY^^
# DefaultIcon is which icon to show for files which do not have an icon explicitly set.
DefaultIcon /icons/unknown.gif
# AddDescription allows you to place a short description after a file in server-generated indexes.
AddDescription "GZIP compressed document" .gz
# ReadmeName is the name of the README file the server will look for by default, and append to directory listings.
ReadmeName README.html
# HeaderName is the name of a file which should be prepended to directory indexes.
HeaderName HEADER.html</pre>
<p>Here are the rest of them if you wanna take a look.  (<a href="http://uploads.askapache.com/2008/08/httpd-mpmconf.in" title="Server-Pool Management (MPM specific)">httpd-mpm.conf</a>, <a href="http://uploads.askapache.com/2008/08/httpd-defaultconf.in" title="This configuration file reflects default settings for Apache HTTP Server">httpd-default.conf</a>, <a href="http://uploads.askapache.com/2008/08/httpd-sslconf.in" title="Contains the configuration directives to instruct the server how to serve pages over an https connection">httpd-ssl.conf</a>, <a href="http://uploads.askapache.com/2008/08/httpd-infoconf.in" title="Get information about the requests being processed by the server and the configuration of the server">httpd-info.conf</a>, <a href="http://uploads.askapache.com/2008/08/httpd-vhostsconf.in" title="If you want to maintain multiple domains/hostnames on your machine">httpd-vhosts.conf</a>, <a href="http://uploads.askapache.com/2008/08/httpd-davconf.in" title="Distributed authoring and versioning (WebDAV)">httpd-dav.conf</a>)</p>
<hr class="C" />







<h2>Example .htaccess Files</h2>
<p>Here are some samples and examples taken from different .htaccess files I've used over the years.  Specific solutions are farther down on this page and throughout the site.</p>
<pre># Set the Time Zone of your Server
SetEnv TZ America/Indianapolis
# ServerAdmin:  This address appears on some server-generated pages, such as error documents.
SetEnv SERVER_ADMIN webmaster@askapache.com
# Possible values for the Options directive are "None", "All", or any combination of:
#  Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
Options -ExecCGI -MultiViews -Includes -Indexes FollowSymLinks
# DirectoryIndex: sets the file that Apache will serve if a directory is requested.
DirectoryIndex index.html index.php /index.php
#
# Action lets you define media types that will execute a script whenever
# a matching file is called. This eliminates the need for repeated URL
# pathnames for oft-used CGI file processors.
# Format: Action media/type /cgi-script/location
# Format: Action handler-name /cgi-script/location
#
Action php5-cgi /bin/php.cgi
#
# AddHandler allows you to map certain file extensions to "handlers":
# actions unrelated to filetype. These can be either built into the server
# or added with the Action directive (see below)
#
# To use CGI scripts outside of ScriptAliased directories:
# (You will also need to add "ExecCGI" to the "Options" directive.)
#
AddHandler php-cgi .php .inc
# Commonly used filename extensions to character sets.
AddDefaultCharset UTF-8
# AddType allows you to add to or override the MIME configuration
AddType &#039;application/rdf+xml; charset=UTF-8&#039; .rdf
AddType &#039;application/xhtml+xml; charset=UTF-8&#039; .xhtml
AddType &#039;application/xhtml+xml; charset=UTF-8&#039; .xhtml.gz
AddType &#039;text/html; charset=UTF-8&#039; .html
AddType &#039;text/html; charset=UTF-8&#039; .html.gz
AddType application/octet-stream .rar .chm .bz2 .tgz .msi .pdf .exe
AddType application/vnd.ms-excel .csv
AddType application/x-httpd-php-source .phps
AddType application/x-pilot .prc .pdb
AddType application/x-shockwave-flash .swf
AddType application/xrds+xml .xrdf
AddType text/plain .ini .sh .bsh .bash .awk .nawk .gawk .csh .var .c .in .h .asc .md5 .sha .sha1
AddType video/x-flv .flv
# AddEncoding allows you to have certain browsers uncompress information on the fly. Note: Not all browsers support this.
AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
# DefaultType: the default MIME type the server will use for a document.
DefaultType text/html
#
# Optionally add a line containing the server version and virtual host
# name to server-generated pages (internal error documents, FTP directory
# listings, mod_status and mod_info output etc., but not CGI generated
# documents or custom error documents).
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of:  On | Off | EMail
#
ServerSignature Off</pre>
<pre>## MAIN DEFAULTS
Options +ExecCGI -Indexes
DirectoryIndex index.html index.htm index.php
DefaultLanguage en-US
AddDefaultCharset UTF-8
ServerSignature Off
## ENVIRONMENT VARIABLES
SetEnv PHPRC /webroot/includes
SetEnv TZ America/Indianapolis
&nbsp;
SetEnv SERVER_ADMIN webmaster@askapache.com
## MIME TYPES
AddType video/x-flv .flv
AddType application/x-shockwave-flash .swf
AddType image/x-icon .ico
## FORCE FILE TO DOWNLOAD INSTEAD OF APPEAR IN BROWSER
# http://www.htaccesselite.com/addtype-addhandler-action-vf6.html
AddType application/octet-stream .mov .mp3 .zip
## ERRORDOCUMENTS
# http://askapache.com/htaccess/apache-status-code-headers-errordocument.html
ErrorDocument 400 /e400/
ErrorDocument 401 /e401/
ErrorDocument 402 /e402/
ErrorDocument 403 /e403/
ErrorDocument 404 /e404/
#
# Handlers be builtin, included in a module, or added with Action directive
# default-handler: default, handles static content (core)
#   send-as-is: Send file with HTTP headers (mod_asis)
#   cgi-script: treat file as CGI script (mod_cgi)
#    imap-file: Parse as an imagemap rule file (mod_imap)
#   server-info: Get server config info (mod_info)
#  server-status: Get server status report (mod_status)
#    type-map: type map file for content negotiation (mod_negotiation)
#  fastcgi-script: treat file as fastcgi script (mod_fastcgi)
#
# http://www.askapache.com/php/custom-phpini-tips-and-tricks.html
## PARSE AS CGI
AddHandler cgi-script .cgi .pl .spl
## RUN PHP AS APACHE MODULE
AddHandler application/x-httpd-php .php .htm
## RUN PHP AS CGI
AddHandler php-cgi .php .htm
## CGI PHP WRAPPER FOR CUSTOM PHP.INI
AddHandler phpini-cgi .php .htm
Action phpini-cgi /cgi-bin/php5-custom-ini.cgi
## FAST-CGI SETUP WITH PHP-CGI WRAPPER FOR CUSTOM PHP.INI
AddHandler fastcgi-script .fcgi
AddHandler php-cgi .php .htm
Action php-cgi /cgi-bin/php5-wrapper.fcgi
## CUSTOM PHP CGI BINARY SETUP
AddHandler php-cgi .php .htm
Action php-cgi /cgi-bin/php.cgi
## PROCESS SPECIFIC FILETYPES WITH CGI-SCRIPT
Action image/gif /cgi-bin/img-create.cgi
## CREATE CUSTOM HANDLER FOR SPECIFIC FILE EXTENSIONS
AddHandler custom-processor .ssp
Action custom-processor /cgi-bin/myprocessor.cgi
### HEADER CACHING
# http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html
&lt;FilesMatch "\.(flv|gif|jpg|jpeg|png|ico)$"&gt;
Header set Cache-Control "max-age=2592000"
&lt;/FilesMatch&gt;
&lt;FilesMatch "\.(js|css|pdf|swf)$"&gt;
Header set Cache-Control "max-age=604800"
&lt;/FilesMatch&gt;
&lt;FilesMatch "\.(html|htm|txt)$"&gt;
Header set Cache-Control "max-age=600"
&lt;/FilesMatch&gt;
&lt;FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$"&gt;
Header unset Cache-Control
&lt;/FilesMatch&gt;
## ALTERNATE EXPIRES CACHING
# htaccesselite.com/d/use-htaccess-to-speed-up-your-site-discussion-vt67.html
ExpiresActive On
ExpiresDefault A604800
ExpiresByType image/x-icon A2592000
ExpiresByType application/x-javascript A2592000
ExpiresByType text/css A2592000
ExpiresByType text/html A300
&lt;FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$"&gt;
ExpiresActive Off
&lt;/FilesMatch&gt;
## META HTTP-EQUIV REPLACEMENTS
&lt;FilesMatch "\.(html|htm|php)$"&gt;
Header set imagetoolbar "no"
&lt;/FilesMatch&gt;</pre>
<p>Here are some default MOD_REWRITE code examples.</p>
<pre>## REWRITE DEFAULTS
RewriteEngine On
RewriteBase /
## REQUIRE SUBDOMAIN
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^subdomain\.askapache\.com$ [NC]
RewriteRule ^/(.*)$ http://subdomain.askapache.com/$1 [L,R=301]
## SEO REWRITES
RewriteRule ^(.*)/ve/(.*)$ $1/voluntary-employee/$2 [L,R=301]
RewriteRule ^(.*)/hsa/(.*)$ $1/health-saving-account/$2 [L,R=301]
## WORDPRESS
RewriteCond %{REQUEST_FILENAME} !-f  # Existing File
RewriteCond %{REQUEST_FILENAME} !-d  # Existing Directory
RewriteRule . /index.php [L]
## ALTERNATIVE ANTI-HOTLINKING
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(subdomain\.)?askapache.com/.*$ [NC]
RewriteRule ^.*\.(bmp|tif|gif|jpg|jpeg|jpe|png)$ - [F]
## REDIRECT HOTLINKERS
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(subdomain\.)?askapache.com/.*$ [NC]
RewriteRule ^.*\.(bmp|tif|gif|jpg|jpeg|jpe|png)$ http://google.com [R]
## DENY REQUEST BASED ON REQUEST METHOD
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK|OPTIONS|HEAD)$ [NC]
RewriteRule ^.*$ - [F]
## REDIRECT UPLOADS
RewriteCond %{REQUEST_METHOD} ^(PUT|POST)$ [NC]
RewriteRule ^(.*)$ /cgi-bin/form-upload-processor.cgi?p=$1 [L,QSA]
## REQUIRE SSL EVEN WHEN MOD_SSL IS NOT LOADED
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]
### ALTERNATATIVE TO USING ERRORDOCUMENT
# http://www.htaccesselite.com/d/htaccess-errordocument-examples-vt11.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /error.php [L]
## SEO REDIRECTS
Redirect 301 /2006/oldfile.html http://subdomain.askapache.com/newfile.html
RedirectMatch 301 /o/(.*)$ http://subdomain.askapache.com/s/dl/$1</pre>
<p>Examples of protecting your files and securing with password protection.</p>
<pre>#
# Require (user|group|valid-user) (username|groupname)
#
## BASIC PASSWORD PROTECTION
AuthType basic
AuthName "prompt"
AuthUserFile /.htpasswd
AuthGroupFile /dev/null
Require valid-user
## ALLOW FROM IP OR VALID PASSWORD
Require valid-user
Allow from 192.168.1.23
Satisfy Any
## PROTECT FILES
&lt;FilesMatch "\.(htaccess|htpasswd|ini|phps|fla|psd|log|sh)$"&gt;
Order Allow,Deny
Deny from all
&lt;/FilesMatch&gt;
## PREVENT HOTLINKING
SetEnvIfNoCase Referer "^http://subdomain.askapache.com/" good
SetEnvIfNoCase Referer "^$" good
&lt;FilesMatch "\.(png|jpg|jpeg|gif|bmp|swf|flv)$"&gt;
Order Deny,Allow
Deny from all
Allow from env=good
ErrorDocument 403 http://www.google.com/intl/en_ALL/images/logo.gif
ErrorDocument 403 /images/you_bad_hotlinker.gif
&lt;/FilesMatch&gt;
## LIMIT UPLOAD FILE SIZE TO PROTECT AGAINST DOS ATTACK
#bytes, 0-2147483647(2GB)
LimitRequestBody 10240000
## MOST SECURE WAY TO REQUIRE SSL
# http://www.askapache.com/htaccess/apache-ssl-in-htaccess-examples.html
SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "askapache.com"
ErrorDocument 403 https://askapache.com
## COMBINED DEVELOPER HTACCESS CODE-USE THIS
&lt;FilesMatch "\.(flv|gif|jpg|jpeg|png|ico|js|css|pdf|swf|html|htm|txt)$"&gt;
Header set Cache-Control "max-age=5"
&lt;/FilesMatch&gt;
AuthType basic
AuthName "Ooops! Temporarily Under Construction..."
AuthUserFile /.htpasswd
AuthGroupFile /dev/null
Require valid-user      # password prompt for everyone else
Order Deny,Allow
Deny from all
Allow from 192.168.64.5   # Your, the developers IP address
Allow from w3.org      # css/xhtml check jigsaw.w3.org/css-validator/
Allow from googlebot.com   # Allows google to crawl your pages
Satisfy Any        # no password required if host/ip is Allowed
## DONT HAVE TO EMPTY CACHE OR RELOAD TO SEE CHANGES
ExpiresDefault A5 #If using mod_expires
&lt;FilesMatch "\.(flv|gif|jpg|jpeg|png|ico|js|css|pdf|swf|html|htm|txt)$"&gt;
Header set Cache-Control "max-age=5"
&lt;/FilesMatch&gt;
## ALLOW ACCESS WITH PASSWORD OR NO PASSWORD FOR SPECIFIC IP/HOSTS
AuthType basic
AuthName "Ooops! Temporarily Under Construction..."
AuthUserFile /.htpasswd
AuthGroupFile /dev/null
Require valid-user      # password prompt for everyone else
Order Deny,Allow
Deny from all
Allow from 192.168.64.5   # Your, the developers IP address
Allow from w3.org      # css/xhtml check jigsaw.w3.org/css-validator/
Allow from googlebot.com   # Allows google to crawl your pages
Satisfy Any        # no password required if host/ip is Allowed</pre>
<hr class="C" />






<h2>Example .htaccess Code Snippets</h2>
<p>Here are some specific examples, this is the most popular section of this page.  Updated frequently.</p>

<h4>Redirect Everyone Except IP address to alternate page</h4>
<pre>ErrorDocument 403 http://www.yahoo.com/
Order deny,allow
Deny from all
Allow from 208.113.134.190</pre>

<h4>When developing sites</h4>
<p>This lets google crawl the page, lets me access  without a password, and lets my client access the page WITH a password.  It also allows for XHTML and CSS validation! (w3.org)</p>
<pre>AuthName "Under Development"
AuthUserFile /home/sitename.com/.htpasswd
AuthType basic
Require valid-user
Order deny,allow
Deny from all
Allow from 208.113.134.190 w3.org htmlhelp.com googlebot.com
Satisfy Any</pre>

<h4>Fix double-login prompt</h4>
<p>Redirect non-https requests to https server and ensure that <strong>.htpasswd authorization</strong> can only be entered across HTTPS</p>
<pre>SSLOptions +StrictRequire
SSLRequireSSL
SSLRequire %{HTTP_HOST} eq "askapache.com"
ErrorDocument 403 https://askapache.com</pre>

<h4>Set Timezone of the Server (GMT)</h4>
<pre>SetEnv TZ America/Indianapolis</pre>

<h4>Administrator Email for ErrorDocument</h4>
<pre>SetEnv SERVER_ADMIN webmaster@google.com</pre>

<h4><code>ServerSignature</code> for <code>ErrorDocument</code></h4>
<pre>ServerSignature off | on | email</pre>

<h4>Charset and Language headers</h4>
<p>Article: <a href="/htaccess/setting-charset-in-htaccess.html">Setting Charset in htaccess</a>, and <a href="http://www.w3.org/International/questions/qa-htaccess-charset">article by <cite>Richard Ishida</cite></a></p>
<pre>AddDefaultCharset UTF-8
DefaultLanguage en-US</pre>

<h4>Disallow Script Execution</h4>
<pre>Options -ExecCGI
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi</pre>

<h4>Deny Request Methods</h4>
<pre>RewriteCond %{REQUEST_METHOD} !^(GET|HEAD|OPTIONS|POST|PUT)
RewriteRule .* - [F]</pre>

<h4>Force "File Save As" Prompt</h4>
<pre>AddType application/octet-stream .avi .mpg .mov .pdf .xls .mp4</pre>

<h4>Show CGI Source Code</h4>
<pre>RemoveHandler cgi-script .pl .py .cgi
AddType text/plain .pl .py .cgi</pre>

<h4>Serve all .pdf files on your site using .htaccess and mod_rewrite with the php script.</h4>
<pre>RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.+)\.pdf$  /cgi-bin/pdf.php?file=$1 [L,NC,QSA]</pre>

<h4>Rewrite to www</h4>
<pre>RewriteCond %{REQUEST_URI} !^/(robots\.txt|favicon\.ico|sitemap\.xml)$
RewriteCond %{HTTP_HOST} !^www\.askapache\.com$ [NC]
RewriteRule ^(.*)$ http://www.askapache.com/$1 [R=301,L]</pre>

<h4>Rewrite to www dynamically</h4>
<pre>RewriteCond %{REQUEST_URI} !^/robots\.txt$ [NC]
RewriteCond %{HTTP_HOST} !^www\.[a-z-]+\.[a-z]{2,6} [NC]
RewriteCond %{HTTP_HOST} ([a-z-]+\.[a-z]{2,6})$   [NC]
RewriteRule ^/(.*)$ http://%1/$1 [R=301,L]</pre>

<h4>301 Redirect Old File</h4>
<pre>Redirect 301 /old/file.html http://www.askapache.com/new/file.html</pre>

<h4>301 Redirect Entire Directory</h4>
<pre>RedirectMatch 301 /blog(.*) http://www.askapache.com/$1</pre>

<h4>Protecting your php.cgi</h4>
<pre>&lt;FilesMatch "^php5?\.(ini|cgi)$"&gt;
Order Deny,Allow
Deny from All
Allow from env=REDIRECT_STATUS
&lt;/FilesMatch&gt;</pre>

<h4>Set Cookie based on Request</h4>
<p>This code sends the <code>Set-Cookie</code> header to create a cookie on the client with the value of a matching item in 2nd parantheses.</p>
<pre>RewriteEngine On
RewriteBase /
RewriteRule ^(.*)(de|es|fr|it|ja|ru|en)/$ - [co=lang:$2:.askapache.com:7200:/]</pre>

<h4>Set Cookie with env variable</h4>
<pre>Header set Set-Cookie "language=%{lang}e; path=/;" env=lang</pre>

<h4>Custom ErrorDocuments</h4>
<pre>ErrorDocument 100 /100_CONTINUE
ErrorDocument 101 /101_SWITCHING_PROTOCOLS
ErrorDocument 102 /102_PROCESSING
ErrorDocument 200 /200_OK
ErrorDocument 201 /201_CREATED
ErrorDocument 202 /202_ACCEPTED
ErrorDocument 203 /203_NON_AUTHORITATIVE
ErrorDocument 204 /204_NO_CONTENT
ErrorDocument 205 /205_RESET_CONTENT
ErrorDocument 206 /206_PARTIAL_CONTENT
ErrorDocument 207 /207_MULTI_STATUS
ErrorDocument 300 /300_MULTIPLE_CHOICES
ErrorDocument 301 /301_MOVED_PERMANENTLY
ErrorDocument 302 /302_MOVED_TEMPORARILY
ErrorDocument 303 /303_SEE_OTHER
ErrorDocument 304 /304_NOT_MODIFIED
ErrorDocument 305 /305_USE_PROXY
ErrorDocument 307 /307_TEMPORARY_REDIRECT
ErrorDocument 400 /400_BAD_REQUEST
ErrorDocument 401 /401_UNAUTHORIZED
ErrorDocument 402 /402_PAYMENT_REQUIRED
ErrorDocument 403 /403_FORBIDDEN
ErrorDocument 404 /404_NOT_FOUND
&nbsp;
ErrorDocument 405 /405_METHOD_NOT_ALLOWED
ErrorDocument 406 /406_NOT_ACCEPTABLE
ErrorDocument 407 /407_PROXY_AUTHENTICATION_REQUIRED
ErrorDocument 408 /408_REQUEST_TIME_OUT
ErrorDocument 409 /409_CONFLICT
ErrorDocument 410 /410_GONE
ErrorDocument 411 /411_LENGTH_REQUIRED
ErrorDocument 412 /412_PRECONDITION_FAILED
ErrorDocument 413 /413_REQUEST_ENTITY_TOO_LARGE
ErrorDocument 414 /414_REQUEST_URI_TOO_LARGE
ErrorDocument 415 /415_UNSUPPORTED_MEDIA_TYPE
ErrorDocument 416 /416_RANGE_NOT_SATISFIABLE
ErrorDocument 417 /417_EXPECTATION_FAILED
ErrorDocument 422 /422_UNPROCESSABLE_ENTITY
ErrorDocument 423 /423_LOCKED
ErrorDocument 424 /424_FAILED_DEPENDENCY
ErrorDocument 426 /426_UPGRADE_REQUIRED
ErrorDocument 500 /500_INTERNAL_SERVER_ERROR
ErrorDocument 501 /501_NOT_IMPLEMENTED
ErrorDocument 502 /502_BAD_GATEWAY
ErrorDocument 503 /503_SERVICE_UNAVAILABLE
ErrorDocument 504 /504_GATEWAY_TIME_OUT
ErrorDocument 505 /505_VERSION_NOT_SUPPORTED
ErrorDocument 506 /506_VARIANT_ALSO_VARIES
ErrorDocument 507 /507_INSUFFICIENT_STORAGE
ErrorDocument 510 /510_NOT_EXTENDED</pre>

<h4>Implementing a Caching Scheme with .htaccess</h4>
<pre># 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;
#2 hours
&lt;FilesMatch "\.(html|htm|xml|txt|xsl)$"&gt;
Header set Cache-Control "max-age=7200, must-revalidate"
&lt;/FilesMatch&gt;
&lt;FilesMatch "\.(js|css)$"&gt;
SetOutputFilter DEFLATE
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
&lt;/FilesMatch&gt;</pre>

<h4>Password Protect single file</h4>
<pre>&lt;Files login.php&gt;
AuthName "Prompt"
AuthType Basic
AuthUserFile /home/askapache.com/.htpasswd
Require valid-user
&lt;/Files&gt;</pre>

<h4>Password Protect multiple files</h4>
<pre>&lt;FilesMatch "^(private|phpinfo)\.*$"&gt;
AuthName "Development"
AuthUserFile /.htpasswd
AuthType basic
Require valid-user
&lt;/FilesMatch&gt;</pre>

<h4>Send Custom Headers</h4>
<pre>Header set P3P "policyref=\"http://www.askapache.com/w3c/p3p.xml\""
Header set X-Pingback "http://www.askapache.com/xmlrpc.php"
Header set Content-Language "en-US"
Header set Vary "Accept-Encoding"</pre>

<h4>Blocking based on User-Agent Header</h4>
<pre>SetEnvIfNoCase ^User-Agent$ .*(craftbot|download|extract|stripper|sucker|ninja|clshttp|webspider|leacher|collector|grabber|webpictures) HTTP_SAFE_BADBOT
SetEnvIfNoCase ^User-Agent$ .*(libwww-perl|aesop_com_spiderman) HTTP_SAFE_BADBOT
Deny from env=HTTP_SAFE_BADBOT</pre>

<h4>Blocking with RewriteCond</h4>
<pre>RewriteCond %{HTTP_USER_AGENT} ^.*(craftbot|download|extract|stripper|sucker|ninja|clshttp|webspider|leacher|collector|grabber|webpictures).*$ [NC]
RewriteRule . - [F,L]</pre>

<h4>.htaccess for mod_php</h4>
<pre>SetEnv PHPRC /location/todir/containing/phpinifile</pre>

<h4>.htaccess for php as cgi</h4>
<pre>AddHandler php-cgi .php .htm
Action php-cgi /cgi-bin/php5.cgi</pre>

<h4>Shell wrapper for custom php.ini</h4>
<pre>#!/bin/sh
export PHP_FCGI_CHILDREN=3
exec php5.cgi -c /abs/php5/php.ini</pre>

<h4>Add values from HTTP Headers</h4>
<pre>SetEnvIfNoCase ^If-Modified-Since$ "(.+)" HTTP_IF_MODIFIED_SINCE=$1
SetEnvIfNoCase ^If-None-Match$ "(.+)" HTTP_IF_NONE_MATCH=$1
SetEnvIfNoCase ^Cache-Control$ "(.+)" HTTP_CACHE_CONTROL=$1
SetEnvIfNoCase ^Connection$ "(.+)" HTTP_CONNECTION=$1
SetEnvIfNoCase ^Keep-Alive$ "(.+)" HTTP_KEEP_ALIVE=$1
SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
SetEnvIfNoCase ^Cookie$ "(.+)" HTTP_MY_COOKIE=$1</pre>

<h4>Stop hotlinking</h4>
<pre>RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?askapache.com/.*$ [NC]
RewriteRule \.(gif|jpg|swf|flv|png)$ http://www.askapache.com/feed.gif [R=302,L]</pre>

<h4>Turn logging off for IP</h4>
<pre>SecFilterSelective REMOTE_ADDR "208\.113\.183\.103" "nolog,noauditlog,pass"</pre>

<h4>Turn logging on for IP</h4>
<pre>SecFilterSelective REMOTE_ADDR "!^208\.113\.183\.103" "nolog,noauditlog,pass"
SecFilterSelective REMOTE_ADDR "208\.113\.183\.103" "log,auditlog,pass"</pre>
<hr class="C" />






<h2>Advanced Mod_Rewrite Examples</h2>
<p>Here are some specific examples taken mostly from my WordPress Password Protection plugin, that also does alot more than password protection as you can see from the following mod_rewrite examples.  These are a few of the mod_rewrite uses that BlogSecurity declared pushed the boundaries of Mod_Rewrite!  Some of these snippets are quite exotic and unlike anything you may have seen before, also only for those who understand them as they can kill a website pretty quick.</p>

<h4>Directory Protection</h4>
<p>Enable the DirectoryIndex Protection, preventing directory index listings and defaulting. [<a href="/htaccess/htaccess.html">Disable</a>]</p>
<pre>Options -Indexes
DirectoryIndex index.html index.php /index.php</pre>

<h4>Password Protect wp-login.php</h4>
<p>Requires a valid user/pass to access the login page[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-401">401</a>]</p>
<pre>&lt;Files wp-login.php&gt;
Order Deny,Allow
Deny from All
Satisfy Any
AuthName "Protected By AskApache"
AuthUserFile /home/askapache.com/.htpasswda1
AuthType Basic
Require valid-user
&lt;/Files&gt;</pre>


<h4>Password Protect wp-admin</h4>
<p>Requires a valid user/pass to access any non-static (css, js, images) file in this directory.[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-401">401</a>]</p>
<pre>Options -ExecCGI -Indexes +FollowSymLinks -Includes
DirectoryIndex index.php /index.php
Order Deny,Allow
Deny from All
Satisfy Any
AuthName "Protected By AskApache"
AuthUserFile /home/askapache.com/.htpasswda1
AuthType Basic
Require valid-user
&lt;FilesMatch "\.(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$"&gt;
Allow from All
&lt;/FilesMatch&gt;
&lt;FilesMatch "(async-upload)\.php$"&gt;
&lt;IfModule mod_security.c&gt;
SecFilterEngine Off
&lt;/IfModule&gt;
Allow from All
&lt;/FilesMatch&gt;</pre>

<h4>Protect wp-content</h4>
<p>Denies any Direct request for files ending in .php with a 403 Forbidden.. May break plugins/themes [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-401">401</a>]</p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /wp-content/.*$ [NC]
RewriteCond %{REQUEST_FILENAME} !^.+flexible-upload-wp25js.php$
RewriteCond %{REQUEST_FILENAME} ^.+\.(php|html|htm|txt)$
RewriteRule .* - [F,NS,L]</pre>

<h4>Protect wp-includes</h4>
<p>Denies any Direct request for files ending in .php with a 403 Forbidden.. May break plugins/themes [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /wp-includes/.*$ [NC]
RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ /wp-includes/js/.+/.+\ HTTP/ [NC]
RewriteCond %{REQUEST_FILENAME} ^.+\.php$
RewriteRule .* - [F,NS,L]</pre>

<h4>Common Exploits</h4>
<p>Block common exploit requests with 403 Forbidden. These can help alot, may break some plugins. [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ ///.*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\?\=?(http|ftp|ssl|https):/.*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\?\?.*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.(asp|ini|dll).*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.(htpasswd|htaccess|aahtpasswd).*\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>Stop Hotlinking</h4>
<p>Denies any request for static files (images, css, etc) if referrer is not local site or empty. [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteCond %{HTTP_REFERER} !^http://www.askapache.com.*$ [NC]
RewriteRule \.(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$ - [F,NS,L]</pre>

<h4>Safe Request Methods</h4>
<p>Denies any request not using <a href="http://www.askapache.com/online-tools/request-method-scanner/">GET,PROPFIND,POST,OPTIONS,PUT,HEAD</a>[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} !^(GET|HEAD|POST|PROPFIND|OPTIONS|PUT)$ [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>Forbid Proxies</h4>
<p>Denies any POST Request using a Proxy Server. Can still access site, but not comment.  See <a href="http://perishablepress.com/press/2008/04/20/how-to-block-proxy-servers-via-htaccess/">Perishable Press</a> [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP:VIA}%{HTTP:FORWARDED}%{HTTP:USERAGENT_VIA}%{HTTP:X_FORWARDED_FOR}%{HTTP:PROXY_CONNECTION} !^$ [OR]
RewriteCond %{HTTP:XPROXY_CONNECTION}%{HTTP:HTTP_PC_REMOTE_ADDR}%{HTTP:HTTP_CLIENT_IP} !^$
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>Real wp-comments-post.php</h4>
<p>Denies any POST attempt made to a non-existing wp-comments-post.php[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/wp-comments-post\.php.*\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>HTTP PROTOCOL</h4>
<p>Denies any badly formed HTTP PROTOCOL in the request, 0.9, 1.0, and 1.1 only[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ .+\ HTTP/(0\.9|1\.0|1\.1) [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>SPECIFY CHARACTERS</h4>
<p>Denies any request for a url containing characters other than "a-zA-Z0-9.+/-?=&amp;"  - REALLY helps but may break your site depending on your links. [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ [a-zA-Z0-9\.\+_/\-\?\=\&amp;amp;]+\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>BAD Content Length</h4>
<p>Denies any POST request that doesnt have a Content-Length Header[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP:Content-Length} ^$
RewriteCond %{REQUEST_URI} !^/(wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>BAD Content Type</h4>
<p>Denies any POST request with a content type other than application/x-www-form-urlencoded|multipart/form-data[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP:Content-Type} !^(application/x-www-form-urlencoded|multipart/form-data.*(boundary.*)?)$ [NC]
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>Missing HTTP_HOST</h4>
<p>Denies requests that dont contain a HTTP HOST Header.[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteCond %{HTTP_HOST} ^$
RewriteRule .* - [F,NS,L]</pre>

<h4>Bogus Graphics Exploit</h4>
<p>Denies obvious exploit using bogus graphics[<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{HTTP:Content-Disposition} \.php [NC]
RewriteCond %{HTTP:Content-Type} image/.+ [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>No UserAgent, Not POST</h4>
<p>Denies POST requests by blank user-agents.  May prevent a small number of visitors from POSTING. [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP_USER_AGENT} ^-?$
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>No Referer, No Comment</h4>
<p>Denies any comment attempt with a blank HTTP_REFERER field, highly indicative of spam.  May prevent some visitors from POSTING. [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/wp-comments-post\.php.*\ HTTP/ [NC]
RewriteCond %{HTTP_REFERER} ^-?$
RewriteRule .* - [F,NS,L]</pre>

<h4>Trackback Spam</h4>
<p>Denies obvious trackback spam.  See Holy Shmoly! [<a href="/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP_USER_AGENT} ^.*(opera|mozilla|firefox|msie|safari).*$ [NC]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]</pre>

<h4>Map all URIs except those corresponding to existing files to a handler</h4>
<pre>RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule . /script.php</pre>

<h4>Map any request to a handler</h4>
<p>In the case where all URIs should be sent to the same place (including potentially requests for static content) the method to use depends on the type of the handler. For php scripts, use:
For other handlers such as php scripts, use:</p>
<pre>RewriteEngine On
RewriteCond %{REQUEST_URI} !=/script.php
RewriteRule .* /script.php</pre>

<h4>And for CGI scripts:</h4>
<pre>ScriptAliasMatch .* /var/www/script.cgi</pre>

<h4>Map URIs corresponding to existing files to a handler instead</h4>
<pre>RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
RewriteCond %{REQUEST_URI} !=/script.php
RewriteRule .* /script.php</pre>
<p>If the existing files you wish to have handled by your script have a common set of file extensions distinct from that of the hander, you can bypass mod_rewrite and use instead mod_actions. Let's say you want all .html and .tpl files to be dealt with by your script:</p>
<pre>Action foo-action /script.php
AddHandler foo-action html tpl</pre>

<h4>Deny access if var=val contains the string foo.</h4>
<pre>RewriteCond %{QUERY_STRING} foo
RewriteRule ^/url - [F]</pre>

<h4>Removing the Query String</h4>
<pre>RewriteRule ^/url /url?</pre>

<h4>Adding to the Query String</h4>
<p>Keep the existing query string using the Query String Append flag, but add var=val to the end.</p>
<pre>RewriteRule ^/url /url?var=val [QSA]</pre>

<h4>Rewriting For Certain Query Strings</h4>
<p>Rewrite URLs like http://askapache.com/url1?var=val to http://askapache.com/url2?var=val but don't rewrite if val isn't present.</p>
<pre>RewriteCond %{QUERY_STRING} val
RewriteRule ^/url1 /url2</pre>

<h4>Modifying the Query String</h4>
<p>Change any single instance of val in the query string to other_val when accessing /path. Note that %1 and %2 are back-references to the matched part of the regular expression in the previous RewriteCond.</p>
<pre>RewriteCond %{QUERY_STRING} ^(.*)val(.*)$
RewriteRule /path /path?%1other_val%2</pre>
<hr class="C" />






<h2>Best .htaccess Articles</h2>

<h3><a title="Apache HTTP Web Server htaccess tips and tricks" rel="chapter" href="http://www.askapache.com/htaccess/htaccess-for-webmasters.html">.htaccess for Webmasters</a></h3><ul><li><a title="htaccess trick to run requests through a cgi script" href="/htaccess/htaccess-for-webmasters.html#process-file-through-cgi">Process certain requests for files using a cgi script</a></li><li><a title="htaccess security for apache hacking" href="/htaccess/htaccess-for-webmasters.html#process-request-methods-with-script">Process Requests with certain Request Methods</a></li><li><a title="Apache ForceType Directive in htaccess process file" href="/htaccess/htaccess-for-webmasters.html#force-filetype-with-forcetype">Make any file be a certain filetype</a></li><li><a title="Using the IfModule Directive in Apache htaccess files." href="/htaccess/htaccess-for-webmasters.html#ifmodule-in-apache">Use IfModule directive for robust code</a></li></ul>

<h3><a title="mod_rewrite RewriteRule, RewriteCond help" rel="chapter" href="http://www.askapache.com/htaccess/mod_rewrite-tips-and-tricks.html">Mod_Rewrite URL Rewriting</a></h3><p><a class="hs hs13" href="/htaccess/crazy-advanced-mod_rewrite-tutorial.html#decoded"></a>Undocumented techniques and methods will allow you to utilize mod_rewrite at an  "expert level" by showing you how to <a href="/htaccess/crazy-advanced-mod_rewrite-tutorial.html#decoded">unlock its secrets</a>.</p><ul><li><a title="Search query string at QUERY_STRING" href="/htaccess/mod_rewrite-tips-and-tricks.html#check-for-key-in-query-string">Check for a key in QUERY_STRING</a></li><li><a title="Deny access using htaccess during certain time" href="/htaccess/mod_rewrite-tips-and-tricks.html#time-based-access">Block access to files during certain hours of the day</a></li><li><a title="Change underscores to hyphens for SEO URL" href="/htaccess/mod_rewrite-tips-and-tricks.html#convert-underscore-hyphen">Rewrite underscores to hyphens for SEO URL</a></li><li><a title="Rewriting WordPress RSS feeds to Feedburner in SEO friendly method" href="/htaccess/mod_rewrite-tips-and-tricks.html#redirect-wordpress-feed">Redirecting WordPress Feeds to Feedburner</a></li></ul>

<h3><a title="301 Redirects" rel="chapter" href="http://www.askapache.com/htaccess/seo-search-engine-friendly-redirects-without-mod_rewrite.html">301 Redirects without mod_rewrite</a></h3><ul><li><a title="301 Redirect single file" href="/htaccess/seo-search-engine-friendly-redirects-without-mod_rewrite.html#seo-301-redirect-single-file">Redirect single url</a></li><li><a title="301 Redirect new domain" href="/htaccess/seo-search-engine-friendly-redirects-without-mod_rewrite.html#seo-301-redirect-new-domain">Redirect to new Domain</a></li></ul>

<h3><a href="/htaccess/php-cgi-redirect_status.html">Secure PHP with .htaccess</a></h3>
<p><a class="IFL" title="Locking down your php.ini and php cgi with .htaccess" href="/htaccess/php-cgi-redirect_status.html"><img src="http://uploads.askapache.com/2008/01/jail-bars-1.png" alt="Locking down your php.ini and php cgi with .htaccess" title="jail bars 1 htaccess" /></a>If you have a php.cgi or php.ini file in your /cgi-bin/ directory or other pub directory, try requesting them from your web browser.  If your php.ini shows up or worse you are able to execute your php cgi, you'll need to secure it ASAP.  This shows several ways to secure these files, and other interpreters like perl, fastCGI, bash, csh, etc.<br class="C" /></p>

<h3><a href="/htaccess/htaccess-fresh.html">.htaccess Cookie Manipulation</a></h3><p><a class="IFL" title="Cookie Manipulation in .htaccess with RewriteRule" href="/htaccess/htaccess-fresh.html"><img src="http://uploads.askapache.com/2007/10/cookies.png" alt="Cookie Manipulation in .htaccess with RewriteRule" title="cookies htaccess" /></a><strong>Fresh <a href="/htaccess/htaccess.html">.htaccess</a> code</strong> for you!  Check out the Cookie Manipulation and environment variable usage with mod_rewrite!  I also included a couple Mod_Security .htaccess examples. <strong>Enjoy!</strong><br class="C" /></p><ul><li><a href="/htaccess/htaccess-fresh.html#modrewrite1">Mod_Rewrite .htaccess Examples</a></li><li><a href="/htaccess/htaccess-fresh.html#modrewrite2">Cookie Manipulation and Tests with mod_rewrite</a></li><li><a href="/htaccess/htaccess-fresh.html#modrewrite3">Setting Environment Variables</a></li><li><a href="/htaccess/htaccess-fresh.html#modrewrite4">Using the Environment Variable</a></li><li><a href="/htaccess/htaccess-fresh.html#modrewrite5">Mod_Security .htaccess Examples</a></li></ul>

<h3><a title="htaccess Caching" rel="chapter" href="http://www.askapache.com/htaccess/speed-up-your-site-with-caching-and-cache-control.html">.htaccess Caching</a></h3><ul><li><a href="/htaccess/speed-up-sites-with-htaccess-caching.html">Speed Up Sites with htaccess Caching</a></li><li><a title="htaccess time cheatsheet" href="/htaccess/speed-up-your-site-with-caching-and-cache-control.html#htaccess-time-cheatsheet">htaccess time cheat sheet</a></li></ul>

<h3><a title="401, 403 htpasswd authentication" rel="chapter" href="http://www.askapache.com/htaccess/apache-authentication-in-htaccess.html">Password Protection and Authentication</a></h3><ul><li><a title="Requiring a password for single file" href="/htaccess/apache-authentication-in-htaccess.html#require-password-for-single-file">Require password for single file</a></li><li><a title="A comprehensive default Apache .htaccess example file" href="/htaccess/apache-authentication-in-htaccess.html#skeleton-htaccess">Example .htaccess file for password protection</a></li></ul>

<h3><a title="Creating and using HTTP Headers with htaccess" rel="chapter" href="http://www.askapache.com/htaccess/using-http-headers-with-htaccess.html">Control HTTP Headers</a></h3><ul><li><a title="Prevent Browsers and Proxies from caching" href="/htaccess/using-http-headers-with-htaccess.html#prevent-caching-with-htaccess">Prevent Caching 100%</a></li><li><a title="Remove Internet Explorer imagetoolbar" href="/htaccess/using-http-headers-with-htaccess.html#remove-ie-imagetoolbar">Remove IE imagetoolbar without meta tag</a></li><li><a title="How To use Apache to send P3P Privacy Header for website" href="/htaccess/using-http-headers-with-htaccess.html#privacy-p3p-header-in-apache">Add Privacy (P3P) Header to your site</a></li><li><a title="Language header, Charset header without meta" href="/htaccess/using-http-headers-with-htaccess.html#language-and-content-header-in-htaccess">Add language and charset headers without meta tags</a></li></ul>

<h3><a href="/htaccess/blocking-bad-bots-and-scrapers-with-htaccess.html">Blocking Spam and bad Bots</a></h3><p><a class="IFR" href="/htaccess/blocking-bad-bots-and-scrapers-with-htaccess.html"><img title="Block Bad Robot" src="http://uploads.askapache.com/2008/04/bad_robot1.png" alt="Block Bad Robot" height="100" /></a>Want to block a bad robot or web scraper using .htaccess files?  Here are 2 methods that illustrate blocking 436 various user-agents.  You can block them using either SetEnvIf methods, or by using Rewrite Blocks.<br class="C" /></p>

<h3><a title="php htaccess tips, htaccess php tricks" rel="chapter" href="http://www.askapache.com/htaccess/php-htaccess-tips-and-tricks.html">PHP htaccess tips</a></h3><p>By using some cool .htaccess tricks we can control PHP to be run as a cgi or a module.  If php is run as a cgi then we need to compile it ourselves or use .htaccess to force php to use a local php.ini file.  If it is running as a module then we can use various directives supplied by that modules in .htaccess</p><ul><li><a title=".htaccess for php as cgi" href="/htaccess/php-htaccess-tips-and-tricks.html#php-run-as-cgi">When php run as CGI</a></li><li><a title="custom php.ini with Apache htaccess using PHPRC" href="/htaccess/php-htaccess-tips-and-tricks.html#htaccess-php-ini">Use a custom php.ini with mod_php or php as a cgi</a></li><li><a title="htaccess tips for mod_php php running as Apache module" href="/htaccess/php-htaccess-tips-and-tricks.html#sub-mod_php">When php run as Apache Module (mod_php)</a></li><li><a title="Apache FastCGI wrapper for php cgi" href="/htaccess/php-htaccess-tips-and-tricks.html#php-and-fastcgi-in-htaccess">When cgi php is run with wrapper (FastCGI)</a></li></ul>

<h3><a href="/htaccess/http-https-rewriterule-redirect.html">HTTP to HTTPS Redirects with mod_rewrite</a></h3><p><a href="/htaccess/http-https-rewriterule-redirect.html"><img class="IFL" src="http://uploads.askapache.com/2007/11/security.png" alt="HTTP to HTTPS Redirects with mod_rewrite" title="security htaccess" /></a>This is freaking sweet if you use SSL I promise you!  Basically instead of having to check for HTTPS using a <code>RewriteCond %{HTTPS} =on</code> for every redirect that can be either HTTP or HTTPS, I set an environment variable once with the value "http" or "https" if HTTP or HTTPS is being used for that request, and use that env variable in the RewriteRule.<br class="C" /></p>

<h3><a title="Apache SSL examples" rel="chapter" href="http://www.askapache.com/htaccess/ssl-example-usage-in-htaccess.html">SSL in .htaccess</a></h3><ul><li><a title="Redirecting non-SSL to SSL in Apache" href="/htaccess/ssl-example-usage-in-htaccess.html#redirect-http-to-https">Redirect non-https requests to https server</a></li><li><a title="redirect HTTP to HTTPS without mod_ssl!" href="/htaccess/ssl-example-usage-in-htaccess.html#rewrite-http-to-https-no-mod_ssl">Rewrite non-https to HTTPS without mod_ssl!</a></li><li><a title="Redirect HTTP to HTTPS by port" href="/htaccess/ssl-example-usage-in-htaccess.html#redirect-port-80-to-https">Redirect everything served on port 80 to HTTPS URI</a></li></ul>

<h3><a title="Conditionally setting variables in Apache .htaccess" rel="chapter" href="http://www.askapache.com/htaccess/setenvif.html">SetEnvIf and SetEnvIfNoCase in .htaccess</a></h3><ul><li><a title="Unique mod_setenvif Variables" href="/htaccess/setenvif.html#setenvif-variables">Unique mod_setenvif Variables</a></li><li><a title="Populates HTTP_MY_ Variables with mod_setenvif variable values" href="/htaccess/setenvif.html#http-headers">Populates HTTP_MY_ Variables with mod_setenvif variable values</a></li><li><a title="Allows only if HOST Header is present in request" href="/htaccess/setenvif.html#allow-host">Allows only if HOST Header is present in request</a></li><li><a title="Add values from HTTP Headers" href="/htaccess/setenvif.html#header-copy">Add values from HTTP Headers</a></li></ul>

<h3><a title="htaccess security and hacking" rel="chapter" href="http://www.askapache.com/htaccess/security-with-htaccess.html">Site Security with .htaccess</a></h3>
<p>chmod .htpasswd files 640, chmod .htaccess 644, php files 600, and chmod files that you really dont want people to see as 400. (NEVER chmod 777, try 766)</p>
<ul><li><a title="CHMOD .htaccess, chmod .htpasswd, chmodding files" href="/htaccess/security-with-htaccess.html#chmod-htaccess-info">CHMOD your files</a></li><li><a title="Deny access for htaccess/htpasswd file" href="/htaccess/security-with-htaccess.html#deny-htaccess-htpasswd-access">Prevent access to .htaccess and .htpasswd files</a></li><li><a title="Show source code in browser, prevent executing file" href="/htaccess/security-with-htaccess.html#show-source-code">Show Source Code instead of executing</a></li><li><a title="Remove execution privileges" href="/htaccess/security-with-htaccess.html#securing-directories-with-htaccess">Securing directories: Remove ability to execute scripts</a></li><li><a title="ErrorDocument usage in htaccess files" href="/htaccess/security-with-htaccess.html#errordocument-usage-in-htaccess">.htaccess ErrorDocuments</a></li></ul>

<h3><a title="mod_security Guide and sample mod_Security diretive usage in .htaccess" rel="chapter" href="http://www.askapache.com/htaccess/mod_security-htaccess-tricks.html">.htaccess Security with MOD_SECURITY</a></h3><ul><li><a href="/htaccess/mod_security-htaccess-tricks.html#mod_security-mod_rewrite">mod_security + mod_rewrite</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#block-post-spam">Block Spam by examining POST form fields</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#disable-mod_security">Disabling mod_security conditionally per IP</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#mod_security-authorization">Disabling mod_security with .htaccess Authorization</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#block-wordpress-spam">Block WordPress Spam Forever!</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#pause-connections">Force Any Connections to be Paused a set number of ms</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#mod_security-debugging">ModSecurity Debugging and Logging</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#conditional-logging">Turn Off/On Logging JUST for your IP Address</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#mod_security-directives">Mod_Security Directives for DreamHost</a></li><li><a href="/htaccess/mod_security-htaccess-tricks.html#httpdconf-rules">Example httpd.conf mod_security rule files</a></li></ul>
<hr class="C" />





<h3>Merging Notes</h3>
<p>The order of merging is:</p>
<ol>
<li><code>&lt;Directory&gt;</code> (except regular expressions) and .htaccess done simultaneously (with .htaccess, if allowed, overriding <code>&lt;Directory&gt;</code>)</li>
<li><code>&lt;DirectoryMatch&gt;</code> (and <code>&lt;Directory ~&gt;</code>)</li>
<li><code>&lt;Files&gt;</code> and <code>&lt;FilesMatch&gt;</code> done simultaneously</li>
<li><code>&lt;Location&gt;</code> and <code>&lt;LocationMatch&gt;</code> done simultaneously</li>
</ol>
<p>Below is an artificial example to show the order of merging. Assuming they all apply to the request, the directives in this example will be applied in the order:</p>
<p><code>A &gt; B &gt; C &gt; D &gt; E</code></p>.
<pre>&lt;Location /&gt;
E
&lt;/Location&gt;
&lt;Files askapache.txt&gt;
D
&lt;/Files&gt;
&lt;VirtualHost *&gt;
&lt;Directory /a/b&gt;
B
&lt;/Directory&gt;
&lt;/VirtualHost&gt;
&lt;DirectoryMatch "^.*b$"&gt;
C
&lt;/DirectoryMatch&gt;
&lt;Directory /a/b&gt;
A
&lt;/Directory&gt;</pre>





<h2>My Favorite .htaccess Links</h2>
<p class="anote">These are just some of my favorite <a href="http://www.google.com/Top/Computers/Internet/Web_Design_and_Development/Authoring/FAQs,_Help,_and_Tutorials/Access_Control/">.htaccess resources</a>.  I'm really into doing your own hacking to get knowledge and these links are all great resources in that respect.  I'm really interested in new or unusual htaccess solutions or htaccess hacks using .htaccess files, so let me know if you find one.</p>
<p><strong>NCSA HTTPd Tutorials</strong><br /></p>
<p><strong>Robert Hansen</strong><br />Here's a great <a href="http://www.securityfocus.com/infocus/1368">Hardening HTAccess part 1</a>, <a href="http://www.securityfocus.com/infocus/1369">part 2</a>, <a href="http://www.securityfocus.com/infocus/1370">part 3</a> article that goes into detail about some of the rarer security applications for .htaccess files.</p>
<p><strong>SAMAXES</strong><br />Some very detailed and helpful .htaccess articles, such as the <a href="http://www.samaxes.com/2008/04/20/htaccess-gzip-and-cache-your-site-for-faster-loading-and-bandwidth-saving/">".htaccess - gzip and cache your site for faster loading and bandwidth saving."</a></p>
<p><strong>PerishablePress</strong><br /><a href="http://perishablepress.com/press/2006/01/10/stupid-htaccess-tricks/">Stupid .htaccess tricks</a> is probably the <strong>best explanation online</strong> for many of the best .htaccess solutions, including many from this page. Unlike me they are fantastic writers, even for technical stuff they are very readable, so its a good blog to kick back on and read.  They also have a <a title="Eight Ways to Blacklist with Apache's mod_rewrite" href="http://perishablepress.com/press/2009/02/03/eight-ways-to-blacklist-with-apaches-mod_rewrite/">fantastic article</a> detailing how to block/deny specific requests using mod_rewrite.</p>
<p><strong>BlogSecurity</strong><br />Mostly a site for... blog security (which is really any web-app security) this blog has a few really impressive articles full of solid information for <a href="http://blogsecurity.net/wordpress/article-210607/">Hardening WordPress with .htaccess</a> among more advanced topics that can be challenging but effective.  This is a good site to subscribe to their feed, they publish plugin exploits and wordpress core vulnerabilities quite a bit.</p>
<p><strong>Check-These</strong><br />Oldschool security/unix dude with some incredibly detailed mod_rewrite tutorials, helped me the most when I first got into this, and a great guy too. See: <a href="http://check-these.info/mod_rewrite-basic.html">Basic Mod_Rewrite Guide</a>, and <a href="http://check-these.info/RewriteRule.html">Advanced Mod_Rewrite Tutorial</a></p>
<p><strong>Reaper-X</strong><br />Alot of .htaccess tutorials and code.  See: <a href="http://www.reaper-x.com/2007/09/01/hardening-wordpress-with-mod-rewrite-and-htaccess/">Hardening WordPress with Mod Rewrite and htaccess</a></p>
<p><strong>jdMorgan</strong><br /><a href="http://www.webmasterworld.com/profilev4.cgi?action=view&amp;member=jdMorgan">jdMorgan</a> is the Moderator of the <a href="http://www.webmasterworld.com/apache/">Apache Forum</a> at WebmasterWorld, a great place for answers.  In my experience he can answer any tough question pertaining to advanced .htaccess usage, haven't seen him stumped yet.</p>
<p><strong>The W3C</strong><br /><a href="http://www.w3.org/International/questions/qa-htaccess-charset">Setting Charset in .htaccess</a> is very informative.<br /></p>
<p><strong>Holy Shmoly!</strong><br />A great blogger with analysis of attacks and spam.  See: More ways to stop spammers and unwanted traffic.</p>
<p><strong>Apache Week</strong><br />A partnership with Red Hat back in the 90's that produced some <a href="http://www.apacheweek.com/features/userauth">excellent documentation</a>.</p>
<p><strong>Corz</strong><br />Here's a resource that I consider to have some of the most creative and ingenious ideas for .htaccess files, although the author is somewhat of a character ;) Its a trip trying to navigate around the site, a fun trip. Its like nothing I've ever seen. There are only a few articles on the site, but the htaccess articles are very original and well-worth a look. See: <a rel="nofollow" href="http://corz.org/serv/tricks/htaccess.php">htaccess tricks and tips</a>.</p>
<hr class="C" />







<h2>Htaccess Directives</h2>
<p class="anote">This is an AskApache.com exclusive <em>you won't find this anywhere else</em>.</p>
<p>Directory, DirectoryMatch, Files, FilesMatch, IfDefine, IfVersion, IfModule, Limit, LimitExcept, Location, LocationMatch, Proxy, ProxyMatch, VirtualHost, AcceptMutex, AcceptPathInfo, AccessFileName, Action, AddCharset, AddDefaultCharset, AddDescription, AddEncoding, AddHandler, AddInputFilter, AddLanguage, AddOutputFilter, AddOutputFilterByType, AddType, Alias, AliasMatch, AllowCONNECT, AllowOverride, Anonymous, Anonymous_Authoritative, Anonymous_LogEmail, Anonymous_MustGiveEmail, Anonymous_NoUserId, Anonymous_VerifyEmail, AuthAuthoritative, AuthDBMAuthoritative, AuthDBMGroupFile, AuthDBMType, AuthDBMUserFile, AuthDigestAlgorithm, AuthDigestDomain, AuthDigestFile, AuthDigestGroupFile, AuthDigestNcCheck, AuthDigestNonceFormat, AuthDigestNonceLifetime, AuthDigestQop, AuthDigestShmemSize, AuthGroupFile, AuthName, AuthType, AuthUserFile, BS2000Account, BrowserMatch, BrowserMatchNoCase, CacheNegotiatedDocs, CharsetDefault, CharsetOptions, CharsetSourceEnc, CheckSpelling, ContentDigest, CookieDomain, CookieExpires, CookieName, CookieStyle, CookieTracking, CoreDumpDirectory, DAV, DAVDepthInfinity, DAVMinTimeout, DefaultIcon, DefaultLanguage, DefaultType, DocumentRoot, ErrorDocument, ErrorLog, ExtFilterDefine, ExtFilterOptions, FancyIndexing, FileETag, ForceLanguagePriority, ForceType, GprofDir, Header, HeaderName, HostnameLookups, IdentityCheck, ImapBase, ImapDefault, ImapMenu, Include, IndexIgnore, LanguagePriority, LimitRequestBody, LimitRequestFields, LimitRequestFieldsize, LimitRequestLine, LimitXMLRequestBody, LockFile, LogLevel, MaxRequestsPerChild, MultiviewsMatch, NameVirtualHost, NoProxy, Options, PassEnv, PidFile, Port, ProxyBlock, ProxyDomain, ProxyErrorOverride, ProxyIOBufferSize, ProxyMaxForwards, ProxyPass, ProxyPassReverse, ProxyPreserveHost, ProxyReceiveBufferSize, ProxyRemote, ProxyRemoteMatch, ProxyRequests, ProxyTimeout, ProxyVia, RLimitCPU, RLimitMEM, RLimitNPROC, ReadmeName, Redirect, RedirectMatch, RedirectPermanent, RedirectTemp, RemoveCharset, RemoveEncoding, RemoveHandler, RemoveInputFilter, RemoveLanguage, RemoveOutputFilter, RemoveType, RequestHeader, Require, RewriteCond, RewriteRule, SSIEndTag, SSIErrorMsg, SSIStartTag, SSITimeFormat, SSIUndefinedEcho, Satisfy, ScoreBoardFile, Script, ScriptAlias, ScriptAliasMatch, ScriptInterpreterSource, ServerAdmin, ServerAlias, ServerName, ServerPath, ServerRoot, ServerSignature, ServerTokens, SetEnv, SetEnvIf, SetEnvIfNoCase, SetHandler, SetInputFilter, SetOutputFilter, Timeout, TypesConfig, UnsetEnv, UseCanonicalName, XBitHack, allow, deny, order, CGIMapExtension, EnableMMAP, ISAPIAppendLogToErrors, ISAPIAppendLogToQuery, ISAPICacheFile, ISAPIFakeAsync, ISAPILogNotSupported, ISAPIReadAheadBuffer, SSLLog, SSLLogLevel, MaxMemFree, ModMimeUsePathInfo, EnableSendfile, ProxyBadHeader, AllowEncodedSlashes, LimitInternalRecursion, EnableExceptionHook, TraceEnable, ProxyFtpDirCharset, AuthBasicAuthoritative, AuthBasicProvider, AuthDefaultAuthoritative, AuthDigestProvider, AuthLDAPAuthzEnabled, AuthLDAPBindDN, AuthLDAPBindPassword, AuthLDAPCharsetConfig, AuthLDAPCompareDNOnServer, AuthLDAPDereferenceAliases, AuthLDAPGroupAttribute, AuthLDAPGroupAttributeIsDN, AuthLDAPRemoteUserIsDN, AuthLDAPURL, AuthzDBMAuthoritative, AuthzDBMType, AuthzDefaultAuthoritative, AuthzGroupFileAuthoritative, AuthzLDAPAuthoritative, AuthzOwnerAuthoritative, AuthzUserAuthoritative, BalancerMember, DAVGenericLockDB, FilterChain, FilterDeclare, FilterProtocol, FilterProvider, FilterTrace, IdentityCheckTimeout, IndexStyleSheet, ProxyPassReverseCookieDomain, ProxyPassReverseCookiePath, ProxySet, ProxyStatus, ThreadStackSize, AcceptFilter, Protocol, AuthDBDUserPWQuery, AuthDBDUserRealmQuery, UseCanonicalPhysicalPort, CheckCaseOnly, AuthLDAPRemoteUserAttribute, ProxyPassMatch, SSIAccessEnable, Substitute, ProxyPassInterpolateEnv</p>
<hr class="C" />







<h2>Htaccess Modules</h2>
<p>Here are most of the modules that come with Apache.  Each one can have new commands that can be used in .htaccess file scopes.</p>
<p><a href="/servers/mod_actions.c.html">mod_actions</a>, <a href="/servers/mod_alias.c.html">mod_alias</a>, <a href="/servers/mod_asis.c.html">mod_asis</a>, <a href="/servers/mod_auth_basic.c.html">mod_auth_basic</a>, <a href="/servers/mod_auth_digest.c.html">mod_auth_digest</a>, <a href="/servers/mod_authn_anon.c.html">mod_authn_anon</a>, <a href="/servers/mod_authn_dbd.c.html">mod_authn_dbd</a>, <a href="/servers/mod_authn_dbm.c.html">mod_authn_dbm</a>, <a href="/servers/mod_authn_default.c.html">mod_authn_default</a>, <a href="/servers/mod_authn_file.c.html">mod_authn_file</a>, <a href="/servers/mod_authz_dbm.c.html">mod_authz_dbm</a>, <a href="/servers/mod_authz_default.c.html">mod_authz_default</a>, <a href="/servers/mod_authz_groupfile.c.html">mod_authz_groupfile</a>, <a href="/servers/mod_authz_host.c.html">mod_authz_host</a>, <a href="/servers/mod_authz_owner.c.html">mod_authz_owner</a>, <a href="/servers/mod_authz_user.c.html">mod_authz_user</a>, <a href="/servers/mod_autoindex.c.html">mod_autoindex</a>, <a href="/servers/mod_cache.c.html">mod_cache</a>, <a href="/servers/mod_cern_meta.c.html">mod_cern_meta</a>, <a href="/servers/mod_cgi.c.html">mod_cgi</a>, <a href="/servers/mod_dav.c.html">mod_dav</a>, <a href="/servers/mod_dav_fs.c.html">mod_dav_fs</a>, <a href="/servers/mod_dbd.c.html">mod_dbd</a>, <a href="/servers/mod_deflate.c.html">mod_deflate</a>, <a href="/servers/mod_dir.c.html">mod_dir</a>, <a href="/servers/mod_disk_cache.c.html">mod_disk_cache</a>, <a href="/servers/mod_dumpio.c.html">mod_dumpio</a>, <a href="/servers/mod_env.c.html">mod_env</a>, <a href="/servers/mod_expires.c.html">mod_expires</a>, <a href="/servers/mod_ext_filter.c.html">mod_ext_filter</a>, <a href="/servers/mod_file_cache.c.html">mod_file_cache</a>, <a href="/servers/mod_filter.c.html">mod_filter</a>, <a href="/servers/mod_headers.c.html">mod_headers</a>, <a href="/servers/mod_ident.c.html">mod_ident</a>, <a href="/servers/mod_imagemap.c.html">mod_imagemap</a>, <a href="/servers/mod_include.c.html">mod_include</a>, <a href="/servers/mod_info.c.html">mod_info</a>, <a href="/servers/mod_log_config.c.html">mod_log_config</a>, <a href="/servers/mod_log_forensic.c.html">mod_log_forensic</a>, <a href="/servers/mod_logio.c.html">mod_logio</a>, <a href="/servers/mod_mem_cache.c.html">mod_mem_cache</a>, <a href="/servers/mod_mime.c.html">mod_mime</a>, <a href="/servers/mod_mime_magic.c.html">mod_mime_magic</a>, <a href="/servers/mod_negotiation.c.html">mod_negotiation</a>, <a href="/servers/mod_proxy.c.html">mod_proxy</a>, <a href="/servers/mod_proxy_ajp.c.html">mod_proxy_ajp</a>, <a href="/servers/mod_proxy_balancer.c.html">mod_proxy_balancer</a>, <a href="/servers/mod_proxy_connect.c.html">mod_proxy_connect</a>, <a href="/servers/mod_proxy_ftp.c.html">mod_proxy_ftp</a>, <a href="/servers/mod_proxy_http.c.html">mod_proxy_http</a>, <a href="/servers/mod_rewrite.c.html">mod_rewrite</a>, <a href="/servers/mod_setenvif.c.html">mod_setenvif</a>, <a href="/servers/mod_speling.c.html">mod_speling</a>, <a href="/servers/mod_ssl.c.html">mod_ssl</a>, <a href="/servers/mod_status.c.html">mod_status</a>, <a href="/servers/mod_substitute.c.html">mod_substitute</a>, <a href="/servers/mod_unique_id.c.html">mod_unique_id</a>, <a href="/servers/mod_userdir.c.html">mod_userdir</a>, <a href="/servers/mod_usertrack.c.html">mod_usertrack</a>, <a href="/servers/mod_version.c.html">mod_version</a>, <a href="/servers/mod_vhost_alias.c.html">mod_vhost_alias</a></p>
<hr class="C" />





<h2>Htaccess Software</h2>
<p>Apache HTTP Server comes with the following <a href="http://httpd.apache.org/docs/trunk/programs/">programs</a>.</p>
<dl><dt><code>httpd</code></dt><dd>Apache hypertext transfer protocol server</dd><dt><code>apachectl</code></dt><dd>Apache HTTP server control interface</dd><dt><code>ab</code></dt><dd>Apache HTTP server benchmarking tool</dd><dt><code>apxs</code></dt><dd>APache eXtenSion tool</dd><dt><code>dbmmanage</code></dt><dd>Create and update user authentication files in DBM format for basic authentication</dd><dt><code>fcgistarter</code></dt><dd>Start a FastCGI program</dd><dt><code>htcacheclean</code></dt><dd>Clean up the disk cache</dd><dt><code>htdigest</code></dt><dd>Create and update user authentication files for digest authentication</dd><dt><code>htdbm</code></dt><dd>Manipulate DBM password databases.</dd><dt><code>htpasswd</code></dt><dd>Create and update user authentication files for basic authentication</dd><dt><code>httxt2dbm</code></dt><dd>Create dbm files for use with RewriteMap</dd><dt><code>logresolve</code></dt><dd>Resolve hostnames for IP-addresses in Apache logfiles</dd><dt>log_server_status</dt><dd>Periodically log the server's status</dd><dt><code>rotatelogs</code></dt><dd>Rotate Apache logs without having to kill the server</dd><dt>split-logfile</dt><dd>Split a multi-vhost logfile into per-host logfiles</dd><dt><code>suexec</code></dt><dd>Switch User For Exec</dd></dl>




















<h2>Technical Look at .htaccess</h2>
<p><a href="http://httpd.apache.org/docs/1.3/misc/API.html">Source: Apache API notes</a></p>
<h3>Per-directory configuration structures</h3>
<p>Let's look out how all of this plays out in mod_mime.c, which defines the file typing handler which emulates the NCSA server's behavior of determining file types from suffixes. What we'll be looking at, here, is the code which implements the AddType and AddEncoding commands. These commands can appear in .htaccess files, so they must be handled in the module's private per-directory data, which in fact, consists of two separate tables for MIME types and encoding information, and is declared as follows:</p>

<pre>table *forced_types;      /* Additional AddTyped stuff */
table *encoding_types;    /* Added with AddEncoding... */
mime_dir_config;</pre>

<p>When the server is reading a configuration file, or &lt;Directory&gt; section, which includes one of the MIME module's commands, it needs to create a mime_dir_config structure, so those commands have something to act on. It does this by invoking the function it finds in the module's `create per-dir config slot', with two arguments: the name of the directory to which this configuration information applies (or NULL for srm.conf), and a pointer to a resource pool in which the allocation should happen.</p>

<p>(If we are reading a .htaccess file, that resource pool is the per-request resource pool for the request; otherwise it is a resource pool which is used for configuration data, and cleared on restarts. Either way, it is important for the structure being created to vanish when the pool is cleared, by registering a cleanup on the pool if necessary).</p>

<p>For the MIME module, the per-dir config creation function just ap_pallocs the structure above, and a creates a couple of tables to fill it. That looks like this:</p>

<pre>void *create_mime_dir_config (pool *p, char *dummy)
mime_dir_config *new = (mime_dir_config *) ap_palloc (p, sizeof(mime_dir_config));
&nbsp;
new-&gt;forced_types = ap_make_table (p, 4);
new-&gt;encoding_types = ap_make_table (p, 4);</pre>


<p>Now, suppose we've just read in a .htaccess file. We already have the per-directory configuration structure for the next directory up in the hierarchy. If the .htaccess file we just read in didn't have any AddType or AddEncoding commands, its per-directory config structure for the MIME module is still valid, and we can just use it. Otherwise, we need to merge the two structures somehow.</p>

<p>To do that, the server invokes the module's per-directory config merge function, if one is present. That function takes three arguments: the two structures being merged, and a resource pool in which to allocate the result. For the MIME module, all that needs to be done is overlay the tables from the new per-directory config structure with those from the parent:</p>

<pre>void *merge_mime_dir_configs (pool *p, void *parent_dirv, void *subdirv)
mime_dir_config *parent_dir = (mime_dir_config *)parent_dirv;
mime_dir_config *subdir = (mime_dir_config *)subdirv;
mime_dir_config *new =  (mime_dir_config *)ap_palloc (p, sizeof(mime_dir_config));
new-&gt;forced_types = ap_overlay_tables (p, subdir-&gt;forced_types, parent_dir-&gt;forced_types);
new-&gt;encoding_types = ap_overlay_tables (p, subdir-&gt;encoding_types, parent_dir-&gt;encoding_types);</pre>


<p>As a note --- if there is no per-directory merge function present, the server will just use the subdirectory's configuration info, and ignore the parent's. For some modules, that works just fine (e.g., for the includes module, whose per-directory configuration information consists solely of the state of the XBITHACK), and for those modules, you can just not declare one, and leave the corresponding structure slot in the module itself NULL.</p>

<h3>Command handling</h3>
<p>Now that we have these structures, we need to be able to figure out how to fill them. That involves processing the actual AddType and AddEncoding commands. To find commands, the server looks in the module's command table. That table contains information on how many arguments the commands take, and in what formats, where it is permitted, and so forth. That information is sufficient to allow the server to invoke most command-handling functions with pre-parsed arguments. Without further ado, let's look at the AddType command handler, which looks like this (the AddEncoding command looks basically the same, and won't be shown here):</p>
<pre>char *add_type(cmd_parms *cmd, mime_dir_config *m, char *ct, char *ext)
if (*ext == &#039;.&#039;) ++ext;
ap_table_set (m-&gt;forced_types, ext, ct);</pre>

<p>This command handler is unusually simple. As you can see, it takes four arguments, two of which are pre-parsed arguments, the third being the per-directory configuration structure for the module in question, and the fourth being a pointer to a cmd_parms structure. That structure contains a bunch of arguments which are frequently of use to some, but not all, commands, including a resource pool (from which memory can be allocated, and to which cleanups should be tied), and the (virtual) server being configured, from which the module's per-server configuration data can be obtained if required.</p>

<p>Another way in which this particular command handler is unusually simple is that there are no error conditions which it can encounter. If there were, it could return an error message instead of NULL; this causes an error to be printed out on the server's stderr, followed by a quick exit, if it is in the main config files; for a .htaccess file, the syntax error is logged in the server error log (along with an indication of where it came from), and the request is bounced with a server error response (HTTP error status, code 500).</p>

<p>The MIME module's command table has entries for these commands, which look like this:</p>
<pre>command_rec mime_cmds[] =
{ "AddType", add_type, NULL, OR_FILEINFO, TAKE2, "a mime type followed by a file extension" },
{ "AddEncoding", add_encoding, NULL, OR_FILEINFO, TAKE2, "an encoding (e.g., gzip), followed by a file extension" },</pre>


<p>The entries in these tables are:</p>
<ul>
<li>The name of the command</li>
<li>The function which handles it a (void *) pointer, which is passed in the cmd_parms structure to the command handler --- this is useful in case many similar commands are handled by the same function.</li>
<li>A bit mask indicating where the command may appear. There are mask bits corresponding to each AllowOverride option, and an additional mask bit, RSRC_CONF, indicating that the command may appear in the server's own config files, but not in any .htaccess file.</li>
<li>A flag indicating how many arguments the command handler wants pre-parsed, and how they should be passed in. TAKE2 indicates two pre-parsed arguments. Other options are TAKE1, which indicates one pre-parsed argument, FLAG, which indicates that the argument should be On or Off, and is passed in as a boolean flag, RAW_ARGS, which causes the server to give the command the raw, unparsed arguments (everything but the command name itself). There is also ITERATE, which means that the handler looks the same as TAKE1, but that if multiple arguments are present, it should be called multiple times, and finally ITERATE2, which indicates that the command handler looks like a TAKE2, but if more arguments are present, then it should be called multiple times, holding the first argument constant.</li>
<li>Finally, we have a string which describes the arguments that should be present. If the arguments in the actual config file are not as required, this string will be used to help give a more specific error message. (You can safely leave this NULL).</li>
</ul>

<p>Finally, having set this all up, we have to use it. This is ultimately done in the module's handlers, specifically for its file-typing handler, which looks more or less like this; note that the per-directory configuration structure is extracted from the request_rec's per-directory configuration vector by using the ap_get_module_config function.</p>

<h3>Side notes --- per-server configuration, virtual servers, etc.</h3>
<p>The basic ideas behind per-server module configuration are basically the same as those for per-directory configuration; there is a creation function and a merge function, the latter being invoked where a virtual server has partially overridden the base server configuration, and a combined structure must be computed. (As with per-directory configuration, the default if no merge function is specified, and a module is configured in some virtual server, is that the base configuration is simply ignored).</p>

<p>The only substantial difference is that when a command needs to configure the per-server private module data, it needs to go to the cmd_parms data to get at it. Here's an example, from the alias module, which also indicates how a syntax error can be returned (note that the per-directory configuration argument to the command handler is declared as a dummy, since the module doesn't actually have per-directory config data):</p>




<p><a href="/htaccess/htaccess-rewrite.html">Continue Reading Page 2</a></p><p><a href="http://www.askapache.com/htaccess/htaccess.html"></a><a href="http://www.askapache.com/htaccess/htaccess.html">THE Ultimate Htaccess</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/htaccess/htaccess.html/feed</wfw:commentRss>
		<slash:comments>87</slash:comments>
		</item>
		<item>
		<title>.htaccess Plugin Blocks Spam, Hackers, and Password Protects Blog</title>
		<link>http://www.askapache.com/wordpress/htaccess-plugin-blocks-spam-hackers-password-protects-blog.html</link>
		<comments>http://www.askapache.com/wordpress/htaccess-plugin-blocks-spam-hackers-password-protects-blog.html#comments</comments>
		<pubDate>Sat, 22 Nov 2008 15:18:12 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.askapache.com/?p=1053</guid>
		<description><![CDATA[<p><a class="IFL" href="http://www.askapache.com/htaccess/htaccess-plugin-blocks-spam-hackers-and-password-protects-blog.html"><img src="http://uploads.askapache.com/2008/11/htaccess-plugin-2.png" alt=".htaccess security plugin 2" title=".htaccess security plugin 2" width="269" height="436" /></a><br /><br />Well what can I say, <strong>other than this is sooo DOPE</strong>!  Here is a list of the modules this plugin (version 4.7 unreleased) will automatically detect.  I compiled the list myself using every module included with any default Apache installation for ALL the versions listed below, 1.3 to 2.2+<br /><br />Want to know something else I'm including in this plugin?  For each and every module that is detected, this plugin can then detect ALL of the modules .htaccess Directives!  For instance, <code>RewriteRule, AccessFileName, AddHandler, etc..</code> are each a directive belonging to a module that is allowed to be used from within .htaccess files.<br /><br /><strong>Talk about sick.. these tricks have the diamond disease!</strong><br class="C" /></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/wordpress/htaccess-plugin-blocks-spam-hackers-password-protects-blog.html"></a><a href="http://www.askapache.com/wordpress/htaccess-plugin-blocks-spam-hackers-password-protects-blog.html"><cite>AskApache.com</cite></a></p><p><a class="IFL" href="http://uploads.askapache.com/2008/11/htaccess-plugin-2.png"><img src="http://uploads.askapache.com/2008/11/htaccess-plugin-2.png" alt=".htaccess security plugin 2" title=".htaccess security plugin 2" /></a><br /><br />Well what can I say, <strong>other than this is sooo DOPE</strong>!  Here is a <a href="#htaccess-module-list">list of the modules</a> this plugin (version 4.7 unreleased) will automatically detect.  I compiled the list myself using every module included with any default Apache installation for ALL the versions listed below, 1.3 to 2.2+<br /><br />Want to know something else I'm including in this plugin?  For each and every module that is detected, this plugin can then detect ALL of the modules .htaccess Directives!  For instance, <code>RewriteRule, AccessFileName, AddHandler, etc..</code> are each a directive belonging to a module that is allowed to be used from within .htaccess files.<br /><br /><strong>Talk about sick.. these tricks have the diamond disease!</strong><br class="C" /></p>



<h2>Screenshot Unreleased 4.7</h2>
<p>I've been making a lot of progress as these screenshots illustrate, including the ability to detect 100% accurately the modules that are enabled on your server.  Big deal!  you might say... "How does knowing the modules help?"</p>
<p>Well it just so happens that in addition to detecting which modules are loaded on your server, this plugin will also detect which Directives are enabled for each module that are allowed to be used from within your .htaccess file!  Future release will provide the ability to explore the different .htaccess directives allowed by your server, so you can do all sorts of cool Apache .htaccess tricks to secure your blog and make it run better.</p>

<p><a href="http://uploads.askapache.com/2008/11/htaccess-plugin-1.png"><img src="http://uploads.askapache.com/2008/11/htaccess-plugin-1.png" alt=".htaccess security plugin 1" title=".htaccess security plugin 1" /></a><br /><a href="http://uploads.askapache.com/2008/11/htaccess-plugin-3.png"><img src="http://uploads.askapache.com/2008/11/htaccess-plugin-3.png" alt=".htaccess security plugin 3" title=".htaccess security plugin 3" /></a><br /><a href="http://uploads.askapache.com/2008/11/htaccess-plugin-4.png"><img src="http://uploads.askapache.com/2008/11/htaccess-plugin-4.png" alt=".htaccess security plugin 4" title=".htaccess security plugin 4" /></a></p>

<h2><a id="htaccess-module-list">Apache Module Detection</a></h2>
<p>Future releases of this plugin will also let you search for non-default modules, wild, beta, and others.</p>
<ul>
	<li>mod_access</li>
	<li>mod_actions</li>
	<li>mod_alias</li>
	<li>mod_asis</li>
	<li>mod_auth</li>
	<li>mod_auth_anon</li>
	<li>mod_auth_basic</li>
	<li>mod_auth_dbm</li>
	<li>mod_auth_digest</li>
	<li>mod_auth_ldap</li>
	<li>mod_authn_alias</li>
	<li>mod_authn_anon</li>
	<li>mod_authn_dbd</li>
	<li>mod_authn_dbm</li>
	<li>mod_authn_default</li>
	<li>mod_authn_file</li>
	<li>mod_authnz_ldap</li>
	<li>mod_authz_dbm</li>
	<li>mod_authz_default</li>
	<li>mod_authz_groupfile</li>
	<li>mod_authz_host</li>
	<li>mod_authz_owner</li>
	<li>mod_authz_user</li>
	<li>mod_autoindex</li>
	<li>mod_bucketeer</li>
	<li>mod_cache</li>
	<li>mod_case_filter</li>
	<li>mod_case_filter_in</li>
	<li>mod_cern_meta</li>
	<li>mod_cgi</li>
	<li>mod_cgid</li>
	<li>mod_charset_lite</li>
	<li>mod_dav</li>
	<li>mod_dav_fs</li>
	<li>mod_dav_lock</li>
	<li>mod_dbd</li>
	<li>mod_deflate</li>
	<li>mod_dir</li>
	<li>mod_disk_cache</li>
	<li>mod_dumpio</li>
	<li>mod_echo</li>
	<li>mod_env</li>
	<li>mod_example</li>
	<li>mod_expires</li>
	<li>mod_ext_filter</li>
	<li>mod_file_cache</li>
	<li>mod_filter</li>
	<li>mod_headers</li>
	<li>mod_ident</li>
	<li>mod_imagemap</li>
	<li>mod_imap</li>
	<li>mod_include</li>
	<li>mod_info</li>
	<li>mod_isapi</li>
	<li>mod_log_config</li>
	<li>mod_log_forensic</li>
	<li>mod_logio</li>
	<li>mod_mem_cache</li>
	<li>mod_mime</li>
	<li>mod_mime_magic</li>
	<li>mod_mycore</li>
	<li>mod_negotiation</li>
	<li>mod_netware</li>
	<li>mod_nw_ssl</li>
	<li>mod_optional_fn_export</li>
	<li>mod_optional_fn_import</li>
	<li>mod_optional_hook_export</li>
	<li>mod_optional_hook_import</li>
	<li>mod_proxy</li>
	<li>mod_proxy_ajp</li>
	<li>mod_proxy_balancer</li>
	<li>mod_proxy_connect</li>
	<li>mod_proxy_ftp</li>
	<li>mod_proxy_http</li>
	<li>mod_rewrite</li>
	<li>mod_security</li>
	<li>mod_setenvif</li>
	<li>mod_so</li>
	<li>mod_speling</li>
	<li>mod_ssl</li>
	<li>mod_status</li>
	<li>mod_substitute</li>
	<li>mod_suexec</li>
	<li>mod_test</li>
	<li>mod_unique_id</li>
	<li>mod_userdir</li>
	<li>mod_usertrack</li>
	<li>mod_version</li>
	<li>mod_vhost_alias</li>
	<li>mod_win32</li>
</ul>

<p><a rel="lb" class="IFL hs hs35" href='http://uploads.askapache.com/2008/07/http-security-askapache.png' title="http-security-askapache"></a>The original plugin page and description <a href="http://www.askapache.com/wordpress/htaccess-password-protect.html">can be found here</a>.<br class="C" /></p>


<h2>UPDATE: 11/22/08</h2>

<p><a rel="lb" class="IFL hs hs35" href='http://uploads.askapache.com/2008/07/http-security-askapache.png' title="http-security-askapache"></a><strong>To make a long story short,</strong> I downloaded each major release of the apache httpd source code from version 1.3.0 to version 2.2.10, then I configured and compiled each for a custom HTTPD installation built from source.  This allowed me to find every directive allowed in .htaccess files for each particular version.  <strong style="font-weight:bold;">YES!</strong><br class="C" /></p>


<blockquote cite="http://wordpress.org/support/topic/214390"><cite><a href="http://wordpress.org/support/rss/topic/214390">http://wordpress.org/support/rss/topic/214390</a></cite><br />
I've been working on a completely improved version on/off for about a month with the specific goal of finally ending all the little errors that can crop up when dealing with .htaccess.

To that effect I am succeeding marvelously, first I've converted the plugin to a class (4+5 compat), I've replaced my error_handling with WordPress's WP_Error class, and the coolest change is the new tests I've added.

To make a long story short, I downloaded each major release of the apache httpd source code starting at version 1.3.0 and finishing with version 2.2.10, I then compiled each version and built a HTTPD from source for all the apache versions.

<em><code>1.3.0</code>, <code>1.3.1</code>, <code>1.3.11</code>, <code>1.3.12</code>, <code>1.3.14</code>, <code>1.3.17</code>, <code>1.3.19</code>, <code>1.3.2</code>, <code>1.3.20</code>, <code>1.3.22</code>, <code>1.3.23</code>, <code>1.3.24</code>, <code>1.3.27</code>, <code>1.3.28</code>, <code>1.3.29</code>, <code>1.3.3</code>, <code>1.3.31</code>, <code>1.3.32</code>, <code>1.3.33</code>, <code>1.3.34</code>, <code>1.3.35</code>, <code>1.3.36</code>, <code>1.3.37</code>, <code>1.3.39</code>, <code>1.3.4</code>, <code>1.3.41</code>, <code>1.3.6</code>, <code>1.3.9</code>, <code>2.0.35</code>, <code>2.0.36</code>, <code>2.0.39</code>, <code>2.0.40</code>, <code>2.0.42</code>, <code>2.0.43</code>, <code>2.0.44</code>, <code>2.0.45</code>, <code>2.0.46</code>, <code>2.0.47</code>, <code>2.0.48</code>, <code>2.0.49</code>, <code>2.0.50</code>, <code>2.0.51</code>, <code>2.0.52</code>, <code>2.0.53</code>, <code>2.0.54</code>, <code>2.0.55</code>, <code>2.0.58</code>, <code>2.0.59</code>, <code>2.0.61</code>, <code>2.0.63</code>, <code>2.1.3-beta</code>, <code>2.1.6-alpha</code>, <code>2.1.7-beta</code>, <code>2.1.8-beta</code>, <code>2.1.9-beta</code>, <code>2.2.0</code>, <code>2.2.10</code>, <code>2.2.2</code>, <code>2.2.3</code>, <code>2.2.4</code>, <code>2.2.6</code>, <code>2.2.8</code>, <code>2.2.9</code></em>


Then I went through each version and determined the compatible modules for that version, and I'm pretty confident that I was also able to find each and every directive allowed by the compatible modules for that version (including core directives).  See <a href="http://www.askapache.com/htaccess/htaccess.html#htaccess-directives">.htaccess directive list</a>.

Basically I can now test a server using a variety of methods and determine almost 100% accurately what version of Apache (down to the API) is running, what modules (and versions) are enabled, and each and every directive that is allowed or disallowed for that version.

So this is so awesome because now we can enable all sorts of additional security features.

Other big changes are:
<ul>
<li>Completely hands-off updates, so that updating the plugin keeps all your settings.</li>
<li>making each SID module have its own configuration and options (like protecting individual files, individual request, and custom exploit strings).</li>
<li>Advanced ErrorDocument usage and handling (like tracking repeat offenders and suggesting they be blocked, emailing admin with custom info, etc..)</li>
<li>Multi User/Group password Control</li>
</ul>
And this time I am developing the plugin using a plethora of wordpress installations and configurations, to make sure that it will work regardless of a custom siteurl, blogid, etc..

<strong>Release will come before 2009.. I have some vacations to take and business to finish first. </strong>
</blockquote>







<h2>.htaccess Security Modules</h2>
<h3><a id="htaccess-sid700" title="Directory Protection">Directory Protection</a></h3>
<p>Enable the DirectoryIndex Protection, preventing directory index listings and defaulting. [<a href="http://www.askapache.com/htaccess/htaccess.html">Disable</a>]</p>
<pre>Options -Indexes
DirectoryIndex index.html index.php /index.php</pre>





<h3><a id="htaccess-sid800" title="Password Protect wp-login.php">Password Protect wp-login.php</a></h3>
<p>Requires a valid user/pass to access the login page <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-401">401</a>]</p>
<pre>&lt;files wp-login.php&gt;
Order Deny,Allow
Deny from All
Satisfy Any
&nbsp;
AuthName "Protected By AskApache"
AuthUserFile /home/askapache.com/.htpasswda1
AuthType Basic
Require valid-user
&lt;/files&gt;</pre>





<h3><a id="htaccess-sid900" title="Password Protect wp-admin">Password Protect wp-admin</a></h3>
<p>Requires a valid user/pass to access any non-static (css, js, images) file in this directory. <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-401">401</a>]</p>
<pre>Options -ExecCGI -Indexes +FollowSymLinks -Includes
DirectoryIndex index.php /index.php
&nbsp;
Order Deny,Allow
&nbsp;
Deny from All
Satisfy Any
&nbsp;
AuthName "Protected By AskApache"
AuthUserFile /home/askapache.com/.htpasswda1
AuthType Basic
Require valid-user
&nbsp;
&lt;filesMatch "\.(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$"&gt;
Allow from All
&lt;/filesMatch&gt;
&nbsp;
&lt;filesMatch "(async-upload)\.php$"&gt;
&lt;ifModule mod_security.c&gt;
SecFilterEngine Off
&lt;/ifModule&gt;
Allow from All
&lt;/filesMatch&gt;</pre>




<h3><a id="htaccess-sid1000" title="Protect wp-content">Protect wp-content</a></h3>
<p>Denies any Direct request for files ending in .php with a 403 Forbidden.. May break plugins/themes [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-401">401</a>]</p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /wp-content/.*$ [NC]
RewriteCond %{REQUEST_FILENAME} !^.+flexible-upload-wp25js.php$
RewriteCond %{REQUEST_FILENAME} ^.+\.(php|html|htm|txt)$
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1010" title="Protect wp-includes">Protect wp-includes</a></h3>
<p>Denies any Direct request for files ending in .php with a 403 Forbidden.. May break plugins/themes [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /wp-includes/.*$ [NC]
RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ /wp-includes/js/.+/.+\ HTTP/ [NC]
RewriteCond %{REQUEST_FILENAME} ^.+\.php$
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1011" title="Common Exploits">Common Exploits</a></h3>
<p>Block common exploit requests with 403 Forbidden. These can help alot, may break some plugins. [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ ///.*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\?\=?(http|ftp|ssl|https):/.*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\?\?.*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.(asp|ini|dll).*\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.(htpasswd|htaccess|aahtpasswd).*\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1012" title="Stop Hotlinking">Stop Hotlinking</a></h3>
<p>Denies any request for static files (images, css, etc) if referrer is not local site or empty. [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteCond %{HTTP_REFERER} !^http://www.askapache.com.*$ [NC]
RewriteRule \.(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$ - [F,NS,L]</pre>





<h3><a id="htaccess-sid1015" title="Safe Request Methods">Safe Request Methods</a></h3>
<p>Denies any request not using <a href="http://www.askapache.com/online-tools/request-method-scanner/">GET,PROPFIND,POST,OPTIONS,PUT,HEAD</a> <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} !^(GET|HEAD|POST|PROPFIND|OPTIONS|PUT)$ [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1017" title="Forbid Proxies">Forbid Proxies</a></h3>
<p>Denies any POST Request using a Proxy Server. Can still access site, but not comment.  See <a href="http://perishablepress.com/press/2008/04/20/how-to-block-proxy-servers-via-htaccess/">Perishable Press</a> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP:VIA}%{HTTP:FORWARDED}%{HTTP:USERAGENT_VIA}%{HTTP:X_FORWARDED_FOR}%{HTTP:PROXY_CONNECTION} !^$ [OR]
RewriteCond %{HTTP:XPROXY_CONNECTION}%{HTTP:HTTP_PC_REMOTE_ADDR}%{HTTP:HTTP_CLIENT_IP} !^$
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteRule .* - [F,NS,L]</pre>






<h3><a id="htaccess-sid1018" title="Real wp-comments-post.php">Real wp-comments-post.php</a></h3>
<p>Denies any POST attempt made to a non-existing wp-comments-post.php <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/wp-comments-post\.php.*\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]</pre>






<h3><a id="htaccess-sid1019" title="HTTP PROTOCOL">HTTP PROTOCOL</a></h3>
<p>Denies any badly formed HTTP PROTOCOL in the request, 0.9, 1.0, and 1.1 only  <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ .+\ HTTP/(0\.9|1\.0|1\.1) [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1020" title="SPECIFY CHARACTERS">SPECIFY CHARACTERS</a></h3>
<p>Denies any request for a url containing characters other than "a-zA-Z0-9.+/-?=&"  - REALLY helps but may break your site depending on your links. [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ [a-zA-Z0-9\.\+_/\-\?\=\&amp;]+\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1021" title="BAD Content Length">BAD Content Length</a></h3>
<p>Denies any POST request that doesnt have a Content-Length Header <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP:Content-Length} ^$
RewriteCond %{REQUEST_URI} !^/(wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1022" title="BAD Content Type">BAD Content Type</a></h3>
<p>Denies any POST request with a content type other than application/x-www-form-urlencoded|multipart/form-data <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP:Content-Type} !^(application/x-www-form-urlencoded|multipart/form-data.*(boundary.*)?)$ [NC]
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1023" title="Directory Traversal">Directory Traversal</a></h3>
<p>Denies Requests containing ../ or ./. which is a directory traversal exploit attempt <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>





<h3><a id="htaccess-sid1024" title="PHPSESSID Cookie">PHPSESSID Cookie</a></h3>
<p>Only blocks when a PHPSESSID cookie is sent by the user and it contains characters other than 0-9a-z <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>





<h3><a id="htaccess-sid1025" title="NO HOST:">NO HOST:</a></h3>
<p>Denies requests that dont contain a HTTP HOST Header. <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteCond %{HTTP_HOST} ^$
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1026" title="Bogus Graphics Exploit">Bogus Graphics Exploit</a></h3>
<p>Denies obvious exploit using bogus graphics  <strong>- *** Safe, Use</strong> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{HTTP:Content-Disposition} \.php [NC]
RewriteCond %{HTTP:Content-Type} image/.+ [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1027" title="No UserAgent, No Post">No UserAgent, No Post</a></h3>
<p>Denies POST requests by blank user-agents.  May prevent a small number of visitors from POSTING. [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP_USER_AGENT} ^-?$
RewriteCond %{REQUEST_URI} !^/(wp-login.php|wp-admin/|wp-content/plugins/|wp-includes/).* [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1028" title="No Referer, No Comment">No Referer, No Comment</a></h3>
<p>Denies any comment attempt with a blank HTTP_REFERER field, highly indicative of spam.  May prevent some visitors from POSTING. [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*/wp-comments-post\.php.*\ HTTP/ [NC]
RewriteCond %{HTTP_REFERER} ^-?$
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1029" title="Trackback Spam">Trackback Spam</a></h3>
<p>Denies obvious trackback spam.   See <a href="http://ocaoimh.ie/2008/07/03/more-ways-to-stop-spammers-and-unwanted-traffic/">Holy Shmoly!</a> [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-403">403</a>]</p>
<pre>RewriteCond %{REQUEST_METHOD} =POST
RewriteCond %{HTTP_USER_AGENT} ^.*(opera|mozilla|firefox|msie|safari).*$ [NC]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.+/trackback/?\ HTTP/ [NC]
RewriteRule .* - [F,NS,L]</pre>





<h3><a id="htaccess-sid1030" title="SSL-Only Site">SSL-Only Site</a></h3>
<p>Redirects all non-SSL (https) requests to your https-enabled url [<a href="http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html#status-301">301</a>]</p>





<h3><a id="htaccess-sid2000" title="Anti-Spam, Anti-Exploits">Anti-Spam, Anti-Exploits</a></h3>
<p>Denies Obvious Spam and uses advanced mod_security protection [<a href="http://www.askapache.com/htaccess/mod_security-htaccess-tricks.html">Read More</a>]</p>


<h2>.htaccess Security Module Screenshot</h2>
<p><a rel="lb" href='http://uploads.askapache.com/2008/07/http-security-askapache.png'><img src="http://uploads.askapache.com/2008/07/http-security-askapache1.png" alt=".htaccess Plugin Blocks Spam, Hackers, and Password Protects Blog" title="http-security-askapache1" /></a></p><p><a href="http://www.askapache.com/wordpress/htaccess-plugin-blocks-spam-hackers-password-protects-blog.html"></a><a href="http://www.askapache.com/wordpress/htaccess-plugin-blocks-spam-hackers-password-protects-blog.html">.htaccess Plugin Blocks Spam, Hackers, and Password Protects Blog</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/wordpress/htaccess-plugin-blocks-spam-hackers-password-protects-blog.html/feed</wfw:commentRss>
		<slash:comments>43</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>
	</channel>
</rss>

