]> granicus.if.org Git - apache/blob - docs/manual/rewrite/rewrite_guide_advanced.xml.fr
fix validation errors
[apache] / docs / manual / rewrite / rewrite_guide_advanced.xml.fr
1 <?xml version="1.0" encoding="ISO-8859-1" ?>
2 <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd">
3 <?xml-stylesheet type="text/xsl" href="../style/manual.fr.xsl"?>
4 <!-- English Revision : 805049 -->
5 <!-- French translation : Lucien GENTIS -->
6 <!-- Reviewed by : Vincent Deffontaines -->
7
8 <!--
9  Licensed to the Apache Software Foundation (ASF) under one or more
10  contributor license agreements.  See the NOTICE file distributed with
11  this work for additional information regarding copyright ownership.
12  The ASF licenses this file to You under the Apache License, Version 2.0
13  (the "License"); you may not use this file except in compliance with
14  the License.  You may obtain a copy of the License at
15
16      http://www.apache.org/licenses/LICENSE-2.0
17
18  Unless required by applicable law or agreed to in writing, software
19  distributed under the License is distributed on an "AS IS" BASIS,
20  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  See the License for the specific language governing permissions and
22  limitations under the License.
23 -->
24
25 <manualpage metafile="rewrite_guide_advanced.xml.meta">
26   <parentdocument href="./">Rewrite</parentdocument>
27
28   <title>Guide de r&eacute;&eacute;criture des URLs - Sujets avanc&eacute;s</title>
29
30   <summary>
31
32     <p>Ce document compl&eacute;mente la
33     <a href="../mod/mod_rewrite.html">documentation de r&eacute;f&eacute;rence</a> du
34     module <module>mod_rewrite</module>. Il d&eacute;crit les diff&eacute;rentes
35     mani&egrave;res d'utiliser le module d'Apache <module>mod_rewrite</module>
36     pour r&eacute;soudre les probl&egrave;mes d'URLs typiques auxquels sont souvent
37     confront&eacute;s les webmasters. Nous fournissons une description
38     d&eacute;taill&eacute;e de la r&eacute;solution de chaque probl&egrave;me par la configuration
39     d'un jeu de r&egrave;gles de r&eacute;&eacute;criture.</p>
40
41     <note type="warning">ATTENTION: il pourra s'av&eacute;rer n&eacute;cessaire de
42     modifier les exemples en fonction de la
43     configuration de votre serveur, par exemple en ajoutant le drapeau
44     <code>[PT]</code> si les modules <module>mod_alias</module> et
45     <module>mod_userdir</module> sont utilis&eacute;s, etc... Les jeux de
46     r&egrave;gles devront &eacute;galement &ecirc;tre adapt&eacute;s pour passer d'un contexte de
47     serveur &agrave; un contexte de r&eacute;pertoire (fichiers
48     <code>.htaccess</code>). Essayez de toujours bien comprendre ce que
49     fait un jeu de r&egrave;gles avant de l'utiliser, ce qui pourra vous &eacute;viter
50     bien des probl&egrave;mes.</note>
51
52   </summary>
53 <seealso><a href="../mod/mod_rewrite.html">Documentation du
54 module</a></seealso>
55 <seealso><a href="rewrite_intro.html">Introduction &agrave;
56 mod_rewrite</a></seealso>
57 <seealso><a href="rewrite_guide.html">Guide de r&eacute;&eacute;criture - exemples
58 utiles</a></seealso>
59 <seealso><a href="rewrite_tech.html">D&eacute;tails techniques</a></seealso>
60
61
62     <section id="cluster">
63
64       <title>Acc&egrave;s &agrave; une grappe de serveurs via un espace d'adressage
65       compatible</title>
66
67       <dl>
68         <dt>Description :</dt>
69
70         <dd>
71           <p>Comment cr&eacute;er un espace d'adressage homog&egrave;ne et compatible
72           avec
73           tous les serveurs WWW d'une grappe de serveurs d'un intranet ?
74           C'est &agrave; dire que toutes les URLs (par d&eacute;finition
75           locales &agrave; un
76           serveur et d&eacute;pendant donc de celui-ci) deviennent
77           v&eacute;ritablement <em>ind&eacute;pendantes</em> du serveur ! Nous voulons
78           disposer, pour acc&eacute;der &agrave; l'espace de nommage WWW, d'un seul
79           espace d'adressage compatible : aucune URL ne
80           doit inclure d'information quelconque &agrave; propos du serveur
81           cible physique. La grappe de serveurs doit elle-m&ecirc;me nous
82           diriger automatiquement vers le bon serveur cible physique,
83           selon les besoins, et ceci de mani&egrave;re transparente.</p>
84         </dd>
85
86         <dt>Solution :</dt>
87
88         <dd>
89           <p>Tout d'abord, la connaissance des serveurs cibles est issue
90           de tables de correspondances externes (distribu&eacute;es) qui
91           contiennent des informations sur la localisation de nos
92           utilisateurs, groupes et entit&eacute;s. Elles se pr&eacute;sentent sous la
93           forme :</p>
94
95 <example><pre>
96 utilisateur1  serveur_utilisateur1
97 utilisateur2  serveur_utilisateur2
98 :      :
99 </pre></example>
100
101           <p>On les enregistre sous forme de fichiers
102           <code>map.xxx-vers-serveur</code>. On doit ensuite faire
103           rediriger &agrave; tous les serveurs les URLs de la forme :</p>
104
105 <example><pre>
106 /u/utilisateur/chemin
107 /g/groupe/chemin
108 /e/entit&eacute;/chemin
109 </pre></example>
110
111           <p>vers</p>
112
113 <example><pre>
114 http://serveur-physique/u/utilisateur/chemin
115 http://serveur-physique/g/groupe/chemin
116 http://serveur-physique/e/entit&eacute;/chemin
117 </pre></example>
118
119           <p>si il n'est pas n&eacute;cessaire que chaque chemin d'URL &ecirc;tre valide sur chaque
120           serveur. Le jeu
121           de r&egrave;gles suivant le fait pour nous &agrave; l'aide des fichiers de
122           correspondance (en supposant que serveur0 soit un serveur par
123           d&eacute;faut qui sera choisi si l'utilisateur ne poss&egrave;de aucune
124           entr&eacute;e dans la table) :</p>
125
126 <example><pre>
127 RewriteEngine on
128
129 RewriteMap      utilisateur-vers-serveur   txt:/chemin/vers/map.utilisateur-vers-serveur
130 RewriteMap     groupe-vers-serveur   txt:/chemin/vers/map.groupe-vers-serveur
131 RewriteMap    entit&eacute;-vers-serveur   txt:/chemin/vers/map.entit&eacute;-vers-serveur
132
133 RewriteRule   ^/u/<strong>([^/]+)</strong>/?(.*)
134 http://<strong>${utilisateur-vers-serveur:$1|serveur0}</strong>/u/$1/$2
135 RewriteRule   ^/g/<strong>([^/]+)</strong>/?(.*)
136 http://<strong>${groupe-vers-serveur:$1|serveur0}</strong>/g/$1/$2
137 RewriteRule   ^/e/<strong>([^/]+)</strong>/?(.*)
138 http://<strong>${entit&eacute;-vers-serveur:$1|serveur0}</strong>/e/$1/$2
139
140 RewriteRule   ^/([uge])/([^/]+)/?$          /$1/$2/.www/
141 RewriteRule   ^/([uge])/([^/]+)/([^.]+.+)   /$1/$2/.www/$3\
142 </pre></example>
143         </dd>
144       </dl>
145
146     </section>
147
148     <section id="structuredhomedirs">
149
150       <title>R&eacute;pertoires utilisateurs structur&eacute;s</title>
151
152       <dl>
153         <dt>Description :</dt>
154
155         <dd>
156           <p>Certains sites poss&eacute;dant des milliers d'utilisateurs
157           organisent les r&eacute;pertoires home de mani&egrave;re
158           structur&eacute;e, <em>c'est &agrave; dire</em> que chaque r&eacute;pertoire home
159           se situe dans un sous-r&eacute;pertoire dont le nom commence (par
160           exemple) par le premier caract&egrave;re du nom de l'utilisateur.
161           Ainsi, <code>/~foo/chemin</code> est dans
162           <code>/home/<strong>f</strong>/foo/.www/chemin</code>, tandis
163           que <code>/~bar/chemin</code> est dans
164           <code>/home/<strong>b</strong>/bar/.www/chemin</code>.</p>
165         </dd>
166
167         <dt>Solution :</dt>
168
169         <dd>
170           <p>Le jeu de r&egrave;gles suivant permet de d&eacute;velopper les URLs avec
171           tilde selon la repr&eacute;sentation ci-dessus.</p>
172
173 <example><pre>
174 RewriteEngine on
175 RewriteRule   ^/~(<strong>([a-z])</strong>[a-z0-9]+)(.*)  /home/<strong>$2</strong>/$1/.www$3
176 </pre></example>
177         </dd>
178       </dl>
179
180     </section>
181
182     <section id="filereorg">
183
184       <title>R&eacute;organisation du syst&egrave;me de fichiers</title>
185
186       <dl>
187         <dt>Description :</dt>
188
189         <dd>
190           <p>Voici un cas d'esp&egrave;ce : une application tr&egrave;s efficace qui
191           fait un usage intensif de r&egrave;gles <code>RewriteRule</code>
192           dans le contexte du r&eacute;pertoire pour pr&eacute;senter un aspect
193           compr&eacute;hensible sur le Web sans modifier la structure des
194           donn&eacute;es.
195           Les coulisses de l'affaire : <strong><em>net.sw</em></strong>
196           rassemble mes archives de paquetages de logiciels Unix
197           librement accessibles, que j'ai commenc&eacute; &agrave; collectionner en
198           1992. Pour moi, c'est un passe-temps, mais aussi un travail,
199           car alors que j'&eacute;tudie la science informatique, j'ai aussi
200           travaill&eacute; depuis de nombreuses ann&eacute;es comme administrateur
201           syst&egrave;me et r&eacute;seau &agrave; mes heures perdues. Chaque semaine j'ai
202           besoin de tel ou tel logiciel, et j'ai donc cr&eacute;&eacute; une
203           arborescence tr&egrave;s ramifi&eacute;e de r&eacute;pertoires o&ugrave; je stocke les
204           paquetages :</p>
205
206 <example><pre>
207 drwxrwxr-x   2 netsw  users    512 Aug  3 18:39 Audio/
208 drwxrwxr-x   2 netsw  users    512 Jul  9 14:37 Benchmark/
209 drwxrwxr-x  12 netsw  users    512 Jul  9 00:34 Crypto/
210 drwxrwxr-x   5 netsw  users    512 Jul  9 00:41 Database/
211 drwxrwxr-x   4 netsw  users    512 Jul 30 19:25 Dicts/
212 drwxrwxr-x  10 netsw  users    512 Jul  9 01:54 Graphic/
213 drwxrwxr-x   5 netsw  users    512 Jul  9 01:58 Hackers/
214 drwxrwxr-x   8 netsw  users    512 Jul  9 03:19 InfoSys/
215 drwxrwxr-x   3 netsw  users    512 Jul  9 03:21 Math/
216 drwxrwxr-x   3 netsw  users    512 Jul  9 03:24 Misc/
217 drwxrwxr-x   9 netsw  users    512 Aug  1 16:33 Network/
218 drwxrwxr-x   2 netsw  users    512 Jul  9 05:53 Office/
219 drwxrwxr-x   7 netsw  users    512 Jul  9 09:24 SoftEng/
220 drwxrwxr-x   7 netsw  users    512 Jul  9 12:17 System/
221 drwxrwxr-x  12 netsw  users    512 Aug  3 20:15 Typesetting/
222 drwxrwxr-x  10 netsw  users    512 Jul  9 14:08 X11/
223 </pre></example>
224
225           <p>J'ai d&eacute;cid&eacute; en 1996 de rendre cette archive disponible pour
226           le monde via une interface web agr&eacute;able. "Agr&eacute;able" signifie
227           que je voulais vous offrir une interface o&ugrave; vous pourriez
228           naviguer directement &agrave; travers la hi&eacute;rarchie des archives.
229           Mais "agr&eacute;able" signifie aussi que je ne voulais rien changer
230           dans cette hi&eacute;rarchie - m&ecirc;me pas en ajoutant queques scripts
231           CGI &agrave; son sommet. Pourquoi ? Parceque j'avais pr&eacute;vu de rendre
232           ult&eacute;rieurement la structure ci-dessus accessible aussi via
233           FTP, et je ne voulais pas voir de fichiers CGI ou Web &agrave; ce
234           niveau.</p>
235         </dd>
236
237         <dt>Solution :</dt>
238
239         <dd>
240           <p>La solution comporte deux parties : la premi&egrave;re consiste en
241           un ensemble de scripts CGI qui cr&eacute;ent toutes les pages &agrave; tous
242           les niveaux de r&eacute;pertoires &agrave; la vol&eacute;e. Je les ai plac&eacute;s dans
243           <code>/e/netsw/.www/</code> comme suit :</p>
244
245 <example><pre>
246 -rw-r--r--   1 netsw  users    1318 Aug  1 18:10 .wwwacl
247 drwxr-xr-x  18 netsw  users     512 Aug  5 15:51 DATA/
248 -rw-rw-rw-   1 netsw  users  372982 Aug  5 16:35 LOGFILE
249 -rw-r--r--   1 netsw  users     659 Aug  4 09:27 TODO
250 -rw-r--r--   1 netsw  users    5697 Aug  1 18:01 netsw-about.html
251 -rwxr-xr-x   1 netsw  users     579 Aug  2 10:33 netsw-access.pl
252 -rwxr-xr-x   1 netsw  users    1532 Aug  1 17:35 netsw-changes.cgi
253 -rwxr-xr-x   1 netsw  users    2866 Aug  5 14:49 netsw-home.cgi
254 drwxr-xr-x   2 netsw  users     512 Jul  8 23:47 netsw-img/
255 -rwxr-xr-x   1 netsw  users   24050 Aug  5 15:49 netsw-lsdir.cgi
256 -rwxr-xr-x   1 netsw  users    1589 Aug  3 18:43 netsw-search.cgi
257 -rwxr-xr-x   1 netsw  users    1885 Aug  1 17:41 netsw-tree.cgi
258 -rw-r--r--   1 netsw  users     234 Jul 30 16:35 netsw-unlimit.lst
259 </pre></example>
260
261           <p>Le sous-r&eacute;pertoire <code>DATA/</code> contient la structure
262           de r&eacute;pertoires proprement dite mentionn&eacute;e plus haut, <em>c'est
263           &agrave; dire</em> les v&eacute;ritables ressources
264           <strong><em>net.sw</em></strong> et est mis &agrave; jour
265           automatiquement via <code>rdist</code> &agrave; intervalles de temps
266           r&eacute;guliers. Reste la seconde partie du probl&egrave;me : comment
267           relier ces deux structures selon une arborescence d'URL
268           facile d'acc&egrave;s ? Il nous faut cacher le r&eacute;pertoire
269           <code>DATA/</code> &agrave; l'utilisateur durant l'ex&eacute;cution des
270           scripts CGI appropri&eacute;s aux diff&eacute;rentes URLs. Voici comment :
271           tout d'abord, j'ajoute ces deux r&egrave;gles dans le fichier de
272           configuration du r&eacute;pertoire racine <directive
273           module="core">DocumentRoot</directive> du serveur afin de
274           r&eacute;&eacute;crire le chemin d'URL public <code>/net.sw/</code> vers le
275           chemin interne <code>/e/netsw</code> :</p>
276
277 <example><pre>
278 RewriteRule  ^net.sw$       net.sw/        [R]
279 RewriteRule  ^net.sw/(.*)$  e/netsw/$1
280 </pre></example>
281
282           <p>La premi&egrave;re r&egrave;gle concerne les requ&ecirc;tes qui ne comportent
283           pas de slash de fin ! C'est la seconde r&egrave;gle qui fait le
284           v&eacute;ritable travail. Et maintenant vient la super configuration
285           qui se trouve dans le fichier de configuration de r&eacute;pertoire
286           <code>/e/netsw/.www/.wwwacl</code> :</p>
287
288 <example><pre>
289 Options       ExecCGI FollowSymLinks Includes MultiViews
290
291 RewriteEngine on
292
293 #  l'acc&egrave;s s'effectue via le pr&eacute;fixe /net.sw/
294 RewriteBase   /net.sw/
295
296 #  tout d'abord, on r&eacute;&eacute;crit le r&eacute;pertoire racine vers
297 #  le script CGI qui lui est associ&eacute;
298 RewriteRule   ^$                       netsw-home.cgi     [L]
299 RewriteRule   ^index\.html$            netsw-home.cgi     [L]
300
301 #  on supprime les sous-r&eacute;pertoires lorsque
302 #  le navigateur nous atteint depuis des pages de r&eacute;pertoire
303 RewriteRule   ^.+/(netsw-[^/]+/.+)$    $1                 [L]
304
305 #  on stoppe maintenant la r&eacute;&eacute;criture pour les fichiers locaux
306 RewriteRule   ^netsw-home\.cgi.*       -                  [L]
307 RewriteRule   ^netsw-changes\.cgi.*    -                  [L]
308 RewriteRule   ^netsw-search\.cgi.*     -                  [L]
309 RewriteRule   ^netsw-tree\.cgi$        -                  [L]
310 RewriteRule   ^netsw-about\.html$      -                  [L]
311 RewriteRule   ^netsw-img/.*$           -                  [L]
312
313 #  ce qui reste est un sous-r&eacute;pertoire qui peut &ecirc;tre trait&eacute;
314 #  par un autre script CGI
315 RewriteRule   !^netsw-lsdir\.cgi.*     -                  [C]
316 RewriteRule   (.*)                     netsw-lsdir.cgi/$1
317 </pre></example>
318
319           <p>Quelques indices pour l'interpr&eacute;tation :</p>
320
321           <ol>
322             <li>Remarquez le drapeau <code>L</code> (last) et l'absence
323             de cha&icirc;ne de substitution ('<code>-</code>') dans la
324             quatri&egrave;me partie.</li>
325
326             <li>Remarquez le caract&egrave;re <code>!</code> (not)  et le
327             drapeau <code>C</code> (chain) dans la premi&egrave;re r&egrave;gle de la
328             derni&egrave;re partie.</li>
329
330             <li>Remarquez le mod&egrave;le qui correspond &agrave; tout dans la
331             derni&egrave;re r&egrave;gle.</li>
332           </ol>
333         </dd>
334       </dl>
335
336     </section>
337
338     <section id="redirect404">
339
340       <title>Rediriger les URLs erron&eacute;es vers un autre serveur Web</title>
341
342       <dl>
343         <dt>Description :</dt>
344
345         <dd>
346           <p>Une question typique de la FAQ &agrave; propos de la r&eacute;&eacute;criture
347           revient souvent : comment rediriger vers un serveur B les
348           requ&ecirc;tes qui &eacute;chouent sur un serveur A ? On s'acquitte en
349           g&eacute;n&eacute;ral de cette t&acirc;che via des scripts CGI <directive
350           module="core">ErrorDocument</directive> en Perl, mais il
351           existe aussi une solution avec <module>mod_rewrite</module>.
352           Notez cependant que les performances sont moindres qu'avec
353           l'utilisation d'un script CGI <directive
354           module="core">ErrorDocument</directive> !</p>
355         </dd>
356
357         <dt>Solution :</dt>
358
359         <dd>
360           <p>La premi&egrave;re solution poss&egrave;de des performances sup&eacute;rieures
361           mais moins de souplesse, et est moins sure :</p>
362
363 <example><pre>
364 RewriteEngine on
365 RewriteCond  %{DOCUMENT_ROOT/%{REQUEST_URI}  <strong>!-f</strong>
366 RewriteRule   ^(.+)                             http://<strong>serveurB</strong>.dom/$1
367 </pre></example>
368
369           <p>Le probl&egrave;me r&eacute;side dans le fait que seules les pages
370           situ&eacute;es dans la racine <directive
371           module="core">DocumentRoot</directive> seront redirig&eacute;es. Mais
372           m&ecirc;me si vous pouvez ajouter des conditions suppl&eacute;mentaires (par
373           exemple pour traiter aussi les r&eacute;pertoires home, etc...), il
374           existe une meilleure solution :</p>
375
376 <example><pre>
377 RewriteEngine on
378 RewriteCond   %{REQUEST_URI} <strong>!-U</strong>
379 RewriteRule   ^(.+)          http://<strong>serveurB</strong>.dom/$1
380 </pre></example>
381 reprendre ici
382           <p>On utilise ici la fonctionnalit&eacute; de pr&eacute;vision des URLs
383           futures de <module>mod_rewrite</module>. Et cette solution
384           fonctionne pour tous les types d'URLs et de mani&egrave;re s&ucirc;re. Par
385           contre, cette m&eacute;thode a un impact sur les performances du
386           serveur web, car chaque requ&ecirc;te entra&icirc;ne le traitement d'une
387           sous-requ&ecirc;te interne suppl&eacute;mentaire. Par cons&eacute;quent, vous
388           pouvez l'utiliser si votre serveur web s'ex&eacute;cute sur un CPU
389           puissant. Dans le cas d'une machine plus lente, utilisez la
390           premi&egrave;re approche, ou mieux, un script CGI <directive
391           module="core">ErrorDocument</directive>.</p>
392         </dd>
393       </dl>
394
395     </section>
396
397    <section id="archive-access-multiplexer">
398
399       <title>Multiplexeur d'acc&egrave;s aux archives</title>
400
401       <dl>
402         <dt>Description :</dt>
403
404         <dd>
405           <p>Connaissez-vous la grande archive CPAN (Comprehensive Perl Archive
406           Network) situ&eacute;e &agrave; <a href="http://www.perl.com/CPAN"
407           >http://www.perl.com/CPAN</a> ?
408           CPAN redirige automatiquement les navigateurs vers un des
409           nombreux serveurs FTP r&eacute;partis &agrave; travers le monde
410           (g&eacute;n&eacute;ralement un serveur assez proche du client) ; chaque
411           serveur h&eacute;berge l'int&eacute;gralit&eacute; d'un miroir CPAN. Il s'agit ni
412           plus ni moins qu'un service d'acc&egrave;s FTP multiplex&eacute;. Alors que
413           le fonctionnement de l'archive CPAN repose sur des scripts
414           CGI, comment impl&eacute;menter une approche similaire avec
415           <module>mod_rewrite</module> ?</p>
416         </dd>
417
418         <dt>Solution :</dt>
419
420         <dd>
421           <p>Premi&egrave;rement, remarquons que depuis la version 3.0.0,
422           <module>mod_rewrite</module> accepte aussi le pr&eacute;fixe
423           "<code>ftp:</code>" dans les redirections. Et deuxi&egrave;mement,
424           l'approximation de la localisation peut &ecirc;tre effectu&eacute;e par une
425           table de correspondances <directive
426           module="mod_rewrite">RewriteMap</directive>, en se basant sur
427           la racine du domaine du client. Un jeu de r&egrave;gles cha&icirc;n&eacute;es
428           astucieux nous permet d'utiliser cette racine du domaine comme
429           cl&eacute; de recherche dans notre table de correspondances de
430           multiplexage.</p>
431
432 <example><pre>
433 RewriteEngine on
434 RewriteMap    multiplex                txt:/chemin/vers/map.cxan
435 RewriteRule   ^/CxAN/(.*)              %{REMOTE_HOST}::$1                 [C]
436 RewriteRule   ^.+\.<strong>([a-zA-Z]+)</strong>::(.*)$
437 ${multiplex:<strong>$1</strong>|ftp.d&eacute;faut.dom}$2  [R,L]
438 </pre></example>
439
440 <example><pre>
441 ##
442 ##  map.cxan -- Multiplexing Map for CxAN%{DOCUMENT_ROOT/%{REQUEST_URI}
443 ##
444
445 de        ftp://ftp.cxan.de/CxAN/
446 uk        ftp://ftp.cxan.uk/CxAN/
447 com       ftp://ftp.cxan.com/CxAN/
448  :
449 ##EOF##
450 </pre></example>
451         </dd>
452       </dl>
453
454     </section>
455
456    <section id="browser-dependent-content">
457
458       <title>Contenu d&eacute;pendant du navigateur</title>
459
460       <dl>
461         <dt>Description :</dt>
462
463         <dd>
464           <p>Il est parfois n&eacute;cessaire, au moins pour les pages
465           principales, de fournir un contenu optimum adapt&eacute; &agrave; chaque
466           type de navigateur, c'est &agrave; dire que l'on doit
467           fournir une version pour les navigateurs courants, une version
468           diff&eacute;rente pour les navigateurs en mode texte du style de
469           Lynx, et une autre pour les autres navigateurs.</p>
470         </dd>
471
472         <dt>Solution :</dt><!-- %{DOCUMENT_ROOT/%{REQUEST_URI} -->
473
474         <dd>
475           <p>On ne peut pas utiliser la n&eacute;gociation de contenu car les
476           navigateurs ne fournissent pas leur type dans cette forme.
477           Nous devons nous baser sur l'en-t&ecirc;te HTTP "User-Agent". La
478           configuration ci-dessous effectue les actions suivantes : si
479           l'en-t&ecirc;te HTTP "User-Agent" commence par "Mozilla/3", la page
480           <code>foo.html</code> est r&eacute;&eacute;crite en <code>foo.NS.html</code>
481           et la r&eacute;&eacute;criture s'arr&ecirc;te. Si le navigateur est "Lynx" ou
482           "Mozilla" version 1 ou 2, la page
483           <code>foo.html</code> est r&eacute;&eacute;crite en
484           <code>foo.20.html</code>. Tous les autres navigateurs
485           re&ccedil;oivent la page <code>foo.32.html</code>. Voici le jeu de
486           r&egrave;gles :</p>
487
488 <example><pre>
489 RewriteCond %{HTTP_USER_AGENT}  ^<strong>Mozilla/3</strong>.*
490 RewriteRule ^foo\.html$         foo.<strong>NS</strong>.html          [<strong>L</strong>]
491
492 RewriteCond %{HTTP_USER_AGENT}  ^<strong>Lynx/</strong>.*         [OR]
493 RewriteCond %{HTTP_USER_AGENT}  ^<strong>Mozilla/[12]</strong>.*
494 RewriteRule ^foo\.html$         foo.<strong>20</strong>.html          [<strong>L</strong>]
495
496 RewriteRule ^foo\.html$         foo.<strong>32</strong>.html          [<strong>L</strong>]
497 </pre></example>
498         </dd>
499       </dl>
500
501     </section>
502
503     <section id="dynamic-mirror">
504
505       <title>Miroir dynamique</title>
506
507       <dl>
508         <dt>Description :</dt>
509
510         <dd>
511           <p>Supposons que nous voulions int&eacute;grer dans notre espace de
512           nommage de belles pages web situ&eacute;es sur un serveur distant.
513           Dans le cas d'un serveur FTP, nous aurions utilis&eacute; le
514           programme <code>mirror</code> qui maintient vraiment une copie
515           des donn&eacute;es distantes mise &agrave; jour explicitement sur le serveur
516           local. Pour un serveur web, nous pourrions utiliser le
517           programme <code>webcopy</code> qui utilise le protocole HTTP.
518           Ces deux techniques pr&eacute;sentent cependant un
519           inconv&eacute;nient majeur : la copie locale n'est v&eacute;ritablement &agrave;
520           jour qu'au moment o&ugrave; nous avons lanc&eacute; le programme. Plut&ocirc;t qu'
521           un miroir statique devant &ecirc;tre d&eacute;fini explicitement, il serait
522           pr&eacute;f&eacute;rable d'avoir un miroir dynamique dont le contenu serait
523           mis &agrave; jour automatiquement, &agrave; la demande, sur le(s) serveur(s)
524           distant(s).</p>
525         </dd>
526
527         <dt>Solution :</dt>
528
529         <dd>
530           <p>Pour y parvenir, on fait
531           correspondre la page web ou m&ecirc;me l'ensemble du
532           r&eacute;pertoire web distants &agrave; notre espace de nommage en utilisant
533           la fonctionnalit&eacute; <dfn>Mandataire</dfn> (drapeau
534           <code>[P]</code> ou <code>[proxy]</code>) :</p>
535
536 <example><pre>
537 RewriteEngine  on
538 RewriteBase    /~quux/
539 RewriteRule    ^<strong>page-convoit&eacute;e/</strong>(.*)$  <strong>http://www.tstimpreso.com/page-convoit&eacute;e/</strong>$1  [<strong>P</strong>]
540 </pre></example>
541
542 <example><pre>
543 RewriteEngine  on
544 RewriteBase    /~quux/
545 RewriteRule    ^<strong>usa-news\.html</strong>$   <strong>http://www.quux-corp.com/news/index.html</strong>  [<strong>P</strong>]
546 </pre></example>
547         </dd>
548       </dl>
549
550     </section>
551
552     <section id="reverse-dynamic-mirror">
553
554       <title>Miroir dynamique inverse</title>
555
556       <dl>
557         <dt>Description :</dt>
558
559         <dd>...</dd>
560
561         <dt>Solution :</dt>
562
563         <dd>
564 <example><pre>
565 RewriteEngine on
566 RewriteCond   /miroir/du/site-distant/$1           -U
567 RewriteRule   ^http://www\.site-distant\.com/(.*)$ /miroir/du/site-distant/$1
568 </pre></example>
569         </dd>
570       </dl>
571
572     </section>
573
574     <section id="retrieve-missing-data">
575
576       <title>R&eacute;cup&eacute;rer des donn&eacute;es manquantes depuis l'Intranet</title>
577
578       <dl>
579         <dt>Description :</dt>
580
581         <dd>
582           <p>C'est une m&eacute;thode astucieuse permettant de faire
583           fonctionner virtuellement un serveur web d'entreprise
584           (<code>www.quux-corp.dom</code>) sur
585           l'Internet (ext&eacute;rieur &agrave; l'entreprise), tout en maintenant et
586           conservant dans la r&eacute;alit&eacute; ses donn&eacute;es sur un serveur web
587           (<code>www2.quux-corp.dom</code>) de l'Intranet (interne &agrave;
588           l'entreprise) prot&eacute;g&eacute; par un pare-feu. L'astuce consiste, sur
589           le serveur web externe, &agrave; r&eacute;cup&eacute;rer &agrave; la vol&eacute;e sur le serveur interne
590           les donn&eacute;es demand&eacute;es.</p>
591         </dd>
592
593         <dt>Solution :</dt>
594
595         <dd>
596           <p>Tout d'abord, nous devons nous assurer que notre pare-feu
597           prot&egrave;ge bien le serveur web interne, et que seul le serveur
598           web externe est autoris&eacute; &agrave; y r&eacute;cup&eacute;rer des donn&eacute;es. Dans le
599           cas d'un filtrage par paquets, nous pourrions par exemple
600           d&eacute;finir un jeu de r&egrave;gles du pare-feu du style :</p>
601
602 <example><pre>
603 <strong>ALLOW</strong> serveur www.quux-corp.dom Port &gt;1024 --&gt;
604 serveur www2.quux-corp.dom Port <strong>80</strong>
605 <strong>DENY</strong>  serveur *                 Port *     --&gt;
606 serveur www2.quux-corp.dom Port <strong>80</strong>
607 </pre></example>
608
609           <p>Il vous suffit d'adapter ces r&egrave;gles &agrave; la syntaxe de votre
610           pare-feu. Nous pouvons maintenant d&eacute;finir les r&egrave;gles de
611           <module>mod_rewrite</module> qui serviront &agrave; r&eacute;cup&eacute;rer les
612           donn&eacute;es manquantes en arri&egrave;re-plan via la fonctionnalit&eacute; de
613           mandataire :</p>
614
615 <example><pre>
616 RewriteRule ^/~([^/]+)/?(.*)          /home/$1/.www/$2 [C]
617 # L'utilisation de REQUEST_FILENAME ci dessous est correcte dans cet
618 # exemple de contexte au niveau serveur car la r&egrave;gle qui fait r&eacute;f&eacute;rence
619 # &agrave; REQUEST_FILENAME est cha&icirc;n&eacute;e &agrave; une r&egrave;gle qui d&eacute;finit
620 # REQUEST_FILENAME.
621 RewriteCond %{REQUEST_FILENAME}       <strong>!-f</strong>
622 RewriteCond %{REQUEST_FILENAME}       <strong>!-d</strong>
623 RewriteRule ^/home/([^/]+)/.www/?(.*) http://<strong>www2</strong>.quux-corp.dom/~$1/pub/$2 [<strong>P</strong>]
624 </pre></example>
625         </dd>
626       </dl>
627
628     </section>
629
630     <section id="load-balancing">
631
632       <title>R&eacute;partition de charge</title>
633
634       <dl>
635         <dt>Description :</dt>
636
637         <dd>
638           <p>Supposons que nous voulions r&eacute;partir la charge du trafic
639           vers <code>www.example.com</code> entre les serveurs
640           <code>www[0-5].example.com</code> (un total de 6 serveurs).
641           Comment y parvenir ?</p>
642         </dd>
643
644         <dt>Solution :</dt>
645
646         <dd>
647           <p>Il existe de nombreuses solutions &agrave; ce probl&egrave;me. Nous
648           d&eacute;crirons tout d'abord une variante assez connue bas&eacute;e sur
649           DNS, puis une autre bas&eacute;e sur <module>mod_rewrite</module>
650           :</p>
651
652           <ol>
653             <li>
654               <strong>Round-Robin (tourniquet) DNS</strong>
655
656               <p>La m&eacute;thode de r&eacute;partition de charge la plus simple
657               consiste &agrave; utiliser le "DNS round-robin"
658               (rotation d'adresses) de
659               <code>BIND</code>. Vous devez seulement enregistrer les
660               serveurs <code>www[0-9].example.com</code> de mani&egrave;re
661               habituelle dans votre DNS &agrave; l'aide d'enregistrements de
662               type A (adresse), comme suit :</p>
663
664 <example><pre>
665 www0   IN  A       1.2.3.1
666 www1   IN  A       1.2.3.2
667 www2   IN  A       1.2.3.3
668 www3   IN  A       1.2.3.4
669 www4   IN  A       1.2.3.5
670 www5   IN  A       1.2.3.6
671 </pre></example>
672
673               <p>Puis vous ajoutez les entr&eacute;es suivantes :</p>
674
675 <example><pre>
676 www   IN  A       1.2.3.1
677 www   IN  A       1.2.3.2
678 www   IN  A       1.2.3.3
679 www   IN  A       1.2.3.4
680 www   IN  A       1.2.3.5
681 </pre></example>
682
683               <p>Maintenant, lors de la r&eacute;solution de
684               <code>www.example.com</code>, <code>BIND</code> renvoie
685               <code>www0-www5</code> - mais selon une permutation
686               diff&eacute;rente &agrave; chaque fois. De cette fa&ccedil;on, les clients sont
687               r&eacute;partis entre les diff&eacute;rents serveurs. Notez cependant
688               que cette m&eacute;thode de r&eacute;partition de charge n'est pas
689               parfaite, car les r&eacute;solutions DNS sont mises en cache par
690               les clients et les autres serveurs DNS du r&eacute;seau, si
691               bien que lorsqu'un client s'est vu r&eacute;soudre
692               <code>www.example.com</code> en un des
693               <code>wwwN.example.com</code>, toutes ses requ&ecirc;tes ult&eacute;rieures
694               continueront d'aller vers la m&ecirc;me adresse IP (et donc le
695               m&ecirc;me serveur), au lieu d'&ecirc;tre r&eacute;parties entre les autres
696               serveurs. Le r&eacute;sultat est cependant globalement
697               satisfaisant car les requ&ecirc;tes sont r&eacute;parties
698               collectivement entre chacun des serveurs web.</p>
699             </li>
700
701             <li>
702               <strong>R&eacute;partition de charge bas&eacute;e sur DNS</strong>
703
704               <p>Une m&eacute;thode de r&eacute;partition de charge sophistiqu&eacute;e bas&eacute;e
705               sur DNS consiste &agrave; utiliser le programme
706               <code>lbnamed</code> que l'on peut trouver &agrave; <a
707               href="http://www.stanford.edu/~riepel/lbnamed/">
708               http://www.stanford.edu/~riepel/lbnamed/</a>.
709               Associ&eacute; &agrave; des outils auxiliaires, il s'agit d'un programme
710               en Perl 5 qui permet d'effectuer une v&eacute;ritable r&eacute;partition
711               de charge bas&eacute;e sur DNS.</p>
712             </li>
713
714             <li>
715               <strong>Round-Robin bas&eacute; sur la fonctionnalit&eacute; de
716               mandataire</strong>
717
718               <p>Dans cette variante, nous utilisons
719               <module>mod_rewrite</module> et sa fonctionnalit&eacute; de
720               mandataire. Tout d'abord, nous d&eacute;finissons
721               <code>www0.example.com</code> comme un autre nom de
722               <code>www.example.com</code> en ajoutant l'entr&eacute;e</p>
723
724 <example><pre>
725 www    IN  CNAME   www0.example.com.
726 </pre></example>
727
728               <p>dans le DNS. Puis nous d&eacute;finissons
729               <code>www0.example.com</code> comme serveur mandataire
730               seulement, c'est &agrave; dire que nous configurons cette machine
731               de telle sorte que toutes les URLs qui lui arrivent soient
732               simplement transmises, via le mandataire interne, vers un
733               des 5 autres serveurs (<code>www1-www5</code>). Pour y
734               parvenir, nous d&eacute;finissons tout d'abord un jeu de r&egrave;gles
735               qui contacte un script de r&eacute;partition de charge
736               <code>lb.pl</code> pour toutes les URLs.</p>
737
738 <example><pre>
739 RewriteEngine on
740 RewriteMap    lb      prg:/chemin/vers/lb.pl
741 RewriteRule   ^/(.+)$ ${lb:$1}           [P,L]
742 </pre></example>
743
744               <p>Puis nous &eacute;crivons <code>lb.pl</code> :</p>
745
746 <example><pre>
747 #!/chemin/vers/perl
748 ##
749 ##  lb.pl -- script de r&eacute;partition de charge
750 ##
751
752 $| = 1;
753
754 $name   = "www";     # la base du nom du serveur
755 $first  = 1;         # le premier serveur (pas 0 ici, car 0 correspond &agrave;
756                      # moi-m&ecirc;me)
757 $last   = 5;         # le dernier serveur du tourniquet
758 $domain = "foo.dom"; # le nom de domaine
759
760 $cnt = 0;
761 while (&lt;STDIN&gt;) {
762     $cnt = (($cnt+1) % ($last+1-$first));
763     $server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);
764     print "http://$server/$_";
765 }
766
767 ##EOF##
768 </pre></example>
769
770               <note>Une derni&egrave;re remarque : &agrave; quoi cela sert-il ?
771               <code>www0.example.com</code>, quant &agrave; lui, n'est-il pas
772               toujours surcharg&eacute; ? La r&eacute;ponse est oui, il est surcharg&eacute;,
773               mais seulement avec des requ&ecirc;tes de mandataire ! Tous les
774               traitements SSI, CGI, ePerl, etc... sont enti&egrave;rement
775               effectu&eacute;s sur les autres machines. Ceci peut fonctionner
776               correctement pour un site complexe. Le plus grand risque
777               r&eacute;side ici dans le fait que www0 est un passage oblig&eacute; et
778               que s'il est hors service, les autres serveurs deviennent
779               inaccessibles.</note>
780             </li>
781
782             <li>
783               <strong>R&eacute;partiteur de charge d&eacute;di&eacute;</strong>
784
785               <p>Il existe aussi des solutions plus sophistiqu&eacute;es.
786               Cisco, F5, et de nombreuses autres soci&eacute;t&eacute;s proposent
787               des r&eacute;partiteurs de charge mat&eacute;riels (utilis&eacute;s en g&eacute;n&eacute;ral
788               en mode doubl&eacute; &agrave; des fins de redondance), qui offrent une
789               r&eacute;partition de charge sophistiqu&eacute;e et des fonctionnalit&eacute;s
790               de passage automatique en mode de fonctionnement par d&eacute;faut
791               en cas de probl&egrave;me. Cependant, des solutions logicielles
792               offrent aussi des fonctionnalit&eacute;s similaires avec du
793               mat&eacute;riel standard. Si vos besoins correspondent et si vous
794               &ecirc;tes assez riche, vous pouvez envisager ces solutions. La
795               <a href="http://vegan.net/lb/">liste de diffusion lb-l</a>
796               est un bon point de d&eacute;part pour vos recherches.</p>
797             </li>
798           </ol>
799         </dd>
800       </dl>
801
802     </section>
803
804     <section id="new-mime-type">
805
806       <title>Nouveau type MIME, nouveau service</title>
807
808       <dl>
809         <dt>Description :</dt>
810
811         <dd>
812           <p>On trouve de nombreux programmes CGI attractifs sur le
813           r&eacute;seau. Mais leur emploi est souvent r&eacute;barbatif, si bien que
814           de nombreux webmasters ne les utilisent pas. M&ecirc;me la
815           fonctionnalit&eacute; de gestionnaire Action d'Apache pour les types
816           MIME ne convient que lorsque les programmes CGI ne n&eacute;cessitent
817           pas d'URLs sp&eacute;ciales (r&eacute;ellement <code>PATH_INFO</code> et
818           <code>QUERY_STRINGS</code>) en entr&eacute;e. Tout d'abord,
819           d&eacute;finissons un nouveau type de fichier ayant pour extension
820           <code>.scgi</code> (pour CGI s&eacute;curis&eacute;) qui sera associ&eacute; pour
821           traitement au programme populaire <code>cgiwrap</code>. Le
822           probl&egrave;me est le suivant : par exemple, si on utilise un style
823           d'URL bien d&eacute;fini (voir ci-dessus), un fichier situ&eacute; dans le
824           r&eacute;pertoire home de l'utilisateur pourra correspondre &agrave; l'URL
825           <code>/u/user/foo/bar.scgi</code>. Mais <code>cgiwrap</code>
826           n&eacute;cessite des URLs de la forme
827           <code>/~user/foo/bar.scgi/</code>. La r&egrave;gle suivante apporte
828           la solution :</p>
829
830 <example><pre>
831 RewriteRule ^/[uge]/<strong>([^/]+)</strong>/\.www/(.+)\.scgi(.*) ...
832 ... /interne/cgi/utilisateur/cgiwrap/~<strong>$1</strong>/$2.scgi$3  [NS,<strong>T=application/x-http-cgi</strong>]
833 </pre></example>
834
835           <p>Ou consid&eacute;rons ces autres programmes attractifs :
836           <code>wwwlog</code> (qui affiche le journal des acc&egrave;s
837           <code>access.log</code> pour un sous r&eacute;pertoire correspondant
838           &agrave; une URL) et <code>wwwidx</code> (qui ex&eacute;cute Glimpse sur un
839           sous r&eacute;pertoire correspondant &agrave; une URL). Nous devons fournir
840           l'URL correspondante &agrave; ces programmes afin qu'ils sachent sur
841           quel r&eacute;pertoire ils doivent agir. Mais c'est en g&eacute;n&eacute;ral
842           compliqu&eacute;, car ils peuvent &ecirc;tre appel&eacute;s &agrave; nouveau
843           par la forme d'URL alternative, c'est &agrave; dire que typiquement,
844           nous ex&eacute;cuterions le programme <code>swwidx</code> depuis
845           <code>/u/user/foo/</code> via un hyperlien vers</p>
846
847 <example><pre>
848 /internal/cgi/user/swwidx?i=/u/user/foo/
849 </pre></example>
850
851           <p>ce qui n'est pas satisfaisant, car nous devons expliciter
852           <strong>&agrave; la fois</strong> la localisation du r&eacute;pertoire
853           <strong>et</strong> la localisation du programme CGI dans
854           l'hyperlien. Si nous devons nous r&eacute;organiser, il nous faudra
855           beaucoup de temps pour modifier tous les hyperliens.</p>
856         </dd>
857
858         <dt>Solution :</dt>
859
860         <dd>
861           <p>La solution consiste ici &agrave; fournir un nouveau format d'URL
862           qui redirige automatiquement vers la requ&ecirc;te CGI appropri&eacute;e.
863           Pour cela, on d&eacute;finit les r&egrave;gles suivantes :</p>
864
865 <example><pre>
866 RewriteRule   ^/([uge])/([^/]+)(/?.*)/\*  /interne/cgi/utilisateur/wwwidx?i=/$1/$2$3/
867 RewriteRule   ^/([uge])/([^/]+)(/?.*):log /interne/cgi/utilisateur/wwwlog?f=/$1/$2$3
868 </pre></example>
869
870           <p>Et maintenant l'hyperlien qui renvoie vers
871           <code>/u/user/foo/</code> se r&eacute;duit &agrave;</p>
872
873 <example><pre>
874 HREF="*"
875 </pre></example>
876
877           <p>qui est automatiquement transform&eacute; en interne en</p>
878
879 <example><pre>
880 /internal/cgi/user/wwwidx?i=/u/user/foo/
881 </pre></example>
882
883           <p>Une approche similaire permet d'invoquer le programme CGI
884           du journal des acc&egrave;s lorsque l'hyperlien <code>:log</code> est
885           utilis&eacute;.</p>
886         </dd>
887       </dl>
888
889     </section>
890
891     <section id="on-the-fly-content">
892
893       <title>R&eacute;g&eacute;neration de contenu &agrave; la vol&eacute;e</title>
894
895       <dl>
896         <dt>Description :</dt>
897
898         <dd>
899           <p>Voici une fonctionnalit&eacute; vraiment &eacute;sot&eacute;rique : des pages
900           g&eacute;n&eacute;r&eacute;es dynamiquement mais servies statiquement, c'est &agrave;
901           dire que les pages doivent &ecirc;tre servies comme des pages
902           purement statiques (lues depuis le syst&egrave;me de fichiers et
903           servies en l'&eacute;tat), mais doivent &ecirc;tre g&eacute;n&eacute;r&eacute;es dynamiquement
904           par le serveur web si elles sont absentes. Ainsi, vous pouvez
905           avoir des pages g&eacute;n&eacute;r&eacute;es par CGI qui sont servies statiquement
906           &agrave; moins qu'un administrateur (ou une t&acirc;che de
907           <code>cron</code>) ne supprime les
908           contenus statiques. Les contenus sont ensuite actualis&eacute;s.</p>
909         </dd>
910
911         <dt>Solution :</dt>
912
913         <dd>
914           A cet effet, on utilise le jeu de r&egrave;gles suivant :
915
916 <example><pre>
917 # Cet exemple n'est valable que dans un contexte de r&eacute;pertoire
918 RewriteCond %{REQUEST_FILENAME}   <strong>!-s</strong>
919 RewriteRule ^page\.<strong>html</strong>$          page.<strong>cgi</strong>   [T=application/x-httpd-cgi,L]
920 </pre></example>
921
922           <p>Ainsi, une requ&ecirc;te pour <code>page.html</code> entra&icirc;ne
923           l'ex&eacute;cution interne de la page <code>page.cgi</code>
924           correspondante si <code>page.html</code> n'existe pas
925           ou poss&egrave;de une taille de fichier nulle. L'astuce r&eacute;side ici
926           dans le fait que <code>page.cgi</code> est un script CGI
927           qui (en plus de <code>STDOUT</code>) &eacute;crit sa sortie dans le
928           fichier <code>page.html</code>. Une fois le script ex&eacute;cut&eacute;, le
929           serveur sert la page <code>page.html</code> fra&icirc;chement
930           g&eacute;n&eacute;r&eacute;e. Si le webmaster
931           veut actualiser les contenus, il lui suffit de supprimer le
932           fichier <code>page.html</code> (le plus souvent via une t&acirc;che
933           de <code>cron</code>).</p>
934         </dd>
935       </dl>
936
937     </section>
938
939     <section id="autorefresh">
940
941       <title>Actualisation automatique d'un document</title>
942
943       <dl>
944         <dt>Description :</dt>
945
946         <dd>
947           <p>Lorsque nous cr&eacute;ons une page web complexe, ne serait-il pas
948           souhaitable que le navigateur web actualise automatiquement la
949           page chaque fois que nous en sauvegardons une nouvelle version
950           &agrave; partir de notre &eacute;diteur ? Impossible ?</p>
951         </dd>
952
953         <dt>Solution :</dt>
954
955         <dd>
956           <p>Non ! Nous allons pour cela combiner la fonctionnalit&eacute; MIME
957           multipart, la fonctionnalit&eacute; NPH du serveur web et la
958           puissance de <module>mod_rewrite</module> pour la manipulation
959           d'URLs. Tout d'abord, nous d&eacute;finissons une nouvelle
960           fonctionnalit&eacute; pour les URLs : l'ajout de
961           <code>:refresh</code> &agrave; toute URL fait que la 'page' est
962           actualis&eacute;e chaque fois que la ressource est mise &agrave; jour dans
963           le syst&egrave;me de fichiers.</p>
964
965 <example><pre>
966 RewriteRule   ^(/[uge]/[^/]+/?.*):refresh  /interne/cgi/apache/nph-refresh?f=$1
967 </pre></example>
968
969           <p>Nous appelons maintenant cette URL</p>
970
971 <example><pre>
972 /u/foo/bar/page.html:refresh
973 </pre></example>
974
975           <p>ce qui entra&icirc;ne en interne l'invocation de l'URL</p>
976
977 <example><pre>
978 /interne/cgi/apache/nph-refresh?f=/u/foo/bar/page.html
979 </pre></example>
980
981           <p>Il ne reste plus qu'&agrave; &eacute;crire le script CGI. Bien que l'on
982           &eacute;crive habituellement dans ces cas "laiss&eacute; &agrave; la charge du
983           lecteur &agrave; titre d'exercice", ;-) je vous l'offre, aussi.</p>
984
985 <example><pre>
986 #!/sw/bin/perl
987 ##
988 ##  nph-refresh -- script NPH/CGI pour l'actualisation automatique de
989 ##  pages
990 ##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
991 ##
992 $| = 1;
993
994 #   &eacute;clate la variable QUERY_STRING
995 @pairs = split(/&amp;/, $ENV{'QUERY_STRING'});
996 foreach $pair (@pairs) {
997     ($name, $value) = split(/=/, $pair);
998     $name =~ tr/A-Z/a-z/;
999     $name = 'QS_' . $name;
1000     $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
1001     eval "\$$name = \"$value\"";
1002 }
1003 $QS_s = 1 if ($QS_s eq '');
1004 $QS_n = 3600 if ($QS_n eq '');
1005 if ($QS_f eq '') {
1006     print "HTTP/1.0 200 OK\n";
1007     print "Content-type: text/html\n\n";
1008     print "&amp;lt;b&amp;gt;ERREUR&amp;lt;/b&amp;gt;: Aucun fichier fourni\n";
1009     exit(0);
1010 }
1011 if (! -f $QS_f) {
1012     print "HTTP/1.0 200 OK\n";
1013     print "Content-type: text/html\n\n";
1014     print "&amp;lt;b&amp;gt;ERREUR&amp;lt;/b&amp;gt;: Fichier $QS_f non trouv&eacute;\n";
1015     exit(0);
1016 }
1017
1018 sub print_http_headers_multipart_begin {
1019     print "HTTP/1.0 200 OK\n";
1020     $bound = "ThisRandomString12345";
1021     print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
1022     &amp;print_http_headers_multipart_next;
1023 }
1024
1025 sub print_http_headers_multipart_next {
1026     print "\n--$bound\n";
1027 }
1028
1029 sub print_http_headers_multipart_end {
1030     print "\n--$bound--\n";
1031 }
1032
1033 sub displayhtml {
1034     local($buffer) = @_;
1035     $len = length($buffer);
1036     print "Content-type: text/html\n";
1037     print "Content-length: $len\n\n";
1038     print $buffer;
1039 }
1040
1041 sub readfile {
1042     local($file) = @_;
1043     local(*FP, $size, $buffer, $bytes);
1044     ($x, $x, $x, $x, $x, $x, $x, $size) = stat($file);
1045     $size = sprintf("%d", $size);
1046     open(FP, "&amp;lt;$file");
1047     $bytes = sysread(FP, $buffer, $size);
1048     close(FP);
1049     return $buffer;
1050 }
1051
1052 $buffer = &amp;readfile($QS_f);
1053 &amp;print_http_headers_multipart_begin;
1054 &amp;displayhtml($buffer);
1055
1056 sub mystat {
1057     local($file) = $_[0];
1058     local($time);
1059
1060     ($x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime) = stat($file);
1061     return $mtime;
1062 }
1063
1064 $mtimeL = &amp;mystat($QS_f);
1065 $mtime = $mtime;
1066 for ($n = 0; $n &amp;lt; $QS_n; $n++) {
1067     while (1) {
1068         $mtime = &amp;mystat($QS_f);
1069         if ($mtime ne $mtimeL) {
1070             $mtimeL = $mtime;
1071             sleep(2);
1072             $buffer = &amp;readfile($QS_f);
1073             &amp;print_http_headers_multipart_next;
1074             &amp;displayhtml($buffer);
1075             sleep(5);
1076             $mtimeL = &amp;mystat($QS_f);
1077             last;
1078         }
1079         sleep($QS_s);
1080     }
1081 }
1082
1083 &amp;print_http_headers_multipart_end;
1084
1085 exit(0);
1086
1087 ##EOF##
1088 </pre></example>
1089         </dd>
1090       </dl>
1091
1092     </section>
1093
1094     <section id="mass-virtual-hosting">
1095
1096       <title>H&eacute;bergement virtuel de masse</title>
1097
1098       <dl>
1099         <dt>Description :</dt>
1100
1101         <dd>
1102           <p>La fonctionnalit&eacute; <directive type="section" module="core"
1103           >VirtualHost</directive> d'Apache est int&eacute;ressante et
1104           fonctionne de mani&egrave;re satisfaisante jusqu'&agrave; quelques
1105           douzaines de serveurs virtuels. Par contre, si vous &ecirc;tes un
1106           FAI et devez h&eacute;berger des centaines de serveurs virtuels,
1107           cette m&eacute;thode n'est pas optimale.</p>
1108         </dd>
1109
1110         <dt>Solution :</dt>
1111
1112         <dd>
1113           <p>Pour fournir cette fonctionnalit&eacute; avec
1114           <module>mod_rewrite</module>, on fait correspondre &agrave; notre espace de
1115           nommage la page web ou m&ecirc;me le r&eacute;pertoire complet distants en
1116           utilisant la fonctionnalit&eacute; <dfn>Mandataire</dfn>
1117           (drapeau <code>[P]</code>) :</p>
1118
1119 <example><pre>
1120 ##
1121 ##  vhost.map
1122 ##
1123 www.vhost1.dom:80  /chemin/vers/racine-doc/vhost1
1124 www.vhost2.dom:80  /chemin/vers/racine-doc/vhost2
1125      :
1126 www.vhostN.dom:80  /chemin/vers/racine-doc/vhostN
1127 </pre></example>
1128
1129 <example><pre>
1130 ##
1131 ##  httpd.conf
1132 ##
1133     :
1134 #   utilisation du nom d'h&ocirc;te canonique pour les redirections, etc...
1135 UseCanonicalName on
1136
1137     :
1138 #   ajout du serveur virtuel en t&ecirc;te du format CLF
1139 CustomLog  /chemin/vers/access_log  "%{VHOST}e %h %l %u %t \"%r\" %&gt;s %b"
1140     :
1141
1142 #   activation du moteur de r&eacute;&eacute;criture pour le serveur principal
1143 RewriteEngine on
1144
1145 #   d&eacute;finition de deux tables de correspondances : une premi&egrave;re pour
1146 #   corriger les URLs et une seconde qui associe les serveurs virtuels
1147 #   disponibles avec leurs racines des documents correspondantes.
1148 RewriteMap    lowercase    int:tolower
1149 RewriteMap    vhost        txt:/chemin/vers/vhost.map
1150
1151 #   et enfin s&eacute;lection proprement dite du serveur virtuel appropri&eacute; via
1152 #   une seule r&egrave;gle longue et complexe :
1153 #
1154 #   1. on s'assure de ne pas s&eacute;lectionner un h&ocirc;te virtuel pour les
1155 #   adresses communes
1156
1157 RewriteCond   %{REQUEST_URI}  !^/adresse-commune1/.*
1158 RewriteCond   %{REQUEST_URI}  !^/adresse-commune2/.*
1159     :
1160 RewriteCond   %{REQUEST_URI}  !^/adresse-communeN/.*
1161 #
1162 #   2. on v&eacute;rifie que l'on dispose bien d'un en-t&ecirc;te Host, car
1163 #   actuellement, cette m&eacute;thode ne peut faire de l'h&eacute;bergement virtuel
1164 #   qu'avec cet en-t&ecirc;te
1165 RewriteCond   %{HTTP_HOST}  !^$
1166 #
1167 #   3. mise en minuscules du nom d'h&ocirc;te
1168 RewriteCond   ${lowercase:%{HTTP_HOST}|NONE}  ^(.+)$
1169 #
1170 #   4. recherche ce ce nom d'h&ocirc;te dans vhost.map et
1171 #      enregistrement de celui-ci seulement s'il s'agit d'un chemin
1172 #      (et non "NONE" en provenance de la condition pr&eacute;c&eacute;dente)
1173 RewriteCond   ${vhost:%1}  ^(/.*)$
1174 #
1175 #   5. nous pouvons enfin faire correspondre l'URL avec la racine des
1176 #   documents correspondant au serveur virtuel appropri&eacute; et enregistrer
1177 #   ce dernier &agrave; des fins de journalisation
1178 RewriteRule   ^/(.*)$   %1/$1  [E=VHOST:${lowercase:%{HTTP_HOST}}]
1179     :
1180 </pre></example>
1181         </dd>
1182       </dl>
1183
1184     </section>
1185
1186     <section id="host-deny">
1187
1188       <title>Interdiction d'h&ocirc;tes</title>
1189
1190       <dl>
1191         <dt>Description :</dt>
1192
1193         <dd>
1194           <p>Comment interdire l'acc&egrave;s &agrave; notre serveur &agrave; une liste
1195           d'h&ocirc;tes ?</p>
1196         </dd>
1197
1198         <dt>Solution :</dt>
1199
1200         <dd>
1201           <p>Pour Apache &gt;= 1.3b6 :</p>
1202
1203 <example><pre>
1204 RewriteEngine on
1205 RewriteMap    h&ocirc;tes-interdits  txt:/chemin/vers/h&ocirc;tes-interdits
1206 RewriteCond   ${h&ocirc;tes-interdits:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]
1207 RewriteCond   ${h&ocirc;tes-interdits:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND
1208 RewriteRule   ^/.*  -  [F]
1209 </pre></example>
1210
1211           <p>Pour Apache &lt;= 1.3b6 :</p>
1212
1213 <example><pre>
1214 RewriteEngine on
1215 RewriteMap    h&ocirc;tes-interdits  txt:/chemin/vers/h&ocirc;tes-interdits
1216 RewriteRule   ^/(.*)$ ${h&ocirc;tes-interdits:%{REMOTE_HOST}|NOT-FOUND}/$1
1217 RewriteRule   !^NOT-FOUND/.* - [F]
1218 RewriteRule   ^NOT-FOUND/(.*)$ ${h&ocirc;tes-interdits:%{REMOTE_ADDR}|NOT-FOUND}/$1
1219 RewriteRule   !^NOT-FOUND/.* - [F]
1220 RewriteRule   ^NOT-FOUND/(.*)$ /$1
1221 </pre></example>
1222
1223 <example><pre>
1224 ##
1225 ##  hosts.deny
1226 ##
1227 ##  ATTENTION! Ceci est une table de correspondances, pas une liste,
1228 ##  m&ecirc;me si on l'utilise en tant que telle. mod_rewrite l'interpr&egrave;te
1229 ##  comme un ensemble de paires cl&eacute;/valeur ; chaque entr&eacute;e doit donc
1230 ##  au moins poss&eacute;der une valeur fictive "-".
1231 ##
1232
1233 193.102.180.41 -
1234 bsdti1.sdm.de  -
1235 192.76.162.40  -
1236 </pre></example>
1237         </dd>
1238       </dl>
1239
1240     </section>
1241
1242     <section id="proxy-deny">
1243
1244       <title>Interdiction du mandataire</title>
1245
1246       <dl>
1247         <dt>Description :</dt>
1248
1249         <dd>
1250           <p>Comment interdire l'utilisation du mandataire d'Apache pour
1251           un certain h&ocirc;te, ou m&ecirc;me seulement pour un utilisateur
1252           de cet h&ocirc;te ?</p>
1253         </dd>
1254
1255         <dt>Solution :</dt>
1256
1257         <dd>
1258           <p>Nous devons tout d'abord nous assurer que
1259           <module>mod_rewrite</module> arrive apr&egrave;s(!)
1260           <module>mod_proxy</module> dans le fichier de configuration
1261           lors de la compilation du serveur web Apache. De cette fa&ccedil;on,
1262           il est appel&eacute; <em>avant</em> <module>mod_proxy</module>. Nous
1263           pouvons ensuite d&eacute;finir cette r&egrave;gle pour une interdiction
1264           d&eacute;pendant de l'h&ocirc;te :</p>
1265
1266 <example><pre>
1267 RewriteCond %{REMOTE_HOST} <strong>^h&ocirc;te-&agrave;-rejeter\.mon-domaine\.com$</strong>
1268 RewriteRule !^http://[^/.]\.mon-domaine.com.*  - [F]
1269 </pre></example>
1270
1271           <p>...et celle-ci pour une interdiction d&eacute;pendant de
1272           utilisateur@h&ocirc;te :</p>
1273
1274 <example><pre>
1275 RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST}  <strong>^utilisateur-&agrave;-
1276 rejeter@h&ocirc;te-&agrave;-rejeter\.mon-domaine\.com$</strong>
1277 RewriteRule !^http://[^/.]\.mon-domaine.com.*  - [F]
1278 </pre></example>
1279         </dd>
1280       </dl>
1281
1282     </section>
1283
1284     <section id="special-authentication">
1285
1286       <title>Variante particuli&egrave;re d'authentification</title>
1287
1288       <dl>
1289         <dt>Description :</dt>
1290
1291         <dd>
1292           <p>On a parfois besoin d'une authentification tr&egrave;s
1293           particuli&egrave;re, par exemple une authentification qui v&eacute;rifie la
1294           pr&eacute;sence d'un utilisateur dans une liste explicitement
1295           d&eacute;finie. Seuls ceux qui sont pr&eacute;sents dans la liste se voient
1296           accorder un acc&egrave;s, et ceci sans avoir &agrave;
1297           s'identifier/authentifier (comme c'est le cas avec une
1298           authentification de base via <module>mod_auth</module>).</p>
1299         </dd>
1300
1301         <dt>Solution :</dt>
1302
1303         <dd>
1304           <p>On d&eacute;finit une liste de conditions de r&eacute;&eacute;criture pour
1305           interdire l'acc&egrave;s &agrave; tout le monde, sauf aux utilisateurs
1306           autoris&eacute;s :</p>
1307
1308 <example><pre>
1309 RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^ami1@client1.quux-corp\.com$</strong>
1310 RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^ami2</strong>@client2.quux-corp\.com$
1311 RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^ami3</strong>@client3.quux-corp\.com$
1312 RewriteRule ^/~quux/seulement-pour-les-amis/      -                                 [F]
1313 </pre></example>
1314         </dd>
1315       </dl>
1316
1317     </section>
1318
1319     <section id="referer-deflector">
1320
1321       <title>Redirection bas&eacute;e sur le r&eacute;f&eacute;rent</title>
1322
1323       <dl>
1324         <dt>Description :</dt>
1325
1326         <dd>
1327           <p>Comment &eacute;crire un programme souple qui redirige certaines
1328           URLs en se basant sur l'en-t&ecirc;te HTTP "Referer", et peut &ecirc;tre
1329           configur&eacute; avec autant de pages de r&eacute;f&eacute;rence
1330           que l'on veut ?</p>
1331         </dd>
1332
1333         <dt>Solution :</dt>
1334
1335         <dd>
1336           <p>On utilise le jeu de r&egrave;gles vraiment astucieux suivant :</p>
1337
1338 <example><pre>
1339 RewriteMap  deflector txt:/chemin/vers/deflector.map
1340
1341 RewriteCond %{HTTP_REFERER} !=""
1342 RewriteCond ${deflector:%{HTTP_REFERER}} ^-$
1343 RewriteRule ^.* %{HTTP_REFERER} [R,L]
1344
1345 RewriteCond %{HTTP_REFERER} !=""
1346 RewriteCond ${deflector:%{HTTP_REFERER}|NOT-FOUND} !=NOT-FOUND
1347 RewriteRule ^.* ${deflector:%{HTTP_REFERER}} [R,L]
1348 </pre></example>
1349
1350           <p>... en association avec la table de r&eacute;&eacute;criture
1351           correspondante :</p>
1352
1353 <example><pre>
1354 ##
1355 ##  deflector.map
1356 ##
1357
1358 http://www.mauvais-sujets.com/mauvais/index.html    -
1359 http://www.mauvais-sujets.com/mauvais/index2.html   -
1360 http://www.mauvais-sujets.com/mauvais/index3.html   http://quelque-part.com/
1361 </pre></example>
1362
1363           <p>Les requ&ecirc;tes sont redirig&eacute;es vers la page de r&eacute;f&eacute;rence
1364           (lorsque la valeur correspondant &agrave; la cl&eacute; extraite de la table
1365           de correspondances est &eacute;gale &agrave; "<code>-</code>"), ou vers une
1366           URL sp&eacute;cifique (lorsqu'une URL est d&eacute;finie dans la table de
1367           correspondances comme second argument).</p>
1368         </dd>
1369       </dl>
1370
1371     </section>
1372
1373 </manualpage>
1374