| <?xml version='1.0' encoding='UTF-8' ?> | |
| <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd"> | |
| <?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?> | |
| <!-- $LastChangedRevision$ --> | |
| <!-- | |
| Licensed to the Apache Software Foundation (ASF) under one or more | |
| contributor license agreements. See the NOTICE file distributed with | |
| this work for additional information regarding copyright ownership. | |
| The ASF licenses this file to You under the Apache License, Version 2.0 | |
| (the "License"); you may not use this file except in compliance with | |
| the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| --> | |
| <manualpage metafile="flags.xml.meta"> | |
| <parentdocument href="./">Rewrite</parentdocument> | |
| <title>RewriteRule Flags</title> | |
| <summary> | |
| <p>This document discusses the flags which are available to the | |
| <directive module="mod_rewrite">RewriteRule</directive> directive, | |
| providing detailed explanations and examples.</p> | |
| </summary> | |
| <seealso><a href="../mod/mod_rewrite.html">Module documentation</a></seealso> | |
| <seealso><a href="intro.html">mod_rewrite introduction</a></seealso> | |
| <seealso><a href="remapping.html">Redirection and remapping</a></seealso> | |
| <seealso><a href="htaccess.html">Per-directory Rewrites</a></seealso> | |
| <seealso><a href="vhosts.html">Virtual hosts</a></seealso> | |
| <seealso><a href="rewritemap.html">Using RewriteMap</a></seealso> | |
| <seealso><a href="avoid.html">When not to use mod_rewrite</a></seealso> | |
| <seealso><a href="tech.html">Technical details</a></seealso> | |
| <section id="introduction"><title>Introduction</title> | |
| <p>A <directive module="mod_rewrite">RewriteRule</directive> can have | |
| its behavior modified by one or more flags. Flags are included in | |
| square brackets at the end of the rule, and multiple flags are separated | |
| by commas.</p> | |
| <highlight language="config"> | |
| RewriteRule pattern target [Flag1,Flag2,Flag3] | |
| </highlight> | |
| <p>Each flag (with a few exceptions) has a short form, such as | |
| <code>CO</code>, as well as a longer form, such as <code>cookie</code>. | |
| While it is most common to use | |
| the short form, it is recommended that you familiarize yourself with the | |
| long form, so that you remember what each flag is supposed to do. | |
| Some flags take one or more arguments. Flags are not case sensitive.</p> | |
| <p>Flags that alter metadata associated with the request (T=, H=, E=) | |
| have no effect in <glossary ref="perdirectory">per-directory context</glossary>, when a substitution | |
| (other than '-') is performed during the same round of rewrite processing. | |
| </p> | |
| <p>Presented here are each of the available flags, along with an example | |
| of how you might use them.</p> | |
| </section> | |
| <section id="flag_quickref"><title>Flag Quick Reference</title> | |
| <p>Flags can be combined: <code>[R=301,L]</code>, <code>[P,QSA]</code>, | |
| <code>[E=VAR:val,L]</code>. This table groups them by purpose, ordered | |
| by how commonly each is used.</p> | |
| <table border="1" style="zebra"> | |
| <columnspec><column width=".12"/><column width=".22"/><column width=".38"/><column width=".28"/></columnspec> | |
| <tr> | |
| <th>Flag</th> | |
| <th>Purpose</th> | |
| <th>Effect</th> | |
| <th>Common combos</th> | |
| </tr> | |
| <tr><td colspan="4"><em><strong>Flow Control</strong></em></td></tr> | |
| <tr> | |
| <td><a href="#flag_l">[L]</a></td> | |
| <td>Last rule</td> | |
| <td>Stop processing rules (this pass)</td> | |
| <td>[R=301,L] [F] [G]</td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_end">[END]</a></td> | |
| <td>Full stop</td> | |
| <td>Stop all rewrite processing (no re-entry in .htaccess)</td> | |
| <td>[R=301,END]</td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_s">[S=N]</a></td> | |
| <td>Skip</td> | |
| <td>Skip next N rules (if/else logic)</td> | |
| <td></td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_n">[N]</a></td> | |
| <td>Next (loop)</td> | |
| <td>Restart ruleset from the top (caution: loop risk)</td> | |
| <td></td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_c">[C]</a></td> | |
| <td>Chain</td> | |
| <td>Tie rule to the next; if this fails, skip chained rules</td> | |
| <td></td> | |
| </tr> | |
| <tr><td colspan="4"><em><strong>Redirection and Proxying</strong></em></td></tr> | |
| <tr> | |
| <td><a href="#flag_r">[R=code]</a></td> | |
| <td>Redirect</td> | |
| <td>External redirect (default 302). Consider Redirect/RedirectMatch for simple cases</td> | |
| <td>[R=301,L] [R=302,L]</td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_p">[P]</a></td> | |
| <td>Proxy</td> | |
| <td>Reverse proxy to target (requires <module>mod_proxy</module>)</td> | |
| <td>[P,QSA]</td> | |
| </tr> | |
| <tr><td colspan="4"><em><strong>Access Control</strong></em></td></tr> | |
| <tr> | |
| <td><a href="#flag_f">[F]</a></td> | |
| <td>Forbidden</td> | |
| <td>Return 403 (implies [L])</td> | |
| <td></td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_g">[G]</a></td> | |
| <td>Gone</td> | |
| <td>Return 410 (implies [L])</td> | |
| <td></td> | |
| </tr> | |
| <tr><td colspan="4"><em><strong>URL / Query String</strong></em></td></tr> | |
| <tr> | |
| <td><a href="#flag_qsa">[QSA]</a></td> | |
| <td>Query string append</td> | |
| <td>Append original query string to substitution</td> | |
| <td>[QSA,L] [P,QSA]</td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_qsd">[QSD]</a></td> | |
| <td>Query string discard</td> | |
| <td>Drop original query string entirely</td> | |
| <td>[R=301,QSD,L]</td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_b">[B]</a></td> | |
| <td>Escape backrefs</td> | |
| <td>Re-encode special chars in backreferences</td> | |
| <td>[B,PT]</td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_ne">[NE]</a></td> | |
| <td>No escape</td> | |
| <td>Don't escape special chars in output (pass #, ? through)</td> | |
| <td>[R=301,NE,L]</td> | |
| </tr> | |
| <tr><td colspan="4"><em><strong>Metadata and Handlers</strong></em></td></tr> | |
| <tr> | |
| <td><a href="#flag_e">[E]</a></td> | |
| <td>Set env var</td> | |
| <td>Set an environment variable</td> | |
| <td>[E=VAR:val,L]</td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_t">[T]</a></td> | |
| <td>MIME type</td> | |
| <td>Force content type</td> | |
| <td></td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_h">[H]</a></td> | |
| <td>Handler</td> | |
| <td>Force a content handler</td> | |
| <td></td> | |
| </tr> | |
| <tr> | |
| <td><a href="#flag_pt">[PT]</a></td> | |
| <td>Pass through</td> | |
| <td>Pass result to next handler (needed with Alias/ScriptAlias)</td> | |
| <td>[PT,L]</td> | |
| </tr> | |
| <tr><td colspan="4"><em><strong>Cookie</strong></em></td></tr> | |
| <tr> | |
| <td><a href="#flag_co">[CO]</a></td> | |
| <td>Set cookie</td> | |
| <td>Set an HTTP cookie on the response</td> | |
| <td>[CO=name:val:.domain,R=302,L]</td> | |
| </tr> | |
| </table> | |
| </section> | |
| <section id="flag_b"><title>B (escape backreferences)</title> | |
| <p>The [B] flag instructs <directive | |
| module="mod_rewrite">RewriteRule</directive> to escape non-alphanumeric | |
| characters before applying the transformation.</p> | |
| <p><module>mod_rewrite</module> has to unescape URLs before mapping them, | |
| so backreferences are unescaped at the time they are applied. | |
| Using the B flag, non-alphanumeric characters in backreferences | |
| will be escaped. For example, consider the rule:</p> | |
| <p>For similar escaping of server variables, see | |
| the "escape" <a href="#mapfunc">mapping-function</a></p> | |
| <highlight language="config"> | |
| RewriteRule "^search/(.*)$" "/search.php?term=$1" | |
| </highlight> | |
| <p>Given a search term of 'x & y/z', a browser will encode it as | |
| 'x%20%26%20y%2Fz', making the request 'search/x%20%26%20y%2Fz'. Without the B | |
| flag, this rewrite rule will map to 'search.php?term=x & y/z', which | |
| isn't a valid URL, and so would be encoded as | |
| <code>search.php?term=x%20&y%2Fz=</code>, which is not what was intended.</p> | |
| <p>With the B flag set on this same rule, the parameters are re-encoded | |
| before being passed on to the output URL, resulting in a correct mapping to | |
| <code>/search.php?term=x%20%26%20y%2Fz</code>.</p> | |
| <highlight language="config"> | |
| RewriteRule "^search/(.*)$" "/search.php?term=$1" [B,PT] | |
| </highlight> | |
| <p>Note that you may also need to set <directive | |
| module="core">AllowEncodedSlashes</directive> to <code>On</code> to get this | |
| particular example to work, as httpd does not allow encoded slashes in URLs, and | |
| returns a 404 if it sees one.</p> | |
| <p>This escaping is particularly necessary in a proxy situation, | |
| when the backend may break if presented with an unescaped URL.</p> | |
| <p>An alternative to this flag is using a <directive module="mod_rewrite" | |
| >RewriteCond</directive> to capture against %{THE_REQUEST} which will capture | |
| strings in the encoded form.</p> | |
| <p>In 2.4.26 and later, you can limit the escaping to specific characters | |
| in backreferences by listing them: <code>[B=#?;]</code>. Note: The space | |
| character can be used in the list of characters to escape, but you must quote | |
| the entire third argument of <directive module="mod_rewrite">RewriteRule</directive> | |
| and the space must not be the last character in the list.</p> | |
| <highlight language="config"> | |
| # Escape spaces and question marks. The quotes around the final argument | |
| # are required when a space is included. | |
| RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B= ?]" | |
| </highlight> | |
| <p>To limit the characters escaped this way, see <a href="#flag_bne">#flag_bne</a> | |
| and <a href="#flag_bctls">#flag_bctls</a></p> | |
| <p>See <a href="tech.html#encoding">URL Encoding and Decoding</a> for | |
| a full explanation of how Apache decodes URIs before pattern matching.</p> | |
| </section> | |
| <section id="flag_bnp"><title>BNP|backrefnoplus (don't escape space to +)</title> | |
| <p>The [BNP] flag instructs <directive | |
| module="mod_rewrite">RewriteRule</directive> to escape the space character | |
| in a backreference to %20 rather than '+'. Useful when the backreference | |
| will be used in the path component rather than the query string.</p> | |
| <highlight language="config"> | |
| # Escape spaces to %20 in the path instead of + as used in form submission via | |
| # the query string | |
| RewriteRule "^search/(.*)$" "/search.php/$1" "[B,BNP]" | |
| </highlight> | |
| <p>This flag is available in version 2.4.26 and later.</p> | |
| <p>See <a href="tech.html#encoding">URL Encoding and Decoding</a> for | |
| background on how encoding is handled in the rewrite pipeline.</p> | |
| </section> | |
| <section id="flag_bctls"><title>BCTLS</title> | |
| <p>The [BCTLS] flag is similar to the [B] flag, but only escapes | |
| control characters and the space character. This is the same set of | |
| characters rejected when they are copied into the query string unencoded. | |
| </p> | |
| <highlight language="config"> | |
| # Escape control characters and spaces | |
| RewriteRule "^search/(.*)$" "/search.php/$1" "[BCTLS]" | |
| </highlight> | |
| <p>This flag is available in version 2.4.57 and later.</p> | |
| </section> | |
| <section id="flag_bne"><title>BNE</title> | |
| <p>The list of characters in [BNE=...] are treated as exclusions to the | |
| characters of the [B] or [BCTLS] flags. The listed characters will not be | |
| escaped. | |
| </p> | |
| <highlight language="config"> | |
| # Escape the default characters, but leave / | |
| RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B,BNE=/]" | |
| </highlight> | |
| <p>This flag is available in version 2.4.57 and later.</p> | |
| </section> | |
| <section id="flag_c"><title>C|chain</title> | |
| <p>The [C] or [chain] flag indicates that the <directive | |
| module="mod_rewrite">RewriteRule</directive> is chained to the next | |
| rule. That is, if the rule matches, then it is processed as usual and | |
| control moves on to the next rule. However, if it does not match, then | |
| the next rule, and any other rules that are chained together, are | |
| skipped.</p> | |
| <highlight language="config"> | |
| # Rewrite legacy product URLs to the new catalog app, | |
| # and add a tracking parameter — but only for the rewritten ones. | |
| RewriteRule "^/products/([0-9]+)$" "/catalog/item/$1" [C] | |
| RewriteRule "^/catalog/(.*)$" "/catalog/$1?via=legacy" [QSA] | |
| </highlight> | |
| <p>Without the [C] flag, the second rule would also match requests | |
| that arrive at <code>/catalog/</code> directly. The chain ensures the | |
| second rule is only applied when the first rule matched.</p> | |
| </section> | |
| <section id="flag_co"><title>CO|cookie</title> | |
| <p>The [CO], or [cookie] flag, allows you to set a cookie when a | |
| particular <directive module="mod_rewrite">RewriteRule</directive> | |
| matches. The argument consists of three required fields and five optional | |
| fields.</p> | |
| <p>The full syntax for the flag, including all attributes, is as | |
| follows:</p> | |
| <example> | |
| [CO=NAME:VALUE:DOMAIN:lifetime:path:secure:httponly:samesite] | |
| </example> | |
| <note type="warning"> | |
| <title>Security Warning</title> | |
| <p>Exercise care when constructing the argument from backreferences or other | |
| variable expansion. If any part of the argument is derived from user input, | |
| a malicious request may include delimiters or other unexpected values.</p> | |
| </note> | |
| <p>If a literal ':' character is needed in any of the cookie fields, an | |
| alternate syntax is available. To opt-in to the alternate syntax, the cookie | |
| "Name" should be preceded with a ';' character, and field separators should be | |
| specified as ';'.</p> | |
| <example> | |
| [CO=;NAME;VALUE:MOREVALUE;DOMAIN;lifetime;path;secure;httponly;samesite] | |
| </example> | |
| <p>You must declare a name, a value, and a domain for the cookie to be set.</p> | |
| <dl> | |
| <dt>Domain</dt> | |
| <dd>The domain for which you want the cookie to be valid. This may be a | |
| hostname, such as <code>www.example.com</code>, or it may be a domain, | |
| such as <code>.example.com</code>. It must be at least two parts | |
| separated by a dot. That is, it may not be merely <code>.com</code> or | |
| <code>.net</code>. Cookies of that kind are forbidden by the cookie | |
| security model.</dd> | |
| </dl> | |
| <p>You may optionally also set the following values:</p> | |
| <dl> | |
| <dt>Lifetime</dt> | |
| <dd>The time for which the cookie will persist, in minutes.</dd> | |
| <dd>A value of 0 indicates that the cookie will persist only for the | |
| current browser session. This is the default value if none is | |
| specified.</dd> | |
| <dd>A negative value causes the cookie to be unset in the browser.</dd> | |
| <dt>Path</dt> | |
| <dd>The path, on the current website, for which the cookie is valid, | |
| such as <code>/customers/</code> or <code>/files/download/</code>.</dd> | |
| <dd>By default, this is set to <code>/</code> - that is, the entire | |
| website.</dd> | |
| <dt>Secure</dt> | |
| <dd>If set to <code>secure</code>, <code>true</code>, or <code>1</code>, | |
| the cookie will only be permitted to be translated via secure (https) | |
| connections.</dd> | |
| <dt>httponly</dt> | |
| <dd>If set to <code>HttpOnly</code>, <code>true</code>, or | |
| <code>1</code>, the cookie will have the <code>HttpOnly</code> flag set, | |
| which means that the cookie is inaccessible to JavaScript code on | |
| browsers that support this feature.</dd> | |
| <dt>samesite</dt> | |
| <dd>If set to anything other than <code>false</code> or <code>0</code>, the <code>SameSite</code> | |
| attribute is set to the specified value. Typical values are <code>None</code>, | |
| <code>Lax</code>, and <code>Strict</code>. Available in 2.5.1 and later.</dd> | |
| </dl> | |
| <p>Consider this example:</p> | |
| <highlight language="config"> | |
| RewriteEngine On | |
| RewriteRule "^/index\.html" "-" [CO=frontdoor:yes:.example.com:1440:/] | |
| </highlight> | |
| <p>In the example give, the rule doesn't rewrite the request. | |
| The "-" rewrite target tells <module>mod_rewrite</module> to pass the request | |
| through unchanged. Instead, it sets a cookie | |
| called 'frontdoor' to a value of 'yes'. The cookie is valid for any host | |
| in the <code>.example.com</code> domain. It is set to expire in 1440 | |
| minutes (24 hours) and is returned for all URIs.</p> | |
| </section> | |
| <section id="flag_dpi"><title>DPI|discardpath</title> | |
| <p>The DPI flag causes the <glossary ref="pathinfo">PATH_INFO</glossary> | |
| that was appended to the rewritten | |
| <glossary ref="urlpath">URL-path</glossary> to be discarded.</p> | |
| <p>In <glossary ref="perdirectory">per-directory context</glossary>, the | |
| <glossary ref="urlpath">URL-path</glossary> each | |
| <directive>RewriteRule</directive> compares against is the concatenation | |
| of the current URL-path and PATH_INFO.</p> | |
| <p>The current URL-path can be the initial path as requested by the | |
| client, the result of a previous round of <module>mod_rewrite</module> | |
| processing, or the result of a prior rule in the current round of | |
| <module>mod_rewrite</module> processing.</p> | |
| <p>In contrast, the PATH_INFO that is appended to the URL-path before | |
| each rule reflects only the value of PATH_INFO before this round of | |
| <module>mod_rewrite</module> processing. As a consequence, if large | |
| portions of the URL-path are matched and copied into a substitution in multiple | |
| <directive>RewriteRule</directive> directives, without regard for | |
| which parts of the URL-path came from the current PATH_INFO, the final | |
| URL-path may have multiple copies of PATH_INFO appended to it.</p> | |
| <p>Use this flag on any substitution where the PATH_INFO that resulted | |
| from the previous mapping of this request to the filesystem is not of | |
| interest. This flag permanently forgets the PATH_INFO established | |
| before this round of <module>mod_rewrite</module> processing began. PATH_INFO will | |
| not be recalculated until the current round of <module>mod_rewrite</module> processing | |
| completes. Subsequent rules during this round of processing will see | |
| only the direct result of substitutions, without any PATH_INFO | |
| appended.</p> | |
| <highlight language="config"> | |
| # Request: /app/script.php/extra/path (PATH_INFO is /extra/path) | |
| # Without DPI, the substitution would see "script.php/extra/path" | |
| # and could inadvertently copy PATH_INFO into the result. | |
| RewriteRule "^script\.php(.*)$" "/new-app/handler$1" [DPI] | |
| </highlight> | |
| <p>The [DPI] flag discards <code>/extra/path</code> so that only the | |
| substitution result (<code>/new-app/handler</code>) is passed to | |
| subsequent rules or the final request.</p> | |
| </section> | |
| <section id="flag_e"><title>E|env</title> | |
| <p>With the [E], or [env] flag, you can set the value of an environment | |
| variable. Note that some environment variables may be set after the rule | |
| is run, thus unsetting what you have set. See <a href="../env.html">the | |
| Environment Variables document</a> for more details on how Environment | |
| variables work.</p> | |
| <p>The full syntax for this flag is:</p> | |
| <highlight language="config"> | |
| [E=VAR:VAL] | |
| [E=!VAR] | |
| </highlight> | |
| <p><code>VAL</code> may contain backreferences (<code>$N</code> or | |
| <code>%N</code>) which are expanded.</p> | |
| <p>Using the short form</p> | |
| <example> | |
| [E=VAR] | |
| </example> | |
| <p>you can set the environment variable named <code>VAR</code> to an | |
| empty value.</p> | |
| <p>The form</p> | |
| <example> | |
| [E=!VAR] | |
| </example> | |
| <p>allows to unset a previously set environment variable named | |
| <code>VAR</code>.</p> | |
| <p>Environment variables can then be used in a variety of | |
| contexts, including CGI programs, other RewriteRule directives, or | |
| CustomLog directives.</p> | |
| <p>The following example sets an environment variable called 'image' to a | |
| value of '1' if the requested URL-path is an image file. Then, that | |
| environment variable is used to exclude those requests from the access | |
| log.</p> | |
| <highlight language="config"> | |
| RewriteRule "\.(png|gif|jpg)$" "-" [E=image:1] | |
| CustomLog "logs/access_log" combined env=!image | |
| </highlight> | |
| <p>Note that this same effect can be obtained using <directive | |
| module="mod_setenvif">SetEnvIf</directive>. This technique is offered as | |
| an example, not as a recommendation.</p> | |
| <p><strong>Setting environment variables for tracking rewrites</strong></p> | |
| <p>At times, we want to maintain some kind of status when we | |
| perform a rewrite. For example, you want to make a note that | |
| you've done that rewrite, so that you can check later to see if a | |
| request came via that rewrite. One way to do this is by setting an | |
| environment variable.</p> | |
| <highlight language="config"> | |
| RewriteEngine on | |
| RewriteRule "^/horse/(.*)" "/pony/$1" [E=<strong>rewritten:1</strong>] | |
| </highlight> | |
| <p>Later in your ruleset you might check for this environment | |
| variable using a RewriteCond:</p> | |
| <highlight language="config"> | |
| RewriteCond "%{ENV:rewritten}" =1 | |
| </highlight> | |
| <p>Note that environment variables do not survive an external | |
| redirect. You might consider using the [CO] flag to set a | |
| cookie.</p> | |
| <note><title>REDIRECT_ prefix after internal redirects</title> | |
| <p>In <glossary ref="perdirectory">per-directory context</glossary>, | |
| a successful substitution triggers an internal redirect. When this | |
| happens, all environment variables set during the previous pass — | |
| including those created with <code>[E=VAR:VAL]</code> — are renamed | |
| with a <code>REDIRECT_</code> prefix. A variable you set as | |
| <code>rewritten</code> becomes <code>REDIRECT_rewritten</code> in | |
| the redirected request.</p> | |
| <p>To test for the renamed variable, reference it with the | |
| prefix:</p> | |
| </note> | |
| <highlight language="config"> | |
| RewriteRule "^/horses/(.*)" "/ponies/$1" [E=rewritten:1] | |
| # In the next pass, the variable has been renamed: | |
| RewriteCond "%{ENV:REDIRECT_rewritten}" =1 | |
| RewriteRule "^/ponies/(.*)" "-" [E=seen_redirect:1,L] | |
| </highlight> | |
| <p>If the request is redirected multiple times, the prefix stacks: | |
| <code>REDIRECT_REDIRECT_rewritten</code>, and so on. See | |
| <a href="../env.html#redirect-vars">REDIRECT_ variables</a> for | |
| the complete description of this mechanism.</p> | |
| </section> | |
| <section id="flag_end"><title>END</title> | |
| <p>Using the [END] flag terminates not only the current round of rewrite | |
| processing (like [L]) but also prevents any subsequent rewrite | |
| processing from occurring in | |
| <glossary ref="perdirectory">per-directory</glossary> context. This | |
| makes it the preferred flag for most per-directory rules.</p> | |
| <p>In server or virtualhost context, [END] and [L] behave identically. | |
| The difference matters in per-directory context, where [L] stops the | |
| current pass but the ruleset is re-applied on the rewritten URL. This | |
| can cause infinite loops. [END] prevents all further rewrite processing, | |
| breaking the cycle.</p> | |
| <highlight language="config"> | |
| # In .htaccess: route all requests to a front controller | |
| # [L] would cause a loop here; [END] does not | |
| RewriteCond "%{REQUEST_FILENAME}" !-f | |
| RewriteCond "%{REQUEST_FILENAME}" !-d | |
| RewriteRule "^(.*)$" "/index.php" [END] | |
| </highlight> | |
| <p>This does not apply to new requests resulting from external | |
| redirects.</p> | |
| <p>See the <a href="htaccess.html#loops">Per-directory Rewrites</a> | |
| discussion for a detailed explanation of why [L] behaves differently | |
| in per-directory context, and when [END] is the right choice.</p> | |
| </section> | |
| <section id="flag_f"><title>F|forbidden</title> | |
| <p>Using the [F] flag causes the server to return a 403 Forbidden status | |
| code to the client. While the same behavior can be accomplished using | |
| the <directive module="mod_access_compat">Deny</directive> directive, this | |
| allows more flexibility in assigning a Forbidden status.</p> | |
| <p>The following rule will forbid <code>.exe</code> files from being | |
| downloaded from your server.</p> | |
| <highlight language="config"> | |
| RewriteRule "\.exe" "-" [F] | |
| </highlight> | |
| <p>This example uses the "-" syntax for the rewrite target, which means | |
| that the requested URL-path is not modified. There's no reason to rewrite to | |
| another URL-path, if you're going to forbid the request.</p> | |
| <p>When using [F], an [L] is implied - that is, the response is returned | |
| immediately, and no further rules are evaluated.</p> | |
| </section> | |
| <section id="flag_g"><title>G|gone</title> | |
| <p>The [G] flag forces the server to return a 410 Gone status with the | |
| response. This indicates that a resource used to be available, but is no | |
| longer available.</p> | |
| <p>As with the [F] flag, you will typically use the "-" syntax for the | |
| rewrite target when using the [G] flag:</p> | |
| <highlight language="config"> | |
| RewriteRule "oldproduct" "-" [G,NC] | |
| </highlight> | |
| <p>When using [G], an [L] is implied - that is, the response is returned | |
| immediately, and no further rules are evaluated.</p> | |
| </section> | |
| <section id="flag_h"><title>H|handler</title> | |
| <p>Forces the resulting request to be handled with the specified | |
| handler. For example, one might use this to force all files without a | |
| file extension to be parsed by the php handler:</p> | |
| <highlight language="config"> | |
| RewriteRule "!\." "-" [H=application/x-httpd-php] | |
| </highlight> | |
| <p> | |
| The regular expression above - <code>!\.</code> - will match any request | |
| that does not contain the literal <code>.</code> character. | |
| </p> | |
| <p>This can be also used to force the handler based on some conditions. | |
| For example, the following snippet used in per-server context allows | |
| <code>.php</code> files to be <em>displayed</em> by <code>mod_php</code> | |
| if they are requested with the <code>.phps</code> extension:</p> | |
| <highlight language="config"> | |
| RewriteRule "^(/source/.+\.php)s$" "$1" [H=application/x-httpd-php-source] | |
| </highlight> | |
| <p>The regular expression above - <code>^(/source/.+\.php)s$</code> - will | |
| match any request that starts with <code>/source/</code> followed by 1 or | |
| n characters followed by <code>.phps</code> literally. The backreference | |
| $1 referrers to the captured match within parenthesis of the regular | |
| expression.</p> | |
| </section> | |
| <section id="flag_l"><title>L|last</title> | |
| <p>The [L] flag causes <module>mod_rewrite</module> to stop processing | |
| the rule set. In most contexts, this means that if the rule matches, no | |
| further rules will be processed. This corresponds to the | |
| <code>last</code> command in Perl, or the <code>break</code> command in | |
| C. Use this flag to indicate that the current rule should be applied | |
| immediately without considering further rules.</p> | |
| <p>In <glossary ref="perdirectory">per-directory</glossary> context, | |
| [L] stops the current pass through the ruleset, but the rewritten | |
| request may be re-processed from the top — which can cause loops. | |
| Use the <a href="#flag_end">[END]</a> flag to prevent this, or see | |
| the <a href="htaccess.html#loops">Per-directory Rewrites</a> document | |
| for a full discussion of the issue and alternative solutions.</p> | |
| <p>The example given here will rewrite any request to | |
| <code>index.php</code>, giving the original request as a query string | |
| argument to <code>index.php</code>, however, the <directive | |
| module="mod_rewrite">RewriteCond</directive> ensures that if the request | |
| is already for <code>index.php</code>, the <directive | |
| module="mod_rewrite">RewriteRule</directive> will be skipped.</p> | |
| <highlight language="config"> | |
| RewriteBase "/" | |
| RewriteCond "%{REQUEST_URI}" !=/index.php | |
| RewriteRule "^(.*)" "/index.php?req=$1" [L,PT] | |
| </highlight> | |
| </section> | |
| <section id="flag_n"><title>N|next</title> | |
| <p> | |
| The [N] flag causes the ruleset to start over again from the top, using | |
| the result of the ruleset so far as a starting point. Use | |
| with extreme caution, as it may result in loop. | |
| </p> | |
| <p> | |
| The [Next] flag could be used, for example, if you wished to replace a | |
| certain string or letter repeatedly in a request. The example shown here | |
| will replace A with B everywhere in a request, and will continue doing | |
| so until there are no more As to be replaced. | |
| </p> | |
| <highlight language="config"> | |
| RewriteRule "(.*)A(.*)" "$1B$2" [N] | |
| </highlight> | |
| <p>You can think of this as a <code>while</code> loop: While this | |
| pattern still matches (i.e., while the URL-path still contains an | |
| <code>A</code>), perform this substitution (i.e., replace the | |
| <code>A</code> with a <code>B</code>).</p> | |
| <p>In 2.5.0 and later, this module returns an error after 10,000 iterations to | |
| protect against unintended looping. An alternative maximum number of | |
| iterations can be specified by adding to the N flag. </p> | |
| <highlight language="config"> | |
| # Be willing to replace 1 character in each pass of the loop | |
| RewriteRule "(.+)[><;]$" "$1" [N=32000] | |
| # ... or, give up if after 10 loops | |
| RewriteRule "(.+)[><;]$" "$1" [N=10] | |
| </highlight> | |
| </section> | |
| <section id="flag_nc"><title>NC|nocase</title> | |
| <p>Use of the [NC] flag causes the <directive | |
| module="mod_rewrite">RewriteRule</directive> to be matched in a | |
| case-insensitive manner. That is, it doesn't care whether letters appear | |
| as upper-case or lower-case in the matched URL-path.</p> | |
| <p>In the example below, any request for an image file will be proxied | |
| to your dedicated image server. The match is case-insensitive, so that | |
| <code>.jpg</code> and <code>.JPG</code> files are both acceptable, for | |
| example.</p> | |
| <highlight language="config"> | |
| RewriteRule "(.*\.(jpg|gif|png))$" "http://images.example.com$1" [P,NC] | |
| </highlight> | |
| </section> | |
| <section id="flag_ne"><title>NE|noescape</title> | |
| <p>By default, when a <directive module="mod_rewrite">RewriteRule</directive> | |
| results in an external redirect, any characters in the output that are | |
| not in the following safe set will be converted to their hexcode | |
| (percent-encoded) equivalents:</p> | |
| <ul> | |
| <li>Alphanumeric characters: <code>A-Z</code>, <code>a-z</code>, | |
| <code>0-9</code></li> | |
| <li>Special characters: <code>$-_.+!*'(),:;@&=/~</code></li> | |
| </ul> | |
| <p>For example, <code>#</code> would be converted to <code>%23</code>, | |
| and <code>?</code> to <code>%3F</code>. The <code>%</code> character | |
| is also escaped (to <code>%25</code>), which means that any | |
| percent-encoding already present in the substitution will be | |
| double-encoded.</p> | |
| <p>Using the [NE] flag prevents this escaping, allowing characters | |
| such as <code>#</code> and <code>?</code> to pass through to the | |
| redirect URL unmodified.</p> | |
| <highlight language="config"> | |
| RewriteRule "^/anchor/(.+)" "/bigpage.html#$1" [NE,R] | |
| </highlight> | |
| <p> | |
| The above example will redirect <code>/anchor/xyz</code> to | |
| <code>/bigpage.html#xyz</code>. Omitting the [NE] will result in the # | |
| being converted to its hexcode equivalent, <code>%23</code>, which will | |
| then result in a 404 Not Found error condition. | |
| </p> | |
| <p>See <a href="tech.html#encoding">URL Encoding and Decoding</a> for | |
| the full picture of how Apache encodes and decodes URIs during | |
| rewriting.</p> | |
| </section> | |
| <section id="flag_ns"><title>NS|nosubreq</title> | |
| <p>Use of the [NS] flag prevents the rule from being used on | |
| subrequests. For example, a page which is included using an SSI (Server | |
| Side Include) is a subrequest, and you may want to avoid rewrites | |
| happening on those subrequests. Also, when <module>mod_dir</module> | |
| tries to find out information about possible directory default files | |
| (such as <code>index.html</code> files), this is an internal | |
| subrequest, and you often want to avoid rewrites on such subrequests. | |
| On subrequests, it is not always useful, and can even cause errors, if | |
| the complete set of rules are applied. Use this flag to exclude | |
| problematic rules.</p> | |
| <p>To decide whether or not to use this rule: if you prefix URLs with | |
| CGI-scripts, to force them to be processed by the CGI-script, it's | |
| likely that you will run into problems (or significant overhead) | |
| on sub-requests. In these cases, use this flag.</p> | |
| <p> | |
| Images, javascript files, or css files, loaded as part of an HTML page, | |
| are not subrequests - the browser requests them as separate HTTP | |
| requests. | |
| </p> | |
| <highlight language="config"> | |
| # Only rewrite direct requests to the front controller, | |
| # not subrequests from SSI includes or mod_dir. | |
| RewriteCond "%{REQUEST_FILENAME}" !-f | |
| RewriteCond "%{REQUEST_FILENAME}" !-d | |
| RewriteRule "^(.*)$" "/app/index.php?page=$1" [NS,L] | |
| </highlight> | |
| </section> | |
| <section id="flag_p"><title>P|proxy</title> | |
| <p>Use of the [P] flag causes the request to be handled by | |
| <module>mod_proxy</module>, and handled via a proxy request. For | |
| example, if you wanted all image requests to be handled by a back-end | |
| image server, you might do something like the following:</p> | |
| <highlight language="config"> | |
| RewriteRule "/(.*)\.(jpg|gif|png)$" "http://images.example.com/$1.$2" [P] | |
| </highlight> | |
| <p>Use of the [P] flag implies [L] - that is, the request is immediately | |
| pushed through the proxy, and any following rules will not be | |
| considered.</p> | |
| <p> | |
| You must make sure that the substitution string is a valid URL | |
| (typically starting with <code>http://</code><em>hostname</em>) which can be | |
| handled by the <module>mod_proxy</module>. If not, you will get an | |
| error from the proxy module. Use this flag to achieve a | |
| more powerful implementation of the <directive | |
| module="mod_proxy">ProxyPass</directive> directive, | |
| to map remote content into the namespace of the local server.</p> | |
| <note type="warning"> | |
| <title>Security Warning</title> | |
| <p>Take care when constructing the target URL of the rule, considering | |
| the security impact of allowing the client influence over the set of | |
| URLs to which your server will act as a proxy. If any part of the | |
| target URL is derived from user input (backreferences, query strings, | |
| etc.), an attacker may be able to cause your server to make requests | |
| to arbitrary internal or external hosts. This is known as a | |
| Server-Side Request Forgery (SSRF) vulnerability. Ensure that the | |
| scheme and hostname part of the URL is either fixed, or does not allow | |
| the client undue influence.</p> | |
| </note> | |
| <note type="warning"> | |
| <title>Performance warning</title> | |
| <p>Using this flag triggers the use of <module>mod_proxy</module>, without | |
| handling of persistent connections as the default worker is used in this case, | |
| which does not handle connection pooling/reuse.</p> | |
| <p>In order to use persistent connections you need to setup a | |
| <directive module="mod_proxy">Proxy</directive> block at least for the scheme | |
| and host part of the target URL containing a | |
| <directive module="mod_proxy">ProxySet</directive> directive where you e.g. set | |
| a timeout.</p> | |
| <p>If you set it up with <directive module="mod_proxy">ProxyPass</directive> or | |
| <directive module="mod_proxy">ProxyPassMatch</directive> persistent connections | |
| will be used automatically.</p> | |
| </note> | |
| <p>Note: <module>mod_proxy</module> must be enabled in order | |
| to use this flag.</p> | |
| </section> | |
| <section id="flag_pt"><title>PT|passthrough</title> | |
| <p> | |
| The target (or substitution string) in a RewriteRule is assumed to be a | |
| file path, by default. The use of the [PT] flag causes it to be treated | |
| as a URL-path instead. That is to say, the | |
| use of the [PT] flag causes the result of the <directive | |
| module="mod_rewrite">RewriteRule</directive> to be passed back through | |
| URL mapping, so that location-based mappings, such as <directive | |
| module="mod_alias">Alias</directive>, <directive | |
| module="mod_alias">Redirect</directive>, or <directive | |
| module="mod_alias">ScriptAlias</directive>, for example, might have a | |
| chance to take effect. | |
| </p> | |
| <p> | |
| If, for example, you have an | |
| <directive module="mod_alias">Alias</directive> | |
| for /icons, and have a <directive | |
| module="mod_rewrite">RewriteRule</directive> pointing there, you should | |
| use the [PT] flag to ensure that the | |
| <directive module="mod_alias">Alias</directive> is evaluated. | |
| </p> | |
| <highlight language="config"> | |
| Alias "/icons" "/usr/local/apache/icons" | |
| RewriteRule "/pics/(.+)\.jpg$" "/icons/$1.gif" [PT] | |
| </highlight> | |
| <p> | |
| Omission of the [PT] flag in this case will cause the Alias to be | |
| ignored, resulting in a 'File not found' error being returned. | |
| </p> | |
| <p>The <code>PT</code> flag implies the <code>L</code> flag: | |
| rewriting will be stopped in order to pass the request to | |
| the next phase of processing.</p> | |
| <p>Note that the <code>PT</code> flag is implied in per-directory | |
| contexts such as | |
| <directive type="section" module="core">Directory</directive> sections | |
| or in <code>.htaccess</code> files. The only way to circumvent that | |
| is to rewrite to <code>-</code>.</p> | |
| </section> | |
| <section id="flag_qsa"><title>QSA|qsappend</title> | |
| <p> | |
| When the replacement URL contains a query string, the default behavior | |
| of <directive module="mod_rewrite">RewriteRule</directive> is to discard | |
| the existing query string, and replace it with the newly generated one. | |
| Using the [QSA] flag causes the query strings to be combined. | |
| </p> | |
| <p>Consider the following rule:</p> | |
| <highlight language="config"> | |
| RewriteRule "/pages/(.+)" "/page.php?page=$1" [QSA] | |
| </highlight> | |
| <p>With the [QSA] flag, a request for <code>/pages/123?one=two</code> will be | |
| mapped to <code>/page.php?page=123&one=two</code>. Without the [QSA] | |
| flag, that same request will be mapped to | |
| <code>/page.php?page=123</code> - that is, the existing query string | |
| will be discarded. | |
| </p> | |
| </section> | |
| <section id="flag_qsd"><title>QSD|qsdiscard</title> | |
| <p> | |
| When the requested URL contains a query string, and the target URL does | |
| not, the default behavior of <directive | |
| module="mod_rewrite">RewriteRule</directive> is to copy that query | |
| string to the target URL. Using the [QSD] flag causes the query string | |
| to be discarded. | |
| </p> | |
| <p>This flag is available in version 2.4.0 and later.</p> | |
| <p> | |
| Using [QSD] and [QSA] together will result in [QSD] taking precedence. | |
| </p> | |
| <p> | |
| If the target URL has a query string, the default behavior will be | |
| observed - that is, the original query string will be discarded and | |
| replaced with the query string in the <code>RewriteRule</code> target | |
| URL. | |
| </p> | |
| <highlight language="config"> | |
| # Redirect old search URLs to the new path, discarding the query string. | |
| # /search?q=term&page=2 becomes /find (query string removed) | |
| RewriteRule "^/search" "/find" [QSD,R=301,L] | |
| </highlight> | |
| </section> | |
| <section id="flag_qsl"><title>QSL|qslast</title> | |
| <p> | |
| By default, the first (left-most) question mark in the substitution | |
| delimits the path from the query string. Using the [QSL] flag instructs | |
| <directive module="mod_rewrite">RewriteRule</directive> to instead split | |
| the two components using the last (right-most) question mark. </p> | |
| <p> | |
| This is useful when mapping to files that have literal question marks in | |
| their filename. If no query string is used in the substitution, | |
| a question mark can be appended to it in combination with this flag. </p> | |
| <p>For example, if a legacy application expects a query string that | |
| itself contains a question mark:</p> | |
| <highlight language="config"> | |
| # Map /lookup/foo?bar to /app?type=foo?bar | |
| # Without [QSL], the first ? in the substitution would split the | |
| # path, producing /app with query string type=foo?bar incorrectly. | |
| # With [QSL], the LAST ? is used as the delimiter. | |
| RewriteRule "^/lookup/(.*)" "/app?type=$1" [QSL,PT] | |
| </highlight> | |
| <p>Without [QSL], the substitution <code>/app?type=foo?bar</code> | |
| would be split at the first <code>?</code>, losing the literal question | |
| mark in the value.</p> | |
| <p> This flag is available in version 2.4.19 and later.</p> | |
| </section> | |
| <section id="flag_r"><title>R|redirect</title> | |
| <p> | |
| Use of the [R] flag causes a HTTP redirect to be issued to the browser. | |
| If a fully-qualified URL is specified (that is, including | |
| <code>http://servername/</code>) then a redirect will be issued to that | |
| location. Otherwise, the current protocol, servername, and port number | |
| will be used to generate the URL sent with the redirect. | |
| </p> | |
| <p> | |
| <em>Any</em> valid HTTP response status code may be specified, | |
| using the syntax [R=305], with a 302 status code being used by | |
| default if none is specified. The status code specified need not | |
| necessarily be a redirect (3xx) status code. However, | |
| if a status code is outside the redirect range (300-399) then the | |
| substitution string is dropped entirely, and rewriting is stopped as if | |
| the <code>L</code> were used.</p> | |
| <p>In addition to response status codes, you may also specify redirect | |
| status using their symbolic names: <code>temp</code> (default), | |
| <code>permanent</code>, or <code>seeother</code>.</p> | |
| <p> | |
| You will almost always want to use [R] in conjunction with [L] (that is, | |
| use [R,L]) because on its own, the [R] flag prepends | |
| <code>http://thishost[:thisport]</code> to the URL-path, but then passes this | |
| on to the next rule in the ruleset, which can often result in 'Invalid | |
| URI in request' warnings. | |
| </p> | |
| <p>Note: httpd only supports status codes that are included in the HTTP | |
| spec. Using an unrecognized status code will result in a 500 error and | |
| error log message.</p> | |
| <note type="warning"><title>[R=4xx] does not serve the substitution</title> | |
| <p>When a status code outside the 300-399 range is specified (e.g., | |
| <code>[R=403]</code> or <code>[R=410]</code>), the | |
| <em>substitution string is ignored</em>. The URL you wrote as the | |
| target is not served to the client. Instead, httpd returns the | |
| specified status code and handles it through the normal error | |
| response path (including any configured | |
| <directive module="core">ErrorDocument</directive>). | |
| If you want to deny access, the <a href="#flag_f">[F]</a> and | |
| <a href="#flag_g">[G]</a> flags are clearer ways to express the | |
| same intent.</p> | |
| </note> | |
| <highlight language="config"> | |
| # Redirect requests for the old docs path to the new location. | |
| RewriteRule "^/docs/(.*)$" "http://docs.example.com/$1" [R=301,L] | |
| </highlight> | |
| </section> | |
| <section id="flag_s"><title>S|skip</title> | |
| <p>The [S] flag is used to skip rules that you don't want to run. The | |
| syntax of the skip flag is [S=<em>N</em>], where <em>N</em> signifies | |
| the number of rules to skip (provided the <directive module="mod_rewrite"> | |
| RewriteRule</directive> and any preceding <directive module="mod_rewrite"> | |
| RewriteCond</directive> directives match). This can be thought of as a | |
| <code>goto</code> statement in your rewrite ruleset. In the following | |
| example, we only want to run the <directive module="mod_rewrite"> | |
| RewriteRule</directive> if the requested URL-path doesn't correspond with an | |
| actual file.</p> | |
| <highlight language="config"> | |
| # Is the request for a non-existent file? | |
| RewriteCond "%{REQUEST_FILENAME}" !-f | |
| RewriteCond "%{REQUEST_FILENAME}" !-d | |
| # If so, skip these two RewriteRules | |
| RewriteRule ".?" "-" [S=2] | |
| RewriteRule "(.*\.gif)" "images.php?$1" | |
| RewriteRule "(.*\.html)" "docs.php?$1" | |
| </highlight> | |
| <p>This technique is useful because a <directive | |
| module="mod_rewrite">RewriteCond</directive> only applies to the | |
| <directive module="mod_rewrite">RewriteRule</directive> immediately | |
| following it. Thus, if you want to make a <code>RewriteCond</code> apply | |
| to several <code>RewriteRule</code>s, one possible technique is to | |
| negate those conditions and add a <code>RewriteRule</code> with a [Skip] flag. You can | |
| use this to make pseudo if-then-else constructs: The last rule of | |
| the then-clause becomes <code>skip=N</code>, where N is the | |
| number of rules in the else-clause:</p> | |
| <highlight language="config"> | |
| # Does the file exist? | |
| RewriteCond "%{REQUEST_FILENAME}" !-f | |
| RewriteCond "%{REQUEST_FILENAME}" !-d | |
| # Create an if-then-else construct by skipping 3 lines if we meant to go to the "else" stanza. | |
| RewriteRule ".?" "-" [S=3] | |
| # IF the file exists, then: | |
| RewriteRule "(.*\.gif)" "images.php?$1" | |
| RewriteRule "(.*\.html)" "docs.php?$1" | |
| # Skip past the "else" stanza. | |
| RewriteRule ".?" "-" [S=1] | |
| # ELSE... | |
| RewriteRule "(.*)" "404.php?file=$1" | |
| # END | |
| </highlight> | |
| <p>It is probably easier to accomplish this kind of configuration using | |
| the <directive type="section">If</directive>, <directive | |
| type="section">ElseIf</directive>, and <directive | |
| type="section">Else</directive> directives instead.</p> | |
| </section> | |
| <section id="flag_t"><title>T|type</title> | |
| <p>Sets the MIME type with which the resulting response will be | |
| sent. This has the same effect as the <directive | |
| module="mod_mime">AddType</directive> directive.</p> | |
| <p>For example, you might use the following technique to serve Perl | |
| source code as plain text, if requested in a particular way:</p> | |
| <highlight language="config"> | |
| # Serve .pl files as plain text | |
| RewriteRule "\.pl$" "-" [T=text/plain] | |
| </highlight> | |
| <p>Or, perhaps, if you have a camera that produces jpeg images without | |
| file extensions, you could force those images to be served with the | |
| correct MIME type by virtue of their file names:</p> | |
| <highlight language="config"> | |
| # Files with 'IMG' in the name are jpg images. | |
| RewriteRule "IMG" "-" [T=image/jpg] | |
| </highlight> | |
| <p>Please note that this is a trivial example, and could be better done | |
| using <directive type="section" module="core">FilesMatch</directive> | |
| instead. Always consider the alternate | |
| solutions to a problem before resorting to rewrite, which will | |
| invariably be a less efficient solution than the alternatives.</p> | |
| <p> | |
| If used in per-directory context, use only <code>-</code> (dash) | |
| as the substitution <em>for the entire round of <module>mod_rewrite</module> processing</em>, | |
| otherwise the MIME-type set with this flag is lost due to an internal | |
| re-processing (including subsequent rounds of <module>mod_rewrite</module> processing). | |
| The <code>L</code> flag can be useful in this context to end the | |
| <em>current</em> round of <module>mod_rewrite</module> processing.</p> | |
| </section> | |
| <section id="flag_unsafe_allow_3f"><title>UnsafeAllow3F</title> | |
| <p> Setting this flag is required to allow a rewrite to continue If the | |
| HTTP request being written has an encoded question mark, '%3f', and the | |
| rewritten result has a '?' in the substitution. This protects from a malicious | |
| URL taking advantage of a capture and re-substitution of the encoded | |
| question mark.</p> | |
| <highlight language="config"> | |
| # A PHP front controller that routes all requests via a query parameter. | |
| # Without UnsafeAllow3F, a request like /page%3Fname=test would return | |
| # 403 Forbidden because the rewritten substitution contains '?' while | |
| # the original request contains an encoded '%3F'. | |
| RewriteCond "%{REQUEST_FILENAME}" !-f | |
| RewriteCond "%{REQUEST_FILENAME}" !-d | |
| RewriteRule "(.+)" "index.php?route=$1" [L,QSA,UnsafeAllow3F] | |
| </highlight> | |
| <note type="warning"> | |
| This flag exists because of <a | |
| href="https://www.cve.org/CVERecord?id=CVE-2024-38474">CVE-2024-38474</a>. | |
| Use it only on rules where you are certain that user-supplied <code>%3F</code> | |
| in the request cannot be exploited to manipulate the query string of the | |
| substitution target. Prefer restructuring URLs to avoid encoded question | |
| marks where possible. | |
| </note> | |
| </section> | |
| <section id="flag_unsafe_prefix_stat"><title>UnsafePrefixStat</title> | |
| <p> Setting this flag is required in server-scoped substitutions | |
| start with a variable or backreference and resolve to a filesystem path. | |
| These substitutions are not prefixed with the document root. | |
| This protects from a malicious URL causing the expanded substitution to | |
| map to an unexpected filesystem location.</p> | |
| <p><since>2.5.1</since></p> | |
| <highlight language="config"> | |
| # This rule starts the substitution with a backreference. | |
| # Since 2.4.60, this is rejected by default to prevent the expanded | |
| # path from escaping the document root (CVE-2024-38475). | |
| # Only add UnsafePrefixStat after verifying the substitution cannot | |
| # resolve to a filesystem path outside your web root. | |
| RewriteRule "^/mirror/(.+)$" "$1" [PT,UnsafePrefixStat] | |
| </highlight> | |
| <note type="warning"> | |
| This flag exists because of <a | |
| href="https://www.cve.org/CVERecord?id=CVE-2024-38475">CVE-2024-38475</a>. | |
| Without it, a substitution beginning with a backreference or variable | |
| that happens to match an existing filesystem path could allow requests | |
| to escape the document root. Use this flag only after confirming that | |
| the substitution is adequately constrained. | |
| </note> | |
| </section> | |
| <section id="flag_unc"><title>UNC</title> | |
| <p> Setting this flag prevents the merging of multiple leading slashes, | |
| as used in Windows UNC paths. The flag is not necessary when the rules | |
| substitution starts with multiple literal slashes.</p> | |
| <p><since>2.5.1</since></p> | |
| <highlight language="config"> | |
| # On Windows, rewrite to a UNC file share using a variable. | |
| # Without [UNC], the leading slashes in the substitution would be | |
| # collapsed (//server/share becomes /server/share). | |
| RewriteCond "%{HTTP_HOST}" "^(.+)\.internal$" | |
| RewriteRule "^/shared/(.*)$" "//%1/fileshare/$1" [UNC] | |
| </highlight> | |
| <p>This flag is only relevant on Windows. It prevents Apache from | |
| merging the leading double slash (<code>//</code>) that denotes a | |
| UNC path when the path is constructed from a backreference or | |
| variable. If the substitution begins with literal double slashes, | |
| no flag is needed.</p> | |
| </section> | |
| </manualpage> |