]> granicus.if.org Git - apache/blob - docs/manual/rewrite/rewrite_guide.xml
0ac13a68052bd820093a4fed7c6505bdba3eed0e
[apache] / docs / manual / rewrite / rewrite_guide.xml
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
3 <?xml-stylesheet type="text/xsl" href="../style/manual.en.xsl"?>
4 <!-- $LastChangedRevision$ -->
5
6 <!--
7  Licensed to the Apache Software Foundation (ASF) under one or more
8  contributor license agreements.  See the NOTICE file distributed with
9  this work for additional information regarding copyright ownership.
10  The ASF licenses this file to You under the Apache License, Version 2.0
11  (the "License"); you may not use this file except in compliance with
12  the License.  You may obtain a copy of the License at
13
14      http://www.apache.org/licenses/LICENSE-2.0
15
16  Unless required by applicable law or agreed to in writing, software
17  distributed under the License is distributed on an "AS IS" BASIS,
18  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  See the License for the specific language governing permissions and
20  limitations under the License.
21 -->
22
23 <manualpage metafile="rewrite_guide.xml.meta">
24   <parentdocument href="./">Rewrite</parentdocument>
25
26   <title>URL Rewriting Guide</title>
27
28   <summary>
29
30     <p>This document supplements the <module>mod_rewrite</module>
31     <a href="../mod/mod_rewrite.html">reference documentation</a>.
32     It describes how one can use Apache's <module>mod_rewrite</module>
33     to solve typical URL-based problems with which webmasters are
34     commonony confronted. We give detailed descriptions on how to
35     solve each problem by configuring URL rewriting rulesets.</p>
36
37     <note type="warning">ATTENTION: Depending on your server configuration
38     it may be necessary to slightly change the examples for your
39     situation, e.g. adding the <code>[PT]</code> flag when
40     additionally using <module>mod_alias</module> and
41     <module>mod_userdir</module>, etc. Or rewriting a ruleset
42     to fit in <code>.htaccess</code> context instead
43     of per-server context. Always try to understand what a
44     particular ruleset really does before you use it. This
45     avoids many problems.</note>
46
47   </summary>
48 <seealso><a href="../mod/mod_rewrite.html">Module
49 documentation</a></seealso>
50 <seealso><a href="rewrite_intro.html">mod_rewrite
51 introduction</a></seealso>
52 <seealso><a href="rewrite_guide_advanced.html">Advanced Rewrite Guide - advanced 
53 useful examples</a></seealso>
54 <seealso><a href="rewrite_tech.html">Technical details</a></seealso>
55
56
57 <section id="canonicalurl">
58
59 <title>Canonical URLs</title>
60
61 <dl>
62  <dt>Description:</dt>
63
64    <dd>
65      <p>On some webservers there are more than one URL for a
66      resource. Usually there are canonical URLs (which should be
67      actually used and distributed) and those which are just
68      shortcuts, internal ones, etc. Independent of which URL the
69      user supplied with the request he should finally see the
70      canonical one only.</p>
71    </dd>
72
73    <dt>Solution:</dt>
74
75      <dd>
76        <p>We do an external HTTP redirect for all non-canonical
77        URLs to fix them in the location view of the Browser and
78        for all subsequent requests. In the example ruleset below
79        we replace <code>/~user</code> by the canonical
80        <code>/u/user</code> and fix a missing trailing slash for
81        <code>/u/user</code>.</p>
82
83 <example><pre>
84 RewriteRule   ^/<strong>~</strong>([^/]+)/?(.*)    /<strong>u</strong>/$1/$2  [<strong>R</strong>]
85 RewriteRule   ^/([uge])/(<strong>[^/]+</strong>)$  /$1/$2<strong>/</strong>   [<strong>R</strong>]
86 </pre></example>
87         </dd>
88       </dl>
89
90     </section>
91
92 <section id="canonicalhost"><title>Canonical Hostnames</title>
93
94       <dl>
95         <dt>Description:</dt>
96
97         <dd>The goal of this rule is to force the use of a particular
98         hostname, in preference to other hostnames which may be used to
99         reach the same site. For example, if you wish to force the use
100         of <strong>www.example.com</strong> instead of
101         <strong>example.com</strong>, you might use a variant of the
102         following recipe.</dd>
103
104         <dt>Solution:</dt>
105
106         <dd>
107 <p>For sites running on a port other than 80:</p>
108 <example><pre>
109 RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]
110 RewriteCond %{HTTP_HOST}   !^$
111 RewriteCond %{SERVER_PORT} !^80$
112 RewriteRule ^/(.*)         http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]
113 </pre></example>
114
115 <p>And for a site running on port 80</p>
116 <example><pre>
117 RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]
118 RewriteCond %{HTTP_HOST}   !^$
119 RewriteRule ^/(.*)         http://fully.qualified.domain.name/$1 [L,R]
120 </pre></example>
121         </dd>
122       </dl>
123
124     </section>
125
126     <section id="moveddocroot">
127
128       <title>Moved <code>DocumentRoot</code></title>
129
130       <dl>
131         <dt>Description:</dt>
132
133         <dd>
134 <p>Usually the <directive module="core">DocumentRoot</directive>
135 of the webserver directly relates to the URL "<code>/</code>".
136 But often this data is not really of top-level priority. For example,
137 you may wish for visitors, on first entering a site, to go to a
138 particular subdirectory <code>/about/</code>. This may be accomplished
139 using the following ruleset:</p>
140 </dd>
141
142         <dt>Solution:</dt>
143
144         <dd>
145           <p>We redirect the URL <code>/</code> to
146           <code>/about/</code>:
147           </p>
148          
149 <example><pre>
150 RewriteEngine on
151 RewriteRule   <strong>^/$</strong>  /about/  [<strong>R</strong>]
152 </pre></example>
153
154     <p>Note that this can also be handled using the <directive
155     module="mod_alias">RedirectMatch</directive> directive:</p>
156
157 <example>
158 RedirectMatch ^/$ http://example.com/e/www/
159 </example>
160 </dd>
161 </dl>
162
163     </section>
164
165     <section id="trailingslash">
166
167       <title>Trailing Slash Problem</title>
168
169       <dl>
170         <dt>Description:</dt>
171
172     <dd><p>The vast majority of "trailing slash" problems can be dealt
173     with using the techniques discussed in the <a
174     href="http://httpd.apache.org/docs/misc/FAQ-E.html#set-servername">FAQ
175     entry</a>. However, occasionally, there is a need to use mod_rewrite
176     to handle a case where a missing trailing slash causes a URL to
177     fail. This can happen, for example, after a series of complex
178     rewrite rules.</p>
179     </dd>
180
181         <dt>Solution:</dt>
182
183         <dd>
184           <p>The solution to this subtle problem is to let the server
185           add the trailing slash automatically. To do this
186           correctly we have to use an external redirect, so the
187           browser correctly requests subsequent images etc. If we
188           only did a internal rewrite, this would only work for the
189           directory page, but would go wrong when any images are
190           included into this page with relative URLs, because the
191           browser would request an in-lined object. For instance, a
192           request for <code>image.gif</code> in
193           <code>/~quux/foo/index.html</code> would become
194           <code>/~quux/image.gif</code> without the external
195           redirect!</p>
196
197           <p>So, to do this trick we write:</p>
198
199 <example><pre>
200 RewriteEngine  on
201 RewriteBase    /~quux/
202 RewriteRule    ^foo<strong>$</strong>  foo<strong>/</strong>  [<strong>R</strong>]
203 </pre></example>
204
205    <p>Alternately, you can put the following in a
206    top-level <code>.htaccess</code> file in the content directory.
207    But note that this creates some processing overhead.</p>
208
209 <example><pre>
210 RewriteEngine  on
211 RewriteBase    /~quux/
212 RewriteCond    %{REQUEST_FILENAME}  <strong>-d</strong>
213 RewriteRule    ^(.+<strong>[^/]</strong>)$           $1<strong>/</strong>  [R]
214 </pre></example>
215         </dd>
216       </dl>
217
218     </section>
219
220     <section id="movehomedirs">
221
222       <title>Move Homedirs to Different Webserver</title>
223
224       <dl>
225         <dt>Description:</dt>
226
227         <dd>
228           <p>Many webmasters have asked for a solution to the
229           following situation: They wanted to redirect just all
230           homedirs on a webserver to another webserver. They usually
231           need such things when establishing a newer webserver which
232           will replace the old one over time.</p>
233         </dd>
234
235         <dt>Solution:</dt>
236
237         <dd>
238           <p>The solution is trivial with <module>mod_rewrite</module>.
239           On the old webserver we just redirect all
240           <code>/~user/anypath</code> URLs to
241           <code>http://newserver/~user/anypath</code>.</p>
242
243 <example><pre>
244 RewriteEngine on
245 RewriteRule   ^/~(.+)  http://<strong>newserver</strong>/~$1  [R,L]
246 </pre></example>
247         </dd>
248       </dl>
249
250     </section>
251
252     <section id="multipledirs">
253
254       <title>Search pages in more than one directory</title>
255
256       <dl>
257         <dt>Description:</dt>
258
259         <dd>
260           <p>Sometimes it is necessary to let the webserver search
261           for pages in more than one directory. Here MultiViews or
262           other techniques cannot help.</p>
263         </dd>
264
265         <dt>Solution:</dt>
266
267         <dd>
268           <p>We program a explicit ruleset which searches for the
269           files in the directories.</p>
270
271 <example><pre>
272 RewriteEngine on
273
274 #   first try to find it in dir1/...
275 #   ...and if found stop and be happy:
276 RewriteCond         /your/docroot/<strong>dir1</strong>/%{REQUEST_FILENAME}  -f
277 RewriteRule  ^(.+)  /your/docroot/<strong>dir1</strong>/$1  [L]
278
279 #   second try to find it in dir2/...
280 #   ...and if found stop and be happy:
281 RewriteCond         /your/docroot/<strong>dir2</strong>/%{REQUEST_FILENAME}  -f
282 RewriteRule  ^(.+)  /your/docroot/<strong>dir2</strong>/$1  [L]
283
284 #   else go on for other Alias or ScriptAlias directives,
285 #   etc.
286 RewriteRule   ^(.+)  -  [PT]
287 </pre></example>
288         </dd>
289       </dl>
290
291     </section>
292
293     <section id="setenvvars">
294
295       <title>Set Environment Variables According To URL Parts</title>
296
297       <dl>
298         <dt>Description:</dt>
299
300         <dd>
301           <p>Perhaps you want to keep status information between
302           requests and use the URL to encode it. But you don't want
303           to use a CGI wrapper for all pages just to strip out this
304           information.</p>
305         </dd>
306
307         <dt>Solution:</dt>
308
309         <dd>
310           <p>We use a rewrite rule to strip out the status information
311           and remember it via an environment variable which can be
312           later dereferenced from within XSSI or CGI. This way a
313           URL <code>/foo/S=java/bar/</code> gets translated to
314           <code>/foo/bar/</code> and the environment variable named
315           <code>STATUS</code> is set to the value "java".</p>
316
317 <example><pre>
318 RewriteEngine on
319 RewriteRule   ^(.*)/<strong>S=([^/]+)</strong>/(.*)    $1/$3 [E=<strong>STATUS:$2</strong>]
320 </pre></example>
321         </dd>
322       </dl>
323
324     </section>
325
326     <section id="uservhosts">
327
328       <title>Virtual User Hosts</title>
329
330       <dl>
331         <dt>Description:</dt>
332
333         <dd>
334           <p>Assume that you want to provide
335           <code>www.<strong>username</strong>.host.domain.com</code>
336           for the homepage of username via just DNS A records to the
337           same machine and without any virtualhosts on this
338           machine.</p>
339         </dd>
340
341         <dt>Solution:</dt>
342
343         <dd>
344           <p>For HTTP/1.0 requests there is no solution, but for
345           HTTP/1.1 requests which contain a Host: HTTP header we
346           can use the following ruleset to rewrite
347           <code>http://www.username.host.com/anypath</code>
348           internally to <code>/home/username/anypath</code>:</p>
349
350 <example><pre>
351 RewriteEngine on
352 RewriteCond   %{<strong>HTTP_HOST</strong>}                 ^www\.<strong>[^.]+</strong>\.host\.com$
353 RewriteRule   ^(.+)                        %{HTTP_HOST}$1          [C]
354 RewriteRule   ^www\.<strong>([^.]+)</strong>\.host\.com(.*) /home/<strong>$1</strong>$2
355 </pre></example>
356         </dd>
357       </dl>
358
359     </section>
360
361     <section id="redirecthome">
362
363       <title>Redirect Homedirs For Foreigners</title>
364
365       <dl>
366         <dt>Description:</dt>
367
368         <dd>
369           <p>We want to redirect homedir URLs to another webserver
370           <code>www.somewhere.com</code> when the requesting user
371           does not stay in the local domain
372           <code>ourdomain.com</code>. This is sometimes used in
373           virtual host contexts.</p>
374         </dd>
375
376         <dt>Solution:</dt>
377
378         <dd>
379           <p>Just a rewrite condition:</p>
380
381 <example><pre>
382 RewriteEngine on
383 RewriteCond   %{REMOTE_HOST}  <strong>!^.+\.ourdomain\.com$</strong>
384 RewriteRule   ^(/~.+)         http://www.somewhere.com/$1 [R,L]
385 </pre></example>
386         </dd>
387       </dl>
388
389     </section>
390
391     <section id="redirectanchors">
392
393       <title>Redirecting Anchors</title>
394
395       <dl>
396         <dt>Description:</dt>
397
398         <dd>
399         <p>By default, redirecting to an HTML anchor doesn't work,
400         because mod_rewrite escapes the <code>#</code> character,
401         turning it into <code>%23</code>. This, in turn, breaks the
402         redirection.</p>
403         </dd>
404
405         <dt>Solution:</dt>
406
407         <dd>
408           <p>Use the <code>[NE]</code> flag on the
409           <code>RewriteRule</code>. NE stands for No Escape.
410           </p>
411         </dd>
412       </dl>
413
414     </section>
415
416     <section id="time-dependent">
417
418       <title>Time-Dependent Rewriting</title>
419
420       <dl>
421         <dt>Description:</dt>
422
423         <dd>
424           <p>When tricks like time-dependent content should happen a
425           lot of webmasters still use CGI scripts which do for
426           instance redirects to specialized pages. How can it be done
427           via <module>mod_rewrite</module>?</p>
428         </dd>
429
430         <dt>Solution:</dt>
431
432         <dd>
433           <p>There are a lot of variables named <code>TIME_xxx</code>
434           for rewrite conditions. In conjunction with the special
435           lexicographic comparison patterns <code>&lt;STRING</code>,
436           <code>&gt;STRING</code> and <code>=STRING</code> we can
437           do time-dependent redirects:</p>
438
439 <example><pre>
440 RewriteEngine on
441 RewriteCond   %{TIME_HOUR}%{TIME_MIN} &gt;0700
442 RewriteCond   %{TIME_HOUR}%{TIME_MIN} &lt;1900
443 RewriteRule   ^foo\.html$             foo.day.html
444 RewriteRule   ^foo\.html$             foo.night.html
445 </pre></example>
446
447           <p>This provides the content of <code>foo.day.html</code>
448           under the URL <code>foo.html</code> from
449           <code>07:00-19:00</code> and at the remaining time the
450           contents of <code>foo.night.html</code>. Just a nice
451           feature for a homepage...</p>
452         </dd>
453       </dl>
454
455     </section>
456
457     <section id="backward-compatibility">
458
459       <title>Backward Compatibility for YYYY to XXXX migration</title>
460
461       <dl>
462         <dt>Description:</dt>
463
464         <dd>
465           <p>How can we make URLs backward compatible (still
466           existing virtually) after migrating <code>document.YYYY</code>
467           to <code>document.XXXX</code>, e.g. after translating a
468           bunch of <code>.html</code> files to <code>.phtml</code>?</p>
469         </dd>
470
471         <dt>Solution:</dt>
472
473         <dd>
474           <p>We just rewrite the name to its basename and test for
475           existence of the new extension. If it exists, we take
476           that name, else we rewrite the URL to its original state.</p>
477
478
479 <example><pre>
480 #   backward compatibility ruleset for
481 #   rewriting document.html to document.phtml
482 #   when and only when document.phtml exists
483 #   but no longer document.html
484 RewriteEngine on
485 RewriteBase   /~quux/
486 #   parse out basename, but remember the fact
487 RewriteRule   ^(.*)\.html$              $1      [C,E=WasHTML:yes]
488 #   rewrite to document.phtml if exists
489 RewriteCond   %{REQUEST_FILENAME}.phtml -f
490 RewriteRule   ^(.*)$ $1.phtml                   [S=1]
491 #   else reverse the previous basename cutout
492 RewriteCond   %{ENV:WasHTML}            ^yes$
493 RewriteRule   ^(.*)$ $1.html
494 </pre></example>
495         </dd>
496       </dl>
497
498     </section>
499
500     <section id="old-to-new">
501
502       <title>From Old to New (intern)</title>
503
504       <dl>
505         <dt>Description:</dt>
506
507         <dd>
508           <p>Assume we have recently renamed the page
509           <code>foo.html</code> to <code>bar.html</code> and now want
510           to provide the old URL for backward compatibility. Actually
511           we want that users of the old URL even not recognize that
512           the pages was renamed.</p>
513         </dd>
514
515         <dt>Solution:</dt>
516
517         <dd>
518           <p>We rewrite the old URL to the new one internally via the
519           following rule:</p>
520
521 <example><pre>
522 RewriteEngine  on
523 RewriteBase    /~quux/
524 RewriteRule    ^<strong>foo</strong>\.html$  <strong>bar</strong>.html
525 </pre></example>
526         </dd>
527       </dl>
528
529     </section>
530
531     <section id="old-to-new-extern">
532
533       <title>From Old to New (extern)</title>
534
535       <dl>
536         <dt>Description:</dt>
537
538         <dd>
539           <p>Assume again that we have recently renamed the page
540           <code>foo.html</code> to <code>bar.html</code> and now want
541           to provide the old URL for backward compatibility. But this
542           time we want that the users of the old URL get hinted to
543           the new one, i.e. their browsers Location field should
544           change, too.</p>
545         </dd>
546
547         <dt>Solution:</dt>
548
549         <dd>
550           <p>We force a HTTP redirect to the new URL which leads to a
551           change of the browsers and thus the users view:</p>
552
553 <example><pre>
554 RewriteEngine  on
555 RewriteBase    /~quux/
556 RewriteRule    ^<strong>foo</strong>\.html$  <strong>bar</strong>.html  [<strong>R</strong>]
557 </pre></example>
558         </dd>
559       </dl>
560
561     </section>
562
563     <section id="static-to-dynamic">
564
565       <title>From Static to Dynamic</title>
566
567       <dl>
568         <dt>Description:</dt>
569
570         <dd>
571           <p>How can we transform a static page
572           <code>foo.html</code> into a dynamic variant
573           <code>foo.cgi</code> in a seamless way, i.e. without notice
574           by the browser/user.</p>
575         </dd>
576
577         <dt>Solution:</dt>
578
579         <dd>
580           <p>We just rewrite the URL to the CGI-script and force the
581           handler to be <strong>cgi-script</strong> so that it is
582           executed as a CGI program.
583           This way a request to <code>/~quux/foo.html</code>
584           internally leads to the invocation of
585           <code>/~quux/foo.cgi</code>.</p>
586
587 <example><pre>
588 RewriteEngine  on
589 RewriteBase    /~quux/
590 RewriteRule    ^foo\.<strong>html</strong>$  foo.<strong>cgi</strong>  [H=<strong>cgi-script</strong>]
591 </pre></example>
592         </dd>
593       </dl>
594
595     </section>
596
597     <section id="blocking-of-robots">
598
599       <title>Blocking of Robots</title>
600
601       <dl>
602         <dt>Description:</dt>
603
604         <dd>
605           <p>How can we block a really annoying robot from
606           retrieving pages of a specific webarea? A
607           <code>/robots.txt</code> file containing entries of the
608           "Robot Exclusion Protocol" is typically not enough to get
609           rid of such a robot.</p>
610         </dd>
611
612         <dt>Solution:</dt>
613
614         <dd>
615           <p>We use a ruleset which forbids the URLs of the webarea
616           <code>/~quux/foo/arc/</code> (perhaps a very deep
617           directory indexed area where the robot traversal would
618           create big server load). We have to make sure that we
619           forbid access only to the particular robot, i.e. just
620           forbidding the host where the robot runs is not enough.
621           This would block users from this host, too. We accomplish
622           this by also matching the User-Agent HTTP header
623           information.</p>
624
625 <example><pre>
626 RewriteCond %{HTTP_USER_AGENT}   ^<strong>NameOfBadRobot</strong>.*
627 RewriteCond %{REMOTE_ADDR}       ^<strong>123\.45\.67\.[8-9]</strong>$
628 RewriteRule ^<strong>/~quux/foo/arc/</strong>.+   -   [<strong>F</strong>]
629 </pre></example>
630         </dd>
631       </dl>
632
633     </section>
634
635     <section id="blocked-inline-images">
636
637       <title>Blocked Inline-Images</title>
638
639       <dl>
640         <dt>Description:</dt>
641
642         <dd>
643           <p>Assume we have under <code>http://www.quux-corp.de/~quux/</code>
644           some pages with inlined GIF graphics. These graphics are
645           nice, so others directly incorporate them via hyperlinks to
646           their pages. We don't like this practice because it adds
647           useless traffic to our server.</p>
648         </dd>
649
650         <dt>Solution:</dt>
651
652         <dd>
653           <p>While we cannot 100% protect the images from inclusion,
654           we can at least restrict the cases where the browser
655           sends a HTTP Referer header.</p>
656
657 <example><pre>
658 RewriteCond %{HTTP_REFERER} <strong>!^$</strong>
659 RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
660 RewriteRule <strong>.*\.gif$</strong>        -                                    [F]
661 </pre></example>
662
663 <example><pre>
664 RewriteCond %{HTTP_REFERER}         !^$
665 RewriteCond %{HTTP_REFERER}         !.*/foo-with-gif\.html$
666 RewriteRule <strong>^inlined-in-foo\.gif$</strong>   -                        [F]
667 </pre></example>
668         </dd>
669       </dl>
670
671     </section>
672
673     <section id="proxy-deny">
674
675       <title>Proxy Deny</title>
676
677       <dl>
678         <dt>Description:</dt>
679
680         <dd>
681           <p>How can we forbid a certain host or even a user of a
682           special host from using the Apache proxy?</p>
683         </dd>
684
685         <dt>Solution:</dt>
686
687         <dd>
688           <p>We first have to make sure <module>mod_rewrite</module>
689           is below(!) <module>mod_proxy</module> in the Configuration
690           file when compiling the Apache webserver. This way it gets
691           called <em>before</em> <module>mod_proxy</module>. Then we
692           configure the following for a host-dependent deny...</p>
693
694 <example><pre>
695 RewriteCond %{REMOTE_HOST} <strong>^badhost\.mydomain\.com$</strong>
696 RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]
697 </pre></example>
698
699           <p>...and this one for a user@host-dependent deny:</p>
700
701 <example><pre>
702 RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST}  <strong>^badguy@badhost\.mydomain\.com$</strong>
703 RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]
704 </pre></example>
705         </dd>
706       </dl>
707
708     </section>
709
710     <section id="external-rewriting">
711
712       <title>External Rewriting Engine</title>
713
714       <dl>
715         <dt>Description:</dt>
716
717         <dd>
718           <p>A FAQ: How can we solve the FOO/BAR/QUUX/etc.
719           problem? There seems no solution by the use of
720           <module>mod_rewrite</module>...</p>
721         </dd>
722
723         <dt>Solution:</dt>
724
725         <dd>
726           <p>Use an external <directive module="mod_rewrite"
727           >RewriteMap</directive>, i.e. a program which acts
728           like a <directive module="mod_rewrite"
729           >RewriteMap</directive>. It is run once on startup of Apache
730           receives the requested URLs on <code>STDIN</code> and has
731           to put the resulting (usually rewritten) URL on
732           <code>STDOUT</code> (same order!).</p>
733
734 <example><pre>
735 RewriteEngine on
736 RewriteMap    quux-map       <strong>prg:</strong>/path/to/map.quux.pl
737 RewriteRule   ^/~quux/(.*)$  /~quux/<strong>${quux-map:$1}</strong>
738 </pre></example>
739
740 <example><pre>
741 #!/path/to/perl
742
743 #   disable buffered I/O which would lead
744 #   to deadloops for the Apache server
745 $| = 1;
746
747 #   read URLs one per line from stdin and
748 #   generate substitution URL on stdout
749 while (&lt;&gt;) {
750     s|^foo/|bar/|;
751     print $_;
752 }
753 </pre></example>
754
755           <p>This is a demonstration-only example and just rewrites
756           all URLs <code>/~quux/foo/...</code> to
757           <code>/~quux/bar/...</code>. Actually you can program
758           whatever you like. But notice that while such maps can be
759           <strong>used</strong> also by an average user, only the
760           system administrator can <strong>define</strong> it.</p>
761         </dd>
762       </dl>
763
764     </section>
765
766 </manualpage>
767