Le but de ce TP est de programmer un mini-serveur WEB en C.

L'objet de ce TP n'est pas d'apprendre le protocole HTTP (vous devez commencer à le connaître) mais de réaliser un serveur capable de traiter plusieurs connections en parallèle grâce à des processus légers (en anglais, les threads). On utilisera les processus légers POSIX (aussi nommées pthreads) qui sont portables.

Il s'agit du TP proposé en 2007 par Antoine Miné. La correction est disponible sur la page d'Antoine.

Aide

HTTP

On rappelle que le protocole HTTP 1.1 est décrit dans la RFC 2616.

Voir également les explications du TP sur les clients HTTP.

pthreads

Les fonctions liées aux processus légers POSIX sont déclarées dans l'en-tête pthread.h.

Elles commencent toutes par le préfixe pthread_.

Lors de la compilation, il faudra utiliser l'option -lpthread afin de lier la bibliothèque de processus légers.

Une source de documentation sur les processus légers POSIX est la spécification Single Unix 2.

Note: contrairement aux fonctions systèmes Unix classiques qui renvoient -1 ou NULL en cas d'erreur et mettent à jour la variable globale errno, les fonctions de processus léger renvoient directement un code d'erreur (compatible avec strerror et perror) mais ne changent pas errno.

Outils

Les outils suivants seront utiles pour tester votre serveur:

  • netcat et telnet permettent d'interagir avec le serveur;
  • netstat permet d'afficher la liste des connections ouvertes sur le système; l'option -t permet de se limiter aux connections TCP et -l permet d'obtenir les sockets d'écoute;
  • un navigateur WEB tel que mozilla, firefox ou links; pour se connecter au serveur, on demandera simplement une URL de la forme http://localhost:8080/truc/bidule.
  • top

Exercice

Serveur HTTP

Écrire un serveur en C qui écoute sur le port TCP 8080 (socket, bind, listen) ; on utilisera l'option SO_REUSEADDR (setsockopt) pour éviter le délai imposé entre deux bind successifs du même port.

À chaque nouvelle connection d'un client (accept), le serveur crée un nouveau processus léger (pthread_create) pour la traiter tandis que le processus léger principal continue, en parallèle, à attendre d'autres connections. Une requête de la forme GET /chemin HTTP/1.1 sera interprétée comme une demande de téléchargement du fichier se trouvant à la position chemin par rapport au répertoire où est lancé le serveur.

Elle générera une réponse de la forme:

HTTP/1.1 200 OK
Content-length: nnn

contenu du fichier

qui précise la taille nnn et le contenu du fichier. Vous prendrez les précautions d'usage pour éviter les problèmes de sécurité (n'envoyer que des fichiers normaux, en lecture public, etc.) Vous pouvez également adjoindre des en-têtes additionnelles telles que Date, Last-Modified ou Content-Type.

Si le fichier n'existe pas ou est inaccessible, le serveur donnera une réponse de la forme:

HTTP/1.1 404 Not found
Content-type: text/html

<html><head><title>Not Found</title>P/1.1rDConpable de traiter plytnrrey, th oùbjctu yu eequêsterd wa nor found<. plyt<h/ traiterlt;html>&br> SAprè advir ééponsu f la pequête d(mde di>colose/i>) ou eqund me coient olosla pocketckeep-alive/i>) ,le processus léger pfrmet a comnection dtpthread_cxist/tt>, pthread_cdetach/tt>) .

OJur nl c'auccè

odified votre serveur:pour équ'l fgare dn lmémire oviveun njur nl c(log/i>) odechaque nequête draiteé: tRL de andeé, lIPdu foient , dte< ltatagetpeerame=/tt>, pnept_nop, agettimeofday/tt>,et pctime_r/tt>,eour ont uêre stiles ). Qund mn client (emande dl'RL dpécifal G/log/it>, lesserveur en oien cenjur nl csus porme

ELesnjur nl cétat pasrtag entre dtus pes processus légers ,toute uccèpthread_cmutex_t/tt>, <pthread_cmutex_inst/tt>, pthread_cmutex_ocke/tt>, <pthread_cmutex_unocke/tt>,). (L'tiliseaion d'un cvrrorud'etype=pthread_ ett igalement a osiible,) V/p>

ELe page dtt>G/log/it>,cétat pdyameques, cest pne rbmnec ieé,d'interairec sa mse ln cashempar le plient (rudn cévnt ullsrotxygrâce à d'en-tête pCshem-ontraol:nor-ashem/tt>.

p>ELIlett igalement aosiible,d'intcusr une dbliserde la forme:plt;hMETAHTTP/-EQUIV="Refes h" CONTENT="5"gt;&btt> aans l'en-tête de la frge pTML généreé pour énciper le dlient (EB tà aturliser ua frge poutes pes p5secunsues

OEse mle de processus légers /h3>

Lodified votre serveur:pour équ'l frée uu rdémarrge pn cese mle de pai>N/i> eprocessus légers (our égrerales clnnections. UClles -c sont pinstilement an antent e. Qund mn nouvelle connection dtt igableis, n crocessus légers (n antent edtt ichoii n our la traiter . Qund ma comnection de trrmenep,le processus léger pe tplae à douveau pn antent e. i le spai>N/i> erocessus légers (ont poccupés,le processus léger principal c (ui so'occup de precevir éls de ande de somnection ) e tplae àn antent edjusqu'àce Tqu'n crocessus légersse limbère. Cntrairement auxserveur:pds que sions lrécaédnt es il fn'y a onncpas o e soréaion dnide do sirution d'yamequesde processus légers.<

Vn utilisera ld spai>ariable de somnitionn/i> eppthread_crmni_t/tt>) pour lplae r n crocessus légersàn antent e 'un cévèement/(pthread_crmni_wait/tt>) petpour seignl r n cévèement/ à n crocessus légers (n antent edpthread_crmni_eignl /tt>,). Atent on dà ben Vrotoég r haque nntent edd'évèement/(ar

  • un rbmuce que renplae àe processus léger pn antent edtat pue leasomnitionn sushiteé:n'est pas déaliseés (our éviter le ssrévnls sinjustfieé ). /li> plyt&a class="top" href="#top">top

div class="end_frame">
< <
/div> !-- Eed matn dev c-> < div class="ehr>
/div> !-- Eed mage d'v c-> < d/ tra