Project

General

Profile

Mod rewrite » History » Revision 55

Revision 54 (gstrauss, 2016-04-19 20:13) → Revision 55/61 (gstrauss, 2018-08-13 00:34)

h1. URL Rewrites 

 {{>toc}} 

 *Module: mod_rewrite* 

 h2. Description 

 internal redirects, url rewrite 

 The result of *{color:red}NOTE: url rewriting does not work within a rewritten url-path must begin with '/' (enforced since 1.4.50) $HTTP["url"] conditional*, but fixed in v1.4.34 (see #2526). 

 h2. Options 

 h3. url.rewrite-once 

 Rewrites a set of URLs internally in the webserver BEFORE they are handled. 
  
 e.g. 

 <pre> 
 url.rewrite-once = ( "<regex>" => "<relative-uri>" ) 
 </pre> 

 or for multiple rules.. 

 <pre> 
 url.rewrite-once = (  
   "<regex1>" => "<relative-uri1>", 
   "<regex2>" => "<relative-uri2>" 
 ) 
 </pre> 


 h3. url.rewrite-repeat 

 Rewrites a set of URLs internally in the webserver BEFORE they are handled 
  
 e.g. 

 <pre> 
 url.rewrite-repeat = ( "<regex>" => "<relative-uri>" ) 
 </pre> 

 The difference between these options is that, while url.rewrite-repeat allows for applying multiple (seperately defined) rewrite rules in a row, url.rewrite-once will cause further rewrite rules to be skipped if the expression was matched. As such, url.rewrite-once behaves like Apaches' RewriteRule ... [L]: http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriterule 

 The options @url.rewrite@ and @url.rewrite-final@ were mapped to @url.rewrite-once@ in 1.3.16. 


 h3. url.rewrite-[repeat-]if-not-file 

 New: For the 1.4.x branch as of 1.4.24 or r2647 from svn: 

 Rewrites a set of URLs internally in the webserver BEFORE they are handled and checks that files do *not* exist. 
  
 Take examples from above, this is to mimic Apache´s "!-f" RewriteRule. Please note this does not work for directories, pipes, sockets or alike. 

 Where do I want to use this? Maybe with e.g. Drupal backend, where mod_magnet (has an Apache´s -f and -d solution) might not be handy or simply "too much" for just this kind of rewrites. This closes feature request #985. 


 h2. Regular Expressions 

 * Patterns ("wildcards") are matched against a string 
 * Special characters (see [http://www.regular-expressions.info/reference.html] for reference): 

 ** . (full stop) - match any character 
 ** \* (asterisk) - match zero or more of the previous symbol 
 ** \+ (plus) - match one or more of the previous symbol 
 ** ? (question) - match zero or one of the previous symbol 
 ** \\? (backslash-something) - match special characters 
 ** ^ (caret) - match the start of a string 
 ** $ (dollar) - match the end of a string 
 ** [set] - match any one of the symbols inside the square braces. 
 ** [^set] - match any symbol that is NOT inside the square braces. 
 ** (pattern) - grouping, remember what the pattern matched as a special variable  
 ** {n,m} - from n to m times matching the previous character (m could be omitted to mean >=n times) 
 ** (?!expression) - match anything BUT expression at the current position. Example: @"^(/(?!(favicon.ico$|js/|images/)).*)" => "/fgci/$1"@ 

 * Normal alphanumeric characters are treated as normal 

 h3. Replacement Patterns 

 If the matched regex contains groups in parentheses, $1..$9 in the replacement refer to the captured text in the  
 matching group "$1" meaning the first group, "$2" the second, and so on. 

 Note that % replacements (like %1, %2, %0, etc.) in url.rewrite-* targets are permitted, but do *not* have the meaning they would have in evhost.path-pattern.    If url.rewrite-* is specified within a regex conditional, % patterns are replaced by the corresponding groups from the condition regex.    %1 is replaced with the first subexpression, %2 with the second, etc.    %0 is replaced by the entire substring matching the regexp.    See below for an example using "%0". 

 h3. Extended Replacement Patterns 

 lighttpd provides ways to encode redirect and rewrite backreference substitutions (since 1.4.50) in curly-braces %{...} or ${...} 

 Up to nine (9) matches are saved for %{1} - %{9}.    Up to nineteen (19) matches are saved for ${1} - ${19}. 

 In addition to %1 and $1, the following modifiers are now supported, followed by the number for the backreference, e.g. ${esc:1}. 

 * ${noesc:...}      no escaping 
 * ${esc:...}        escape all non-alphanumeric - . _ ~ incl double-escape % 
 * ${escape:...}     escape all non-alphanumeric - . _ ~ incl double-escape % 
 * ${escnde:...}     escape all non-alphanumeric - . _ ~    but no double-esc % 
 * ${escpsnde:...} escape all non-alphanumeric - . _ ~ / but no double-esc % (preserves literal /) 
 * ${tolower:...} 
 * ${toupper:...} 
 * ${encb64u:...}    encode to base64url characters (no-padding) 
 * ${decb64u:...}    decode from base64url characters 

 * %{noesc:...} 
 * %{esc:...} 
 * %{escape:...} 
 * %{escnde:...} 
 * %{escpsnde:...} 
 * %{tolower:...} 
 * %{toupper:...} 
 * %{encb64u:...} 
 * %{decb64u:...} 

 lighttpd provides ways to substitute URI parts without needing a regex match (since 1.4.50) (and can be preceded by encoding modifier, e.g. ${tolower:url.authority}) 

 * ${url.scheme} 
 * ${url.authority} 
 * ${url.port} 
 * ${url.path} 
 * ${url.query} 

 * ${qsa}          appends query string, if not empty 

 h2. Examples 

 The regex is matching the full REQUEST_URI which is supplied by the user including  

 query-string. 

 <pre> 
 # the following example, is, however just simulating vhost by rewrite 
 # * you can never change document-root by mod_rewrite 
 # use mod_*host instead to make real mass-vhost 

 server.document-root = "/www/htdocs/" 
 $HTTP["host"] =~ "^.*\.([^.]+\.com)$" { 
   url.rewrite-once = ( "^/(.*)" => "/%0/$1" ) 
 } 

 # request:          http://any.domain.com/url/  
 # before rewrite: REQUEST_URI="/www/htdocs/url/" 
 # and DOCUMENT_ROOT="/www/htdocs/" %0="any.domain.com" $1="url/" 
 # after rewrite:    REQUEST_URI="/www/htdocs/any.domain.com/url/" 
 # still, you have DOCUMENT_ROOT=/www/htdocs/ 

 # please note, that we have two regular expressions: the one which  
 # $HTTP["host"] is been compared with, and the one of the rewrite rule. 
 # the numbered subexpressions available to build the relative uri are 
 # being prefixed by '%' for subexpressions of the first regular expression  
 # match and by '$' for subexpressions of the second one. 
 # subexpression 0 interpolates the whole matching string: %0 for the whole 
 # string matching the conditional, and $0 for the whole string matching the 
 # rewrite rule. 

 # if the rewrite rule is not included in a conditional  
 # block, only the '$' prefixed variables are available. 

 url.rewrite-once = ( "^/id/([0-9]+)$" => "/index.php?id=$1", 
                      "^/link/([a-zA-Z]+)" => "/index.php?link=$1" ) 

 </pre> 

 h3. With mod_redirect 

 Rewrite rules always execute before redirect rules. This is true regardless of the order of module loading or the order of rules in the configuration (lighttpd v1.4.13). However, mod_rewrite provides a mechanism to pass URLs through unmangled: specify "$0" as the rule target, but be sure that the rule matches the entire string since $0 is the entire matched string. 

 e.g. 

 <pre> 
 url.rewrite-once = ( 
     "^/foo"    => "$0", 
     "^/(.*)" => "/handler/$1" 
 ) 

 url.redirect = ( 
     "^/foo"    => "http://foo.bar/" 
 ) 
 </pre> 

 Since version 1.4.40, an alternative is to specify a blank target to the rewrite rule.    This will cause the matched rule to leave the url unmodified, and will skip any further rewrite rules. 

 <pre> 
 url.rewrite-once = ( 
     "^/foo"    => "",     # instead of (nonsensical) blank url, the url will not be modified 
     "^/(.*)" => "/handler/$1" 
 ) 
 </pre> 


 h3. Workaround for "File name too long" on Windows 

 While running Lighttpd on Windows you may get @500 Internal Server Error@ if computed filename is longer than 255 symbols. 
 In error log it will be @(response.c.537) file not found ... or so:    File name too long /very_looooong_path ->@. 
 As workaround you can use @mod_rewrite@ to avoid this error. 

 <pre> 
 server.modules += ("mod_rewrite") 
 url.rewrite-once = ( ".{250,}" => "/toolong.php" ) 
 </pre> 

 If error handler is PHP, @$_SERVER['REQUEST_URI']@ will contain full URI. 

 h3. Passing / Matching the Query string (GET variables) 

 If you wanna pass the Query String (?foo=bar) to the rewrite destination you have to explicitly match it: 

 <pre> 
 url.rewrite-once = ( 
     "^/news/([^\?]+)(\?(.*))?" => "/news.php?title=$1&$3" 
 ) 
 </pre> 

 h3. Misc Notes 

 *{color:red}NOTE: url rewriting does not work within a $HTTP["url"] conditional*, but fixed in v1.4.34 (see #2526).