Meanwhile, after a full night's sleep at my end...
The line that's stuck in my mind is: The purpose of a RewriteCond is, paradoxically, to
prevent a rule from executing. A conditionless rule executes all the time. So I went back to the beginning.
#1 given a secure directory-- which I'll call /lockdown/ --within a non-secure site, the first step is
RewriteRule ^lockdown/(.*) [
example.com...] [R=301,L]
paired with
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
No condition needed, because the first rule has already intercepted all requests for /lockdown/. You could capture "lockdown/" as well, but no point since it is always the same.
#2 This pair of rules will, of course, not work as written. Both will create infinite redirects, the kind that makes your browser give up after ten-or-so tries and put up a message saying "This is going nowhere fast".
So then you add a condition to the first rule, the https redirect, saying something like
RewriteCond %{SERVER_PORT} ^80$
RewriteRule ^lockdown/(.*) [
example.com...] [R=301,L]
(adding anchors because port numbers can have more than two digits). Now, I kinda think that this single condition really ought to be
RewriteCond %{SERVER_PORT} !^443$ [OR]
RewriteCond %{HTTPS} !on
but don't quote me. It depends on how imaginative the user's browsers and/or your server can be. ("Correct requests are all alike. Incorrect requests are all different in their own way".--Tolstoy.) We'll continue saying ^80$ and ^443$ to keep things simple.
And conversely for the second rule
RewriteCond %{SERVER_PORT} ^443$
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
#3 But now that you've done this, there will be some requests for /lockdown/ that get past the first rule, so you need to exclude them in the second rule:
RewriteCond %{REQUEST_URI} !/lockdown
RewriteCond %{SERVER_PORT} ^443$
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
#4 You are not done yet. (This part is, ahem, your own fault ;)) The /lockdown/ directory contains non-page files that are used by other directories,
and those other directories contain non-page files that are used by /lockdown/ pages. So...
#4a constrain both rules to requests for pages. Assuming their names end in .html:
RewriteRule (^|/|\.html)$ https et cetera
"request is for front page-- i.e. request is empty --or for a directory, or for an .html page" Unfortunately that only works for non-capturing rules; capturing is messier. If you're lucky it's simply
RewriteRule ^lockdown/([^.]+(?:\.html)?)?$ et cetera
and
RewriteRule ^([^.]+(?:\.html)?)$ et cetera
But if your name is apache dot org and you have carelessly allowed literal periods to sneak into your file and/or directory names (hostname doesn't count), you'll have to allow for some server backtracking:
RewriteRule ^(.+(?:\.html|/))?$ et cetera
:: pause here to yawn, twiddle thumbs, check watch, allow a few minutes to elapse ::
#4b take all non-page requests and make them match the requesting page, not their own location. This time you're looking for
\.(?:css|js|jpg|png)$
(et cetera depending on what extensions are involved) with no option for slash alone: there has to be an extension.
Now your two rules have expanded to four. Sticking with the dotless version for simplicity's sake, and grouping them by protocol first, filetype second:
RewriteCond %{SERVER_PORT} ^80$
RewriteRule ^lockdown/([^.]+(\.html)?)?$ [
example.com...] [R=301,L]
RewriteCond %{HTTP_REFERER} https://
RewriteCond %{SERVER_PORT} ^80$
RewriteRule ^([^.]+\.(?:css|js|jpg|png))$ [
example.com...] [R=301,L]
(breakthrough here as I realize you don't have to check the non-page file's location, only its port and/or protocol)
RewriteCond %{REQUEST_URI} !/lockdown
RewriteCond %{SERVER_PORT} ^443$
RewriteRule ^([^.]+(\.html)?)$ http://www.example.com/$1 [R=301,L]
RewriteCond %{HTTP_REFERER} http://
RewriteCond %{SERVER_PORT} ^443$
RewriteRule ^([^.]+\.(?:css|js|jpg|png))$ http://www.example.com/$1 [R=301,L]
I
think that covers all bases.
Since each of the four rules is free-standing, you can arrange them in order of likelihood. Similarly, when a rule has more than one condition, list the conditions in order of
likelihood to fail. If you have a set of conditions linked with [OR], list the members of the set in order of
likelihood to succeed. The object in each case is to let the server finish its job and get out of there faster.
Any one nanosecond on any one request will not be noticeable. But if you've ever stumpled across a site that was loaded down with hotlinked images, you've seen what happens when those nano-, micro- and milliseconds start adding up :)