Search code examples
apache.htaccessmod-rewriteurl-rewriting

.htaccess removing file extension is conflicting with folders of the same name


I'm removing file extensions (like .html) from the url with a .htaccess file. The code in the file is working fine, but as soon as there is a folder with the same name as the file without extension, it redirects to the folder instead of redirecting to the file. For example, if I have a demo.html file and a demo folder in the same directory, as soon as I type in the searchbar of the browser www.example.com/demo, it redirects to the folder, instead of the file. If I delete the folder and I type the same thing again, it works perfectly! Any help would be appreciated :) Here's the code in the .htaccess file:

RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]

RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [NC,L]

Solution

  • This is caused by a conflict with mod_dir. When you request a directory without a trailing slash, mod_dir will "fix" the URL and append a trailing slash with a 301 redirect. After which it will attempt to serve a DirectoryIndex document. This takes priority over your internal rewrite.

    To resolve this you need to disable this behaviour with DirectorySlash Off.

    For example:

    # Ensure that directory listings are disabled
    Options -Indexes
    
    # Prevent mod_dir appending a slash to physical directories
    DirectorySlash Off
    
    # Redirect to remove the ".html" extension
    RewriteCond %{THE_REQUEST} /([^.?]+)\.html [NC]
    RewriteRule ^ /%1 [NC,L,R=301]
    
    # Rewrite request to append ".html" extension if it exists
    RewriteCond %{DOCUMENT_ROOT}/$1.html -f
    RewriteRule (.*) $1.html [L]
    

    Directory listings (mod_autoindex) need to be disabled when you disable DirectorySlash because if mod_autoindex is enabled then when you request the directory without a slash, a directory listing will be generated, regardless of whether you have a DirectoryIndex document (eg. index.html) in that directory that would ordinarily prevent the directory listing being generated.

    Also, I've "fixed" your existing rules that remove and append the .html extension. The first rule that removes the .html extension could have potentially matched an instance of .html that appeared in the query string. And the second rule that appends the .html extension would have resulted in a rewrite-loop (500 error) if requesting /demo/<does-not-exist> - where demo is a directory and a file basename (as in your example).

    See my answer to a related question on ServerFault for more information on this potential rewrite-loop: