Right above your # Add missing trailing slashes to directories if a matching .html does not exist.
rule, try adding this rule that redirects when there is an html file and the request is NOT a directory AND there's a trailing slash:
# if request has a trailing slash
RewriteCond %{REQUEST_URI} ^/(.*)/$
# but it isn't a directory
RewriteCond %{DOCUMENT_ROOT}/%1 !-d
# and if the trailing slash is removed and a .html appended to the end, it IS a file
RewriteCond %{DOCUMENT_ROOT}/%1.html -f
# redirect without trailing slash
RewriteRule ^ /%1 [L,R=301]
This shouldn't conflict with the redirect rule following it because its conditions check for the exact opposite.
EDIT:
To handle the index.html thing, you need to change this rule that you have, which is appending the trailing slashes:
# Add missing trailing slashes to directories if a matching .html does not exist.
# If it's a request to a directory.
RewriteCond %{SCRIPT_FILENAME}/ -d
# And a HTML file does not (!) exist.
RewriteCond %{SCRIPT_FILENAME}.html !-f
# And there is not trailing slash redirect to add it.
RewriteRule [^/]$ %{REQUEST_URI}/ [R=301,L]
To:
# Add missing trailing slashes to directories if a matching .html does not exist.
# If it's a request to a directory.
RewriteCond %{REQUEST_FILENAME}/ -d
# And a HTML file does not (!) exist.
RewriteCond %{REQUEST_FILENAME}/index.html !-f
# And there is not trailing slash redirect to add it.
RewriteRule [^/]$ %{REQUEST_URI}/ [R=301,L]
This checks that the index.html
file is missing from the directory before adding the trailing slash. The reason you must have this is because of the information disclosure security issue when missing the trailing slash will actually expose all of your directory contents if you don't have the trailing slash. Now, add these rules to remove the trailing slash when there's an index.html
:
RewriteCond %{REQUEST_FILENAME} -d
# And a HTML file exists.
RewriteCond %{REQUEST_FILENAME}/index.html -f
# And there is a trailing slash redirect to remove it.
RewriteRule ^(.*?)/$ /$1 [R=301,L]
Now add these rules right after to explicitly display the index.html
when there is no trailing slash (note no R=301
in the rule's flags):
RewriteCond %{REQUEST_FILENAME} -d
# And a HTML file exists.
RewriteCond %{REQUEST_FILENAME}/index.html -f
# And there is no trailing slash show the index.html.
RewriteRule [^/]$ %{REQUEST_URI}/index.html [L]