Test strings, substitutions and E= values all expand %{NAME} variables. The manual lists about fifty; these are the ones rules actually use:
| Group | Variables |
|---|---|
| Request | REQUEST_URI, THE_REQUEST, QUERY_STRING |
| Request details | REQUEST_METHOD, HTTPS, REQUEST_SCHEME |
| Files | REQUEST_FILENAME, DOCUMENT_ROOT |
| Headers | HTTP_HOST, HTTP_REFERER, %{HTTP:Name} |
| Client, server, time | REMOTE_ADDR, SERVER_PORT, TIME_HOUR |
| Prefixed | %{ENV:var}, %{SSL:var}, %{LA-U:var} |
Copying a few into environment variables and echoing them in a header shows their real values:
RewriteEngine On
RewriteRule ^vars/ - [E=U:%{REQUEST_URI},E=R:%{THE_REQUEST},E=F:%{REQUEST_FILENAME}]
RewriteRule ^vars/ - [E=S:%{HTTPS}/%{REQUEST_SCHEME}/%{SERVER_PORT},E=T:%{TIME}]
Header always set X-Vars "%{U}e|%{R}e|%{F}e|%{S}e|%{T}e"$ curl -sI 'localhost:8105/vars/a%20b/c?x=1' | grep X-Vars | tr '|' '\n' X-Vars: /vars/a b/c HEAD /vars/a%20b/c?x=1 HTTP/1.1 /var/www/example/vars off/http/80 20260923152832
REQUEST_URI is decoded and lacks the query string; THE_REQUEST is the raw request line (Stopping Rewrite Loops relies on it); REQUEST_FILENAME stops at vars, the first segment with no file behind it. Behind a TLS-terminating proxy HTTPS reads off, so test %{HTTP:X-Forwarded-Proto} from a proxy you trust (ProxyPass). A header tested in a condition joins Vary (unless [NV]) only when the rule fires: RewriteCond's rule sent Vary: X-Api-Version only to requests carrying it, so shared caches need an explicit Header append Vary.