Flags follow the substitution in brackets, comma-separated with no spaces, as in [R=301,L]:
| Group | Flags | What they do |
|---|---|---|
| Flow | L, END, N, C, S=n | Last, end, next, chain, skip n |
| Outcome | R=code, F, G, P, PT | Redirect, 403, 410, proxy, pass |
| Query string | QSA, QSD, QSL | Append, drop, split at last ? |
| Escaping | B, BNP, BCTLS, BNE, NE | Escape captures, or do not |
| Matching | NC, NS, UNC | No case, no subrequests, keep // |
| Side effects | E, CO, T, H, DPI | Env, cookie, type, handler |
| Safety valves | UnsafeAllow3F, UnsafePrefixStat | Reopen blocked behavior |
QSL arrived in 2.4.19, BCTLS and BNE in 2.4.57, UNC in 2.4.63, and the Unsafe pair in 2.4.60, whose fixes for CVE-2024-38474 and CVE-2024-38475 broke some old rules until the flag was added. R alone means 302, and a code outside 300-399 (R=410) drops the substitution.
RewriteEngine On
RewriteRule ^a$ show.php?x=1 [L]
RewriteRule ^b$ show.php?x=1 [QSA,L]
RewriteRule ^c$ /show.php [R=301,QSD,L]
RewriteRule ^s1/(.+)$ show.php?q=$1 [L]
RewriteRule ^s2/(.+)$ show.php?q=$1 [B,L]$ t '/a?y=2' '/b?y=2' '/c?y=2' /s1/x%20%26%20y /s2/x%20%26%20y
/a?y=2 200 {"x":"1"}
/b?y=2 200 {"x":"1","y":"2"}
/c?y=2 301 http://example.com/show.php
/s1/x%20%26%20y 403
/s2/x%20%26%20y 200 {"q":"x & y"}A substitution with ? replaces the query string unless QSA merges the old one in; QSD strips it from a redirect. The s1 capture decoded to x & y, and since 2.4.56 (the fix for CVE-2023-25690, request splitting) Apache 129 refuses a rewritten query string containing a space: 403, logged as AH10411: Rewritten query string contains control characters or spaces. [B] re-escaped the capture; use it on every capture that lands in a query string.