Project

General

Profile

Mod rewrite » History » Revision 58

Revision 57 (gstrauss, 2021-08-22 23:44) → Revision 58/61 (gstrauss, 2021-08-27 18:32)

h1. URL Rewrites 

 {{>toc}} 

 *Module: mod_rewrite* 

 h2. Description 

 internal redirects, url rewrite 

 The result of a rewritten url-path must begin with '/' (enforced since 1.4.50) 

 h2. Options 

 h3. @url.rewrite-once@ 

 Rewrites a set of URLs internally in the webserver BEFORE they are handled. 
 <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 
 <pre> 
 url.rewrite-repeat = ( "<regex>" => "<relative-uri>" ) 
 </pre> 
 The difference between these options is that while @url.rewrite-repeat@ allows for applying multiple (separately 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 Apache's RewriteRule ... [L]: http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html#rewriterule 


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

 Rewrites a set of URLs internally in the webserver BEFORE they are handled *unless* the target exists and is a regular file (not a directory, pipe, socket, or other).    This is akin to Apache´s @!-f@ RewriteRule. 

 Note: All URLs with path-info appended to the end of the URL will be treated as file not existing.    This is useful with frameworks where lighttpd should serve static files (which exist and are files), and everything else should be rewritten to use the dynamic backend, e.g. Drupal, or other @/index.php@ 

 @url.rewrite-if-not-file@ is a simple solution for many frameworks 
 e.g. have lighttpd serve static files (such as .js, .css, .jpg, etc) if file exists, or else rewrite to send request to @/index.php@ 
 @url.rewrite-if-not-file = ( "" => "/index.php?path=${url.path}${qsa}" )@ 

 (As an alternative to mod_rewrite, [[Docs_ModMagnet|mod_magnet]] lua code can be used to fully implement Apache´s -f and -d solutions.) 


 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/)).*)" => "/fcgi/$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. 

 <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 characters. 
 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 want to 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&$2" 
 ) 
 </pre>