1

This is my goal:

  • /any-directory-or-subdirectory should show the contents of /any-directory-or-subdirectory/index.html
  • /any-directory-or-subdirectory/ should redirect to /any-directory-or-subdirectory (no trailing slash)
  • /any-directory-or-subdirectory/index.html should redirect to /any-directory-or-subdirectory
  • /any-directory-or-subdirectory/something.html should show its own contents.

I have this working on a specific directory perfectly:

DirectorySlash Off
RewriteEngine on

RewriteRule ^specific-dir$ /specific-dir/index.html [L,E=LOOP:1]

RewriteCond %{ENV:REDIRECT_LOOP} !1
RewriteRule ^specific-dir/$ /specific-dir [R=301,L]

RewriteCond %{ENV:REDIRECT_LOOP} !1
RewriteRule ^specific-dir/index.html$ /specific-dir [R=301,L]

I need this to work on all subdirectories instead of a specific one and also for the same functions to work at the root of the site. I've tried a number of things to adapt this code to work like that but have not had any luck so far.

0

You don't need to explicitly set an environment variable (eg. LOOP) in order to avoid the redirect loop. You can use Apache's own REDIRECT_STATUS for this purpose. REDIRECT_STATUS is not set when the request is first processed and set to 200 (as in 200 OK) after the first successful rewrite.

I would also arrange your directives so that the external redirects are first, before the internal rewrite, since these would always need to execute first.

In order to make this work for any directory, you can set a regex pattern for the directory name (or rather the full URL-path if dealing with any level of subdirectory) and include a condition that checks whether the request maps to a directory. For example, try something like the following:

DirectorySlash Off
RewriteEngine on

# Strip trailing slash on directory
# (The root always has a slash, but the browser doesn't show it)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (.+)/$ /$1 [R,L]

# Strip trailing "/index.html" (including root)
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.*?)/?index\.html$ /$1 [R,L]

# Rewrite directory request to directory index
# (Any directory will already have had the trailing slash and "index.html" removed)
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (.*) /$1/index.html [L]

(.*?)/?index\.html$ - By making the captured group non-greedy (ie. (.*?)), it won't capture the optional slash that follows. If it did then would potentially copy the trailing slash to the substitution and result in an additional redirect (since the first rule would later remove it). And by making everything before the index.html optional, it will work for the document root as well.

Change the temporary (302) redirects to permanent (301) only when you are sure it's working OK. 301s are cached hard by the browser by default so can make testing problematic.

  • @mathOne Did you get anywhere with this? – MrWhite Aug 24 '17 at 18:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.