Score:1

Apache 2.4 expr - how to load a html file via RewriteRule?

my flag

On Apache 2.4, Having a bunch of mixed SEO friendly and dynamic URLs on an ecom site I want to implement a simple caching system for my blog posts and product pages. First I want to have md5(REQUEST_URI+QUERY_STRING) and then load the prerendered /cache/md5hashumfile.html that's all.

Here is my htaccess code:

    RewriteEngine on 
    RewriteBase /subfolder/
    RewriteCond "expr=%{DOCUMENT_ROOT}/subfolder/cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}\.html" -f 
    RewriteRule ^(.*)$ /cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}\.html [L]

When I do

Header set foo-doc-root "expr=%{DOCUMENT_ROOT}/subfolder/cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}\.html"
#Outputs
foo-doc-root:   /home/user/public_html/subfolder/cache/f427ac3f86b93f6869ef8c2ce847dbd6.html

I can verify in my headers the path is correct and the file exists exactly where I expect it.

I can verify the md5 sum of my URL been the same md5

Header set foo-uri "expr=%{REQUEST_URI}?%{QUERY_STRING}\.html"

Where can it be improved?

kz flag
"Where can it be improved?" - But I assume it's not working at all at present?
nikis avatar
my flag
No, unfortunately it does not.
ezra-s avatar
ru flag
In the RewriteCond I think I would capture the specific parts instead of repeating the same expression in the rewriterule . `RewriteCond "expr=%{DOCUMENT_ROOT}/subfolder/(cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}\.html)" -f` and then `RewriteRule ^ /%1 [L]`
kz flag
@DanielFerradal I think that's the right idea (you can't use _expressions_ in the `RewriteRule` anyway). However, there are some more fundamental errors here . The syntax for using expressions in a `RewriteCond` directive is not correct and I don't believe you can create arbitrary capturing groups like this - this is a regex _thing_, so a separate regex-condition is required to simply capture the result of the `md5()` function. I've explained some of this in [my answer](https://serverfault.com/a/1127451/49157).
kz flag
Just curious... at what point do you create the cache file? (How do you expire/delete the cache?)
ezra-s avatar
ru flag
As always, it is a pleasure to read your comments and answers @MrWhite. I should have been more specific that my comment wasn't aiming for a perfectly correct answer but a hint to a more correct approach. Thanks for your comments and answer, very specific and on point. Cheers!
nikis avatar
my flag
@MrWhite Thanks for your comments and answer. I will try your code later today. As you can see my strength isn't server/htaccess. About the Cache, I will capture the page using curl with specific http headers/user-agent for mobile, and one for desktop. We have one language and one currency at the moment, so for now I won't dig deeper than that. The script encapsulated in a model->method, will be run on product-edit event and separately via cron to reflect stock/price changes (ERP integration) 3 times a day. Separate cron for cleanup, that's it. I want to serve this for no-cookies requests.
Score:1
kz flag
RewriteBase /subfolder/
RewriteCond "expr=%{DOCUMENT_ROOT}/subfolder/cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}\.html" -f 
RewriteRule ^(.*)$ /cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}\.html [L]

You have a few errors here:

  • You are setting RewriteBase /subfolder/, however, this is not being used by this rule since you are using a root-relative substitution string (starting with a slash). Consequently, it looks like you are trying to rewrite to the wrong URL-path. ie. /cache/... instead of /subfolder/cache/.... EDIT: I assume this rule is being used in a directory (or .htaccess) context, otherwise the use of RewriteBase here is wholly invalid.

  • RewriteCond "expr= - This is not the correct syntax when using an Apache expression inside a RewriteCond directive. It looks like you are using mod_headers syntax. With mod_rewrite the TestString (1st argument) should be expr, then the CondPattern (2nd argument) is the expression. eg. RewriteCond expr expression.

  • -f (at the end) - Again, this is not the correct syntax. When using an Apache expression, the -f operator is part of the expression (CondPattern) and must come first. (Ordinarily, when using normal mod_rewrite syntax, the -f "test" is the CondPattern itself.)

  • You can't use expression syntax in the RewriteRule substitution string. You can, however, use backreferences to captured groups (regex) in the preceding conditions. So, calculate/capture the md5 hash in a condition and use a backreference instead.

Try the following instead:

RewriteBase /subfolder/
RewriteCond expr "-f '%{DOCUMENT_ROOT}/subfolder/cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}.html'"
RewriteCond expr "'cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}.html' =~ /(.+)/"
RewriteRule ^ %1 [L]

Additional notes:

  • ^(.*)$ - No need to captured the URL-path since you are using the REQUEST_URI server variable instead.
  • No need to backslash-escape literal dots in the RewriteRule substitution string - this is an "ordinary string", not a regex.
  • I've removed the slash prefix from the substitution string so that it will now take into account the RewriteBase.
  • The purpose of the 2nd RewriteCond directive is simply to capture the md5 hash file name (and file-path) to then use in the RewriteRule substitution using the %1 backreference.

The above does require two calls to the md5() function. You could try the following instead to reduce this to one (and to also remove the dependency on RewriteBase, since you are having to hardcode the /subfolder in the expression anyway):

RewriteCond expr "'/subfolder/cache/%{md5:%{REQUEST_URI}?%{QUERY_STRING}}.html' =~ /(.+)/"
RewriteCond expr "-f '%{DOCUMENT_ROOT}%1'"
RewriteRule ^ %1 [L]
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.