title: Apache Content Negotiation, File Extensions, and Permanent Redirects
body: <p>Given an Apache 2.x web server that uses <strong>Content Negotiation</strong> (<code>+MultiViews</code>) to access URLs <em>without</em> their extensions (e.g., allow <code>/foo</code> vs. <code>/foo.php</code> or <code>/foo.html</code>), how does one issue a <strong>301 permanent redirect</strong> when someone <em>does</em> in fact try to use those extensions?</p>
  
  <p>The goal is for all roads to lead to the <em>sans extension</em> version of the URL, so <code>/foo/</code> goes to <code>/foo</code>, and <code>/foo.html</code> goes to <code>/foo</code>. It's the latter one that is proving tricky. (Use case: There are scattered legacy URLs out on the internets that still use the extension. We want those to be permanently redirected.)</p>
  
  <p>There is the <a href="http://www.mattcutts.com/blog/canonical-link-tag/" rel="nofollow noreferrer">canonical link element</a> but, even in the accompanying slides, the suggestion is it's better to do the redirect server-side in the first place.</p>
  
  <p>I've been trying this with <strong>mod_rewrite</strong>, but it seems like Apache "beats me to it" as it were. It's as if the extension is simply ignored. "No need, I've got it covered" says Apache. But then you can't handle the permanent redirect, and thus extension and no-extension variants are both allowed. Not the desired result. :)</p>
  
  <p>Here's one example. Given a 2-4 character filename consisting of lower-case letters, and a test file placed in <code>/foo/file.html</code>, we want to permanently redirect to <code>/foo/file</code>:</p>
  
  <pre><code>Options +MultiViews
  RewriteEngine on
  ...
  RewriteRule ^foo/([a-z]{2,4}).html/$ /foo/$1 [R=301,L]
  </code></pre>
  
  <p><code>/foo/file/</code> and <code>/foo/file.html/</code> <em>do</em> redirect to <code>/foo/file</code>, but of course <code>/foo/file.html</code> <em>does not</em>. If we try a rule like the following (note the lack of a trailing slash before $):</p>
  
  <pre><code>RewriteRule ^foo/([a-z]{2,4}).html$ /foo/$1 [R=301,L]
  </code></pre>
  
  <p>... we end up with too many redirects because Apache acts as if the rule is the following, and so it ends up chasing its own tail:</p>
  
  <pre><code>RewriteRule ^foo/([a-z]{2,4})$ /foo/$1 [R=301,L]
  </code></pre>
  
  <p>In an attempt to be too clever for my own good, I also tried nested parentheses:</p>
  
  <pre><code>RewriteRule ^foo/(([a-z]{2,4}).html)$ /foo/$2 [R=301,L]
  </code></pre>
  
  <p>No dice. Redirect loop city.</p>
  
  <p>What would be really good is to capture this sort of thing "en masse" so I don't have all these special cases floating around in htaccess.</p>
  
  <p><a href="https://stackoverflow.com/questions/9261384/redirecting-files-with-html-extension-to-files-without-extension-in-url/">Another SO question began to address this</a> for the single case of handling html files, but the proposed solution ostensibly requires <em>disabling of Content Negotiation</em>, which isn't good if you still want to use it for images and other file extensions (as it is in my case).</p>
  
  <p>Extra credit: We also want to avoid trailing slashes, so if someone tries <code>/foo/</code> (which could itself be a .html or .php file) it goes to <code>/foo</code> no matter what. The first rule (above) accomplishes this, but I think it's due to +MultiViews. I have my doubts about using <code>DirectorySlash</code> here, as there may be some risk there that makes it not as worthwhile.</p>