| <?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="tech.xml.meta"> | |
| <parentdocument href="./">Rewrite</parentdocument> | |
| <title>Apache mod_rewrite Technical Details</title> | |
| <summary> | |
| <p>This document discusses some of the technical details of <module>mod_rewrite</module> | |
| and URL matching.</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="flags.html">RewriteRule Flags</a></seealso> | |
| <seealso><a href="vhosts.html">Virtual hosts</a></seealso> | |
| <seealso><a href="rewritemap.html">Using RewriteMap</a></seealso> | |
| <seealso><a href="htaccess.html">Per-directory Rewrites</a></seealso> | |
| <seealso><a href="avoid.html">When not to use mod_rewrite</a></seealso> | |
| <section id="InternalAPI"><title>API Phases</title> | |
| <p>The Apache HTTP Server handles requests in several phases. At | |
| each of these phases, one or more modules may be called upon to | |
| handle that portion of the request lifecycle. Phases include things | |
| like URL-to-filename translation, authentication, authorization, | |
| content, and logging. (This is not an exhaustive list.)</p> | |
| <p><module>mod_rewrite</module> acts in two of these phases (or "hooks", as they are | |
| often called) to influence how URLs may be rewritten.</p> | |
| <p>First, it uses the URL-to-filename translation hook, which occurs | |
| after the HTTP request has been read, but before any authorization | |
| starts. Secondly, it uses the Fixup hook, which is after the | |
| authorization phases, and after per-directory configuration files | |
| (<code>.htaccess</code> files) have been read, but before the | |
| content handler is called.</p> | |
| <p>After a request comes in and a corresponding server or | |
| virtual host has been determined, the rewriting engine starts | |
| processing any <module>mod_rewrite</module> directives appearing in the | |
| per-server configuration. (i.e., in the main server configuration file | |
| and <directive module="core" type="section">Virtualhost</directive> | |
| sections.) This happens in the URL-to-filename phase.</p> | |
| <p>A few steps later, once the final data directories have been found, | |
| the per-directory configuration directives (<code>.htaccess</code> | |
| files and <directive module="core" | |
| type="section">Directory</directive> blocks) are applied. This | |
| happens in the Fixup phase.</p> | |
| <p>In each of these cases, <module>mod_rewrite</module> rewrites the | |
| <code>REQUEST_URI</code> either to a new URL, or to a filename.</p> | |
| <p>In <glossary ref="perdirectory">per-directory context</glossary>, | |
| rules are applied during the Fixup phase after the URL has already | |
| been translated to a filename. This changes what the pattern matches | |
| against and how substitutions are handled. See the | |
| <a href="htaccess.html#path-stripping">Per-directory Rewrites</a> | |
| document for practical details on path stripping, RewriteBase, and | |
| how to avoid looping.</p> | |
| </section> | |
| <section id="order"><title>Module Processing Order</title> | |
| <p><module>mod_rewrite</module> and <module>mod_alias</module> both | |
| operate during the URL-to-filename translation phase, but | |
| <module>mod_rewrite</module> runs <strong>first</strong> regardless | |
| of the order in which directives appear in the configuration file. | |
| This is determined by the hook priority each module registers, not | |
| by source order.</p> | |
| <p>The practical consequence: when both <directive | |
| module="mod_rewrite">RewriteRule</directive> and <directive | |
| module="mod_alias">Redirect</directive> (or <directive | |
| module="mod_alias">RedirectMatch</directive>) are present in the | |
| same server or virtual-host context, the rewrite rules are | |
| evaluated first. If a <code>RewriteRule</code> matches and rewrites | |
| the URL-path (or returns a redirect), <code>Redirect</code> never sees | |
| the request.</p> | |
| <p class="figure"> | |
| <img src="../images/rewrite_module_order.png" | |
| alt="Side-by-side comparison of module processing order: | |
| in server context, mod_rewrite runs first in the | |
| URL-to-filename phase then mod_alias runs second; in | |
| per-directory context, mod_alias runs first in the | |
| URL-to-filename phase, then mod_rewrite runs later in the | |
| Fixup phase" /><br /> | |
| <dfn>Figure:</dfn> Module processing order reversal between server and per-directory context | |
| </p> | |
| <highlight language="config"> | |
| # In this configuration, the Redirect is never reached for /old | |
| # because the RewriteRule matches first — even though | |
| # the Redirect appears earlier in the file. | |
| Redirect "/old" "http://example.com/new" | |
| RewriteRule "^/old" "/other" [L] | |
| </highlight> | |
| <note><title>Per-directory context reverses the order</title> | |
| <p>In <glossary ref="perdirectory">per-directory context</glossary>, | |
| the situation is different. <module>mod_alias</module> directives like | |
| <code>Redirect</code> still run in the URL-to-filename translation | |
| phase, but <module>mod_rewrite</module> rules run later, in the | |
| Fixup phase. This means that in per-directory context, | |
| <code>Redirect</code> is evaluated <em>before</em> | |
| <code>RewriteRule</code>.</p> | |
| </note> | |
| <p>Because of this inconsistency between contexts, mixing | |
| <module>mod_rewrite</module> and <module>mod_alias</module> | |
| directives in the same scope is a common source of confusion. The | |
| simplest advice: choose one module for a given task. If you need | |
| rewrite conditions or pattern matching, use | |
| <code>RewriteRule</code> exclusively. If a simple prefix redirect | |
| suffices, use <code>Redirect</code> and don't add rewrite rules | |
| that might interact with it.</p> | |
| </section> | |
| <section id="encoding"><title>URL Encoding and Decoding</title> | |
| <p>Apache httpd unescapes URL-encoded characters in the request URL-path before any | |
| <directive module="mod_rewrite">RewriteRule</directive> pattern | |
| matching takes place. A request for | |
| <code>/my%20page/cats%3Fdogs</code> is decoded to | |
| <code>/my page/cats?dogs</code>, and that decoded string is what the | |
| <code>RewriteRule</code> pattern matches against.</p> | |
| <p>This means you cannot write a pattern that matches the literal | |
| URL-encoded form. If you need to distinguish | |
| <code>/horses%2Fponies</code> from <code>/horses/ponies</code>, use | |
| <code>%{THE_REQUEST}</code> in a <directive | |
| module="mod_rewrite">RewriteCond</directive> — it preserves the | |
| original request line exactly as the client sent it, before any | |
| decoding:</p> | |
| <highlight language="config"> | |
| # Match only the literally-encoded %2F, not a real path separator | |
| RewriteCond "%{THE_REQUEST}" "/horses%2F" | |
| RewriteRule "^/horses/ponies$" "/special-handler" [L] | |
| </highlight> | |
| <p>After substitution, <module>mod_rewrite</module> re-encodes the | |
| resulting URL-path for output. Several flags control this behavior:</p> | |
| <ul> | |
| <li><a href="flags.html#flag_b">[B]</a> — re-escape | |
| backreferences so that special characters captured from the | |
| decoded URL-path are not interpreted as delimiters in the | |
| substitution.</li> | |
| <li><a href="flags.html#flag_bnp">[BNP]</a> — when [B] is | |
| active, encode spaces as <code>%20</code> rather than | |
| <code>+</code> (appropriate for path components, not query | |
| strings).</li> | |
| <li><a href="flags.html#flag_ne">[NE]</a> — suppress the | |
| default escaping of special characters in the substitution | |
| result, allowing literal <code>#</code>, <code>?</code>, and | |
| other characters to pass through unmodified on external | |
| redirects.</li> | |
| </ul> | |
| <section id="allowencodedslashes"> | |
| <title>AllowEncodedSlashes</title> | |
| <p>By default, Apache returns 404 for any URL containing an encoded | |
| slash (<code>%2F</code>). The <directive | |
| module="core">AllowEncodedSlashes</directive> directive controls | |
| this behavior:</p> | |
| <ul> | |
| <li><code>Off</code> (default) — reject <code>%2F</code> with | |
| 404.</li> | |
| <li><code>On</code> — allow <code>%2F</code> and decode it to | |
| <code>/</code> before passing to handlers.</li> | |
| <li><code>NoDecode</code> — allow <code>%2F</code> but keep it | |
| in encoded form, letting the backend application distinguish it | |
| from a real path separator.</li> | |
| </ul> | |
| <p>When using the <a href="flags.html#flag_b">[B]</a> flag with | |
| URLs that may contain encoded slashes, you typically need | |
| <code>AllowEncodedSlashes NoDecode</code> to prevent Apache from | |
| rejecting the re-encoded result.</p> | |
| </section> | |
| </section> | |
| <section id="InternalRuleset"><title>Ruleset Processing</title> | |
| <p>Now when <module>mod_rewrite</module> is triggered in these two API phases, it | |
| reads the configured rulesets from its configuration | |
| structure (which itself was either created on startup for | |
| per-server context or during the directory walk of the Apache | |
| kernel for per-directory context). Then the URL rewriting | |
| engine is started with the contained ruleset (one or more | |
| rules together with their conditions). The operation of the | |
| URL rewriting engine itself is exactly the same for both | |
| configuration contexts. Only the final result processing is | |
| different.</p> | |
| <p class="figure"> | |
| <img src="../images/mod_rewrite_fig1.png" | |
| alt="Overview of per-request rewrite processing through | |
| per-server and per-directory phases" /><br /> | |
| <dfn>Figure 1:</dfn>The per-request rewrite process showing | |
| both per-server and per-directory rule processing phases | |
| </p> | |
| <p>The order of rules in the ruleset is important because the | |
| rewriting engine processes them in a special (and not very | |
| obvious) order. The rule is this: The rewriting engine loops | |
| through the ruleset rule by rule (<directive | |
| module="mod_rewrite">RewriteRule</directive> directives) and | |
| when a particular rule matches it optionally loops through | |
| existing corresponding conditions (<code>RewriteCond</code> | |
| directives). For historical reasons the conditions are given | |
| first, and so the control flow is a little bit long-winded. See | |
| Figure 2 for more details.</p> | |
| <p class="figure"> | |
| <img src="../images/rewrite_process_uri.png" | |
| alt="Flowchart showing per-rule control flow: for each rule, | |
| check pattern against URL, evaluate RewriteCond conditions, | |
| apply substitution if both pass, then check flags to decide | |
| whether to stop or continue to the next rule" /><br /> | |
| <dfn>Figure 2:</dfn>The control flow through the rewriting ruleset | |
| </p> | |
| <p>First the URL is matched against the | |
| <em>Pattern</em> of each rule. If it fails, <module>mod_rewrite</module> | |
| immediately stops processing this rule, and continues with the | |
| next rule. If the <em>Pattern</em> matches, <module>mod_rewrite</module> looks | |
| for corresponding rule conditions (RewriteCond directives, | |
| appearing immediately above the RewriteRule in the configuration). | |
| If none are present, it substitutes the URL with a new value, which is | |
| constructed from the string <em>Substitution</em>, and goes on | |
| with its rule-looping. But if conditions exist, it starts an | |
| inner loop for processing them in the order that they are | |
| listed. For conditions, the logic is different: we don't match | |
| a pattern against the current URL. Instead we first create a | |
| string <em>TestString</em> by expanding variables, | |
| back-references, map lookups, <em>etc.</em> and then we try | |
| to match <em>CondPattern</em> against it. If the pattern | |
| doesn't match, the complete set of conditions and the | |
| corresponding rule fails. If the pattern matches, then the | |
| next condition is processed until no more conditions are | |
| available. If all conditions match, processing is continued | |
| with the substitution of the URL with | |
| <em>Substitution</em>.</p> | |
| <p class="figure"> | |
| <img src="../images/mod_rewrite_fig2.png" | |
| alt="Flow of backreferences between RewriteRule and | |
| RewriteCond directives" /><br /> | |
| <dfn>Figure 3:</dfn>The flow of backreferences through a rule. | |
| RewriteRule Pattern is matched first; its captures ($1...$9) | |
| are available in all RewriteCond TestStrings. The last matched | |
| CondPattern's captures (%1...%9) are available in Substitution. | |
| </p> | |
| </section> | |
| </manualpage> |