Le site arthur.bebou.netlib.re - retour accueil
git clone git://bebou.netlib.re/arthur.bebou
Log | Files | Refs |
index.sh (23140B)
1 #! page 2 title: Des services internet simples et sobres 3 author: Arthur Pons 4 description: Étudions comment construire et mettre en ligne des services relativement simples et sobres sur internet 5 publication: 2024-06-10 6 7 sectionmd: main 8 9 Cet article n'a pas encore été relu, un peu d'indulgence :) 10 11 ## Le "trop-long-j'ai-pas-lu" : 12 13 Sur un système unix possédant netcat[^1] vous pouvez faire 14 15 nc bebou.netlib.re 2222 16 17 puis taper `h` ou `help` et avoir la liste des commandes disponibles. 18 19 ## Pourquoi ? 20 21 ### Les outils existants 22 23 J'avais développé quelques services que des proches ou moi trouvions utiles, 24 notamment de quoi [conjuguer](/conjugaison/), récupérer des 25 [synonymes](/crisco-des/), faire une recherche youtube et certainement d'autres 26 à l'avenir. Ces outils sont généralement des scripts shell de scraping assez 27 simples, utilisés en local. 28 Ils se substituent à des usages inadéquats de sites web ou de 29 recherches Google. Remplacer *"ouvrir firefox -> taper 'conjugaison manger' -> 30 cliquer sur le premier lien qui a pas l'air de vouloir me montrer mille popups 31 de cookies ou de newsletters -> scroller à travers la page pour trouver la 32 ligne que je veux -> faire un copier-coller"* par *"ouvrir un terminal -> taper 'c 33 manger je présent' -> faire un copier-coller"* ou tout autre utilisation 34 davantage automatisée semblait opportun. On économise du temps, de la 35 frustration, des aller-retour clavier/souris, du texte à taper, de la bande 36 passante, des cycles cpu, de la ram et on s'offre en prime une meilleure 37 interopérabilité avec le reste du système. Selon quelle est la source des 38 données on se permet également de travailler en mode hors-ligne. 39 40 ### Qu'est-ce que "service" convoque comme images dans ma tête ? 41 42 J'ai eu plusieurs conversations avec des membres de Katzele sur le sens que l'on 43 met derrière le mot "service" numérique. Intuitivement, en me nourrissant 44 davantage des exemples que je trouve autour de moi que d'une réflexion 45 proprement théorique sur le sujet, je conçois le service comme le rapport 46 majoritaire qui existe entre les personnes détenant du matériel et des 47 compétences techniques et les autres, souhaitant faire appel à ce matériel et 48 ces compétences là. La première personne, généralement une entreprise, une 49 association, un état, va à l'aide d'ingénieur·es répondre au besoin en créant 50 un "service". Il y a mille façons de les créer, en impliquant plus ou moins 51 les personnes qui sont en demande par exemple, ce qui donnera mille formes 52 différentes de services mais j'ai le sentiment que dans l'ensemble quelques 53 caractéristiques restent assez constantes. Premièrement le cadre technique dans 54 lesquels ils s'inscrivent est, en 2024 et ce depuis des années, presque toujours 55 le web. Deuxièmement ils semblent vouloir, parfois volontairement, tenir au 56 à distance les personnes utilisateur·ices du fonctionnement interne du service. 57 La première pose des questions de soutenabilité pour des raisons mille fois 58 évoquées sur ce blog bien que l'on puisse déjà drastiquement optimiser cette 59 variable en faisant du web "sobre" et pour peu que l'on y évolue avec un 60 outillage radicalement différent de celui majoritaire. La seconde va à 61 l'encontre de l'utopie technique rêvée à Katzele dans laquelle la ligne de 62 démarcation entre celleux qui détiennent et savent manipuler les outils et 63 celleux qui ne peuvent que les consommer ou en consommer leurs fruits serait 64 floutée ou à minima moins épaisse, dans la limite de ce que la complexité des 65 outils nous permet d'envisager. 66 67 C'est au gré de ces pensées que je n'ai durant ces dernières années jamais 68 sérieusement entrepris d'interfacer mes outils via du web. Je privilégiais le 69 fait de faire des ateliers, des formations, des démos et des articles associés 70 pour distribuer le code localement sur les machines des personnes intéressées, 71 propager les idées et inciter les personnes à faire leurs propres versions quand 72 elles le peuvent. 73 74 Évidemment la viabilité de cette stratégie est certainement corrélée à la 75 complexité des idées et du code en question. Plus l'outil est complexe plus il 76 sera intéressant pour moi d'investir une unique fois du temps 77 dans une interface web et dire aux personnes "va simplement sur telle url" 78 plutôt que de dupliquer l'outil ou ses variantes n fois sur n machines de n 79 copaines. De la même manière, la pertinence de la critique est corrélée à 80 l'écart qu'il existe entre la simplicité du service rendu et la complexité de 81 son implémentation technique. C'est pour cela que les services implémentés 82 jusque là sont simples et requiert peu d'interactions avec l'utilisateur·ice. 83 C'est aussi parce que je n'ai pas l'envie ni le temps de faire des choses 84 compliquées. 85 86 ### Mais l'idée fera tout de même son bout de chemin 87 88 Et pourtant, pour de multiples raisons que je n'ai pas audité en profondeur, 89 les personnes sont généralement bien plus enthousiasmées par l'idée d'avoir un 90 service web qu'une version locale, indépendante d'un service tiers et à 91 l'interface plus sobre. J'en prends pour exemple un atelier sur [l'ensemble de 92 systèmes que j'utilise pour consulter des vidéos youtube](/youtube/)[^2] de plus 93 de deux heures pendant lesquelles les échanges avaient été fréquents et de 94 qualité. Plusieurs jours après au gré du hasard je retombe sur l'une des 95 personnes ayant assisté à l'atelier qui partage son enthousiasme à une tierce 96 personne autour de [l'interface web sobre de recherche 97 youtuube](https://codemadness.org/idiotbox) et uniquement de cet aspect là. Je 98 n'ai pas de mal à comprendre que c'était peut-être pour elle le seul outil qui 99 se substituait directement à l'interface youtube classique sans pour autant 100 changer ses habitudes mais j'avoue m'être dit "oh un peu dommage 😞". 101 102 Alors fort de cette expérience et pour éviter de tomber dans le sophisme de la 103 solution parfaite[^3] je me suis dit que j'allais regarder ce qu'il était 104 possible de faire entre l'interface web simple (formulaire html + cgi) et 105 l'outil en ligne de commande en local. 106 107 ## Quelle forme pour ces services ? 108 109 L'objectif est de minimiser au moins : 110 111 * La dépendance à une connection internet 112 * nombre de dépendances 113 * l'instabilité de ces dépendances 114 * nombre de lignes de codes de l'outil et des dépendances 115 * nombre de personnes dans les projets de ces dépendances[^4] 116 117 En permettant : 118 119 * l'interopérabilité de l'outil avec des interfaces textuelles et cli 120 121 ### Communiquer sur internet 122 123 Sur internet les machines communiquent entre elles via des socket. 124 Un moyen simple de créer des sockets est d'utiliser un outil fait pour qui 125 pourra les ouvrir ou écouter dessus. `netcat-openbsd` en est un exemple. 126 Il a l'avantage d'être relativement simple, ne faisant "que" 2340 lignes de C, 127 dont le fichier principal a été édité par une vingtaine de personne depuis 128 25 ans. Sans faire de revue plus détaillée[^5] j'en conclu que c'est un logiciel 129 suffisamment stable fonctionnement et techniquement pour assurer une bonne 130 soutenabilité. La documentation est raisonnable et présente même quelques 131 exemples[^6]. Par exemple, pour communiquer à un serveur web, nc permet de faire 132 passer tel quel un header HTTP et de recevoir la réponse : 133 134 $ nc bebou.netlib.re 80 135 GET / HTTP/1.1 136 Host: arthur.bebou.netlib.re 137 138 HTTP/1.1 200 OK 139 Server: nginx/1.22.1 140 Date: Mon, 10 Jun 2024 12:15:14 GMT 141 Content-Type: text/html 142 Content-Length: 5940 143 Last-Modified: Wed, 05 Jun 2024 17:41:29 GMT 144 Connection: keep-alive 145 ETag: "6660a349-1734" 146 Accept-Ranges: bytes 147 148 <!DOCTYPE html> 149 <html lang="fr"> 150 <head> 151 <title>Unix et environnement ?</title> 152 <link rel=stylesheet href="/style.css" /> 153 <meta charset="utf-8"> 154 <meta name="viewport" content="width=device-width,initial-scale=1.0"> 155 <meta name="description" content="Un blog au sujet de la culture Unix redirigée vers la diminution de l'impact environnementale du numérique" /> 156 <meta name="author" content="Arthur Pons" /> 157 <link rel="icon" href="/favicon.png" /> 158 [...] 159 160 Au passage on voit que c'est côté serveur web qu'est géré la partie 161 "virtual-hosting" qui, sur la base de la valeur du `Host` renverra tel site 162 plutôt qu'un autre. 163 164 Cet exemple qui paraîtra trivial pour les personnes ayant commencé à faire de 165 l'informatique il y a plus de vingt an et un peu magique pour la plupart des 166 autres[^7] met quelque chose en lumière : Il n'y a rien de magique dans la façon 167 dont les machines parlent entre elles via des protocoles. D'ailleurs n'importe 168 quoi peut s'échanger entre deux sockets. Le manuel nous enseigne que (traduit de 169 l'anglais) : 170 171 > Il est assez aisé de construire un modèle client/serveur très simple 172 > avec nc. Dans une console écoutez sur un port donné. Par exemple : 173 > 174 > $ nc -l 1234 175 > 176 > nc attend une connection sur le port 1234. Dans une seconde console (ou une 177 > seconde machine) connectez vous à la machine et le port correspondant : 178 > 179 > $ nc -N 127.0.0.1 1234 180 > 181 > Il devrait dorénavant y avoir une connection établie entre les deux ports. 182 > Ce qui est tapé dans la seconde console sera concaténé à la première et 183 > vice-versa. 184 185 Admettons que l'on souhaite que ce que l'on tape dans la première console soit 186 traité d'une manière ou d'une autre et nous revienne. Plusieurs versions de 187 netcat proposent une option `-e` qui passe les données reçues à un script tier 188 pour traitement. Ce n'est pas le cas de netcat-openbsd, il faudra donc trouver 189 un subterfuge. Ca tombe bien, il nous est donné dans le manuel : 190 191 > Il n'existe pas d'option `-c` ou `-e` dans ce netcat mais vous pouvez toujours 192 > exécuter une commande après qu'une connection ait été établie en redirigeant 193 > des descripteurs de fichiers. Attention, ouvrir un port et laisser n'importe 194 > qui exécuter des commandes arbitraires sur votre serveur est DANGEREUX. Si vous 195 > avez réellement besoin de le faire voici un exemple : 196 > 197 > Côté serveur : 198 > 199 > $ rm -f /tmp/f; mkfifo /tmp/f 200 > $ cat /tmp/f | /bin/sh -i 2>&1 | nc -l 127.0.0.1 1234 > /tmp/f 201 > 202 > Côté client : 203 > 204 > $ nc host.example.com 1234 205 > $ (shell prompt from host.example.com) 206 207 L'example donne carrément un shell interactif à toute personne qui se connecte. 208 C'est effectivement très dangeureux mais en plus ce n'est pas ce que l'on 209 cherche à faire. 210 211 ### Exécuter des commandes à distance 212 213 Le serveur est déjà équipé des commandes `conjuguer`, `synonyme` etc. On 214 cherche, en se basant sur ce que l'on a appris précédemment, à implémenter le 215 minimum nécessaire sur le serveur pour rendre ces commandes disponibles à 216 distance de manière non authentifiée et sécurisée. L'idée est que la 217 construction de services sous cette forme ne nécessite presque rien de plus que 218 de faire fonctionner les commandes associées en local contrairement à une appli 219 web ou même un cgi. 220 221 Si l'on reprend l'exemple 222 223 cat /tmp/f | /bin/sh -i 2>&1 | nc -l 127.0.0.1 1234 > /tmp/f 224 225 on peut modifier le filtre `/bin/sh -i 2>&1` par autre chose. Si l'on veut un 226 service qui modifie toutes les `armes` par des `fleurs` on pourra écrire : 227 228 $ cat /tmp/f | sed 's/armes/fleurs/g' | nc -l 127.0.0.1 1234 > /tmp/f[^8] 229 230 Ce qui donnera côté client 231 232 $ nc bebou.netlib.re 1234 233 Ils prirent les armes 234 235 Ah, ça ne fonctionne pas. En effet sed, comme pleins d'autres commandes pour 236 des raisons de performance, ne traite pas les lignes une à une mais en stocke 237 quelques une avant de les faire passer à la moulinette. Il constitue un 238 "buffer", on dit parfois en franglais qu'il "buffer" son entrée. Pour résoudre 239 ce problème deux solutions. Soit l'outil intègre une option pour ne pas 240 bufferiser (`--unbuffered` pour GNU sed) soit on utilise la commande `stdbuf` 241 qui dira à la commande qui lui est passée en argument qu'il ne faut rien 242 bufferiser : 243 244 $ cat /tmp/f | stdbuf -o0 sed 's/armes/fleurs/g' | nc -l 127.0.0.1 1234& > /tmp/f 245 $ nc bebou.netlib.re 1234 246 Ils prirent les armes 247 Ils prirent les fleurs 248 249 Super ! Nous en savons plus sur comment traiter les données qui arrivent dans le 250 socket du serveur mais nous n'avons toujours pas créé le système que nous 251 voulions. Pour ce faire reprenons l'exemple qui était donné dans le manuel en 252 retirant l'aspect interactif et en ajoutant stdbuf : 253 254 $ cat /tmp/f | stdbuf -o0 sh | nc -l 127.0.0.1 1234& > /tmp/f 255 $ nc bebou.netlib.re 1234 256 date 257 lun. 10 juin 2024 16:04:52 CEST 258 259 ### Avec un peu de securité 260 261 Sans pour autant récupérer un shell, nous pouvons exécuter des commandes. 262 Pour des raisons évidentes de sécurité nous voulons restreindre ces commandes à 263 celles que nous mettons à disposition, par exemple `conjuguer`. Pour cela nous 264 pouvons utiliser grep pour filtrer les entrées avant de les passer à `sh` : 265 266 $ cat /tmp/f | stdbuf -o0 grep -E '^conjuguer' | stdbuf -o0 sh | nc -l 127.0.0.1 1234& > /tmp/f 267 $ nc bebou.netlib.re 1234 268 ls 269 conjuguer manger 270 Indicatif Présent je mange 271 Indicatif Présent tu manges 272 Indicatif Présent il mange 273 Indicatif Présent nous mangeons 274 Indicatif Présent vous mangez 275 276 C'est mieux, on ne peut plus exécuter d'autres commandes que conjuguer. A moins 277 que... 278 279 $ nc bebou.netlib.re 1234 280 conjuguer;date 281 lun. 10 juin 2024 16:05:17 CEST 282 283 A mince. Le grep n'a pas retiré la ligne puisqu'elle commence bien par 284 "conjuguer". Le shell a ensuite tenté d'exécuter `conjuguer` sans argument (en 285 retournant certainement une erreur) puis a compris le point virgule comme 286 délimitant une nouvelle commande, en l'occurrence `date`, qu'il a exécuté. 287 288 Le `sh` du serveur sur lequel tout cela tourne est dash. J'ai donc consulté sont 289 manuel pour connaître les caractères spéciaux : 290 291 > Lexical Structure 292 > The shell reads input in terms of lines from a file and breaks it up into words at 293 > whitespace (blanks and tabs), and at certain sequences of characters that are special 294 > to the shell called “operators”. There are two types of operators: control operators 295 > and redirection operators (their meaning is discussed later). Following is a list of 296 > operators: 297 > 298 > Control operators: 299 > & && ( ) ; ;; | || <newline> 300 > 301 > Redirection operators: 302 > < > >| << >> <& >& <<- <> 303 304 et 305 306 > Reserved Words 307 > Reserved words are words that have special meaning to the shell and are recognized at 308 > the beginning of a line and after a control operator. The following are reserved 309 > words: 310 > 311 > ! elif fi while case 312 > else for then { } 313 > do done until if esac 314 315 Une manière un peu bourrine mais je pense, du moins j'espère, assez fiable est 316 de supprimer toutes les occurrences de ces mots et caractères. Nous aurions donc 317 à minima pour les opérateurs et autres caractères importants : 318 319 $ cat /tmp/f | 320 stdbuf -o0 tr -d '$`&(;|<>' | 321 stdbuf -o0 grep -E '^conjuguer' | 322 stdbuf -o0 sh | 323 nc -l 127.0.0.1 1234& > /tmp/f 324 325 Je n'ai pas la certitude que cela empêche toute commande dangereuse d'arriver à 326 la ligne `sh`. La bonne approche serait certainement de créer une commande 327 spéciale qui parse son entrée et sur la base de certains critères exécute 328 certaines commandes générées par nos soins plutôt que de tenter d'assainir les 329 commandes entrées par l'utilisateur·ice. En attendant le service étant utilisé 330 par très peu de personnes et la survie du serveur n'étant pas absolument 331 primordiale[^9] j'ai décidé que c'était suffisant. Je vais soumettre l'exercice 332 à des personnes motivées pour tenter de trouver des failles. 333 334 Finalement on pourra y ajouter des logs à coup de `tee` : 335 336 $ cat /tmp/f | 337 stdbuf -o0 tee prefilter.log | 338 stdbuf -o0 tr -d '$`&(;|<>' | 339 stdbuf -o0 grep -E '^conjuguer' | 340 stdbuf -o0 tee postfilter.log | 341 stdbuf -o0 sh | 342 nc -l 127.0.0.1 1234& > /tmp/f 343 344 On peut ajouter des commandes disponibles en les installant sur la machine et en 345 ajoutant des alternatives à la regex du grep : `^(conjuguer|synonyme)`. On peut 346 également maintenir un fichier des commandes autorisées, une commande par ligne, 347 et faire : 348 349 stdbuf -o0 grep -wf authorized 350 351 ## Quelques commentaires, bonus et perspectives pour rendre ça un peu sympa 352 353 ### socat 354 355 Dans les faits et pour plusieurs raisons que j'ai déjà oublié j'utilise côté 356 serveur `socat`. Les commandes vues précédemment sont les mêmes, à la suite d'un 357 `cat`, mais existent dans un script séparé qui est renseigné dans la commande 358 socat qui lance le serveur : 359 360 socat -d -d -lf /var/log/socatlog tcp-listen:2222,fork exec:script 361 362 TODO : éclaircir pourquoi j'ai finalement choisi socat. 363 En tout cas cet outil score probablement un peu moins bien dans les critères vus 364 [ici](/services-sobres/#quelle-forme-pour-ces-services-) (32k lignes par ex) 365 mais est plus polyvalent. 366 367 ### Une commande help 368 369 Une commande `help` est une bonne idée ne serait-ce que pour lister les 370 commandes dispos. Pour qu'elle s'affiche au lancement d'une session on peut 371 ajouter un 372 373 echo "help pour la liste des commandes" 374 375 au début du script. Cela à pour inconvénient d'ajouter cette ligne dans les 376 résultats de commandes lancées non interactivement. Exemple : 377 378 $ nc bebou.netlib.re 2222 379 help pour la liste des commandes 380 help 381 h[elp] 382 383 cette aide 384 385 s[ynonyme] mot 386 387 la liste des synonymes de "mot" 388 [...] 389 s table 390 tableau 14 391 répertoire 14 392 pupitre 13 393 liste 11 394 catalogue 11 395 [...] 396 397 mais si l'on passe la commande directement dans stdin (`-N` dira à nc d'envoyer 398 un caractère de fin de fichier à la fin afin de terminer la connexion et 399 récupérer la main) : 400 401 $ echo "s table" | nc -N bebou.netlib.re 2222 402 help ou h pour obtenir de l'aide 403 tableau 14 404 répertoire 14 405 pupitre 13 406 liste 11 407 catalogue 11 408 [...] 409 $ 410 411 On voit que l'on se traine l'aide. Il y a peut-être un moyen d'y remédier côté 412 serveur mais en attendant je script mes usages non interactifs de façon à 413 supprimer la première ligne de résultat. Par exemple, le script zsh que 414 j'utilise pour la conjugaison (noter le `sed '1d'` qui supprime la première 415 ligne) : 416 417 read ?"Verbe (et filtres) : " verbe 418 echo "conjuguer -c $verbe" | nc -N bebou.netlib.re 2222 | sed '1d' 419 read -k1 420 421 ### Des scripts pour un peu plus d'interactivité 422 423 En jouant avec le service de synonyme je me suis rendu compte qu'il était assez 424 naturel de vouloir sélectionner l'un des synonymes proposer pour voir ses 425 synonymes et ainsi de suite, à la manière de la navigation dans un document avec 426 des liens hypertexte. Il aurait été dommage de perdre totalement cette 427 fonctionnalité là. Pour cela j'ai opté de ne pas complexifier la commande côté 428 serveur mais de l'implémenter côté client : 429 430 read ?"Mot : " mot 431 while [ -n "$mot" ] 432 do 433 oldmot=$mot 434 echo $oldmot | cut -f1 435 mot=$(echo "synonyme $mot" | nc -N bebou.netlib.re 2222 | sed '1d' | fzy) 436 done 437 read -k1 438 439 Ce script donne ce genre de session de navigation : 440 441 Mot : table 442 table 443 > 444 tableau 14 445 répertoire 14 446 > pupitre 13 447 liste 11 448 449 Puis après sélection de pupitre : 450 451 Mot : table 452 table 453 pupitre 454 > 455 > lutrin 50 456 console 20 457 chaire 20 458 table 13 459 bureau 4 460 461 Une fois la navigation terminée on peut en sortir en appuyant sur "echap". 462 Pour les personnes initié·es voici mon menu [zenu](/zenu/) correspondant : 463 464 _conjuger 465 _synonyme 466 ## pre 467 ## react 468 ;; (c) 469 read ?"Verbe (et filtres) : " verbe 470 echo "conjuguer -c $verbe" | nc -N bebou.netlib.re 2222 | sed '1d' 471 read -k1 472 ;; (s) 473 read ?"Mot : " mot 474 while [ -n "$mot" ] 475 do 476 oldmot=$mot 477 echo $oldmot | cut -f1 478 mot=$(echo "synonyme $mot" | nc -N bebou.netlib.re 2222 | sed '1d' | fzy) 479 done 480 read -k1 481 482 ### Favoriser le local 483 484 Malgré l'existence de ces services que je compte bien continuer à maintenir je 485 maintiens ma volonté que les personnes autour de moi les installent en local. 486 Pour favoriser cela je devrais : 487 488 * En faire des paquets debian 489 * Mieux les documenter (c'est un peu le foutoir là) 490 * Publier des menus zenu directement dans les dépôts git et/ou dans les 491 paquets debian 492 * Intégrer quelque chose au service qui permette à minima de visibiliser que 493 c'est possible ? 494 495 [^1]: sur debian faire `sudo apt install netcat-openbsd` si vous ne l'avez pas déjà. En réalité tout outil permettant de se connecter à un port sur une machine distante. `socat` fonctionne, `telnet` aussi etc. 496 [^2]: article plus très à jour par rapport à ce que je fais aujourd'hui mais passons 497 [^3]: surtout quand on parle de sobriété dans le numérique, lol. 498 [^4]: en écrivant ces lignes je me rends compte qu'ils n'ont rien d'évident. Notamment celle-ci. L'intuition première est que peu de personne = projet simple et facile à maintenir, pleins de personnes = projet complexe et difficile à maintenir. Je pense que cette intuition n'est pas totalement fausse mais il faut envisager d'autres paramètres. Une personne peut, si elle est très productive, construire des logiciels qui ne sont raisonnablement maintenu par la suite que par une équipe de personne (eg Fabrice Bellard avec qemu et ffmpeg). Il est également possible qu'un outil soit créé et maintenu par une seule personne sans être pour autant documenté ou partagée. A moins que cet outil soit très simple sa maintenance posera problème. D'une certaine manière l'existence d'une équipe, et donc de plus de monde, autour d'un outil peut offrir de la résilience en cas de perte d'une personne. Ça n'est probablement qu'en combinant les variables du nombre de personnes actives pour maintenir l'outil, le nombre de personnes connaissant bien son fonctionnement et la documentation associée que l'on parviendrait à dégager un avis pertinent sur le rapport entre personnes impliquées et soutenabilité. Il faudrait également y inclure des variables économiques telles que la pérennité des financements du projet s'ils existent, la popularité des technologies utilisées etc. Bref c'est bien plus compliqué que ce que ces cinq critères de base laissent penser. 499 [^5]: un jour peut-être 500 [^6]: oui oui, si vous avez l'habitude des manuels des outils GNU ça paraît fou. 501 [^7]: je dois avouer que je n'étais pas très bon élève lors de mes études mais je n'ai pas souvenir que l'on m'ait enseigné des protocoles aussi fondamentaux qu'HTTP et SMTP en me faisant expérimenter de la sorte. Tout conservait une aura un peu mystérieuse. On m'a pourtant enseigné TCP dans les détails. 502 [^8]: évidemment la regex ne couvre pas tous les cas, c'est un exemple 503 [^9]: il ne serait pas très long de le réinstaller tel quel d'autant plus que tout est backupé