% Introduction au HTTP
% Sylvain Eliade — S.C.O.P. Cadoles
% Mai 2019
## Introduction au HTTP
* HyperText Transport Protocol
* Protocole texte
* Client-serveur
* En général sur TCP, port 80
* Stateless, aucun état n'est conservé entre les requêtes
* Très simple
* Requêtes **toujours** initiées par le client
---
## À quoi ça ressemble ?
Un simple `telnet` permet de faire des requêtes HTTP !
```
% telnet sylvain.eliade.net 80
Trying 91.121.181.110...
Connected to eliade.net.
Escape character is '^]'.
GET /resume/ HTTP/1.1
Host: sylvain.eliade.net
```
---
Le serveur nous répond :
```
HTTP/1.1 200 OK
Date: Mon, 13 May 2019 10:02:02 GMT
Server: Apache
Last-Modified: Fri, 19 Apr 2019 07:36:32 GMT
ETag: "2abb-586dd2d7c21de"
Accept-Ranges: bytes
Content-Length: 10939
Vary: Accept-Encoding
Content-Type: text/html
Connection: close
…
```
---
Un outil plus pratique est quand même `curl` !
```
% curl -v http://sylvain.eliade.net/resume/
```
---
## Structure d'une requête
Première ligne : `MÉTHODE RESSOURCE PROTOCOLE`
* Méthode (ou verbe) HTTP = action que l'on souhaite utiliser (`GET`, `DELETE`, `POST`, etc.)
* Ressource sur laquelle on souhaite effectuer l'action
* Version du protocole : `HTTP/1.0` ou `HTTP/1.1` (il existe encore des clients HTTP/0.9 mais bon…)
Lignes suivantes : les entêtes. Puis : une ligne vide.
Puis éventuellement (méthodes `POST`, `PUT`, `PATCH`, etc.) : corps (contenu) de la requête.
---
### Méthodes HTTP
* GET : la plus courante, renvoie la ressource demandée (exemple : visualiser une page web)
* POST : envoyer des données liées à la ressource (exemple : envoyer un formulaire web)
Les méthodes suivantes sont rarements utilisées par les navigateurs mais souvent dans les API :
* HEAD : obtenir des infos sur la ressource. En pratique c'est souvent pareil que GET, mais ça ne renvoie que les entêtes et pas le corps.
* PUT : ajouter / remplacer une ressource
* OPTIONS : savoir quelles sont les méthodes supportées par le serveur pour une ressource
---
## Structure d'une réponse
Première ligne : `PROTOCOLE CODE MESSAGE`
* Code = code de réponse du serveur (200 = OK, 404 = Not Found, etc.)
* Message = message de réponse associé au code
Lignes suivantes : les entêtes de réponse.
Puis : une ligne vide.
Puis éventuellement (tout le temps sauf avec requête `HEAD`) : corps de la réponse.
---
### Codes de réponses HTTP
Le premier chiffre indique le type de code :
* 1xx = requête reçue mais son exécution n'est pas terminée
* 2xx = succès
* 3xx = redirection
* 4xx = erreur du client
* 5xx = erreur du serveur
---
### Codes courants
* 200 OK = la plus courante
* 301 Moved Permanently = ressource déplacée définitivement (voir l'entête `Location` pour la nouvelle adresse)
* 302 Found = ressource déplacée temporairement
* 400 Bad Request = erreur dans la requête du client
* 401 Unauthorized = le client n'a pas accès, il lui faut s'authentifier
* 403 Forbidden = accès refusé (par exemple mauvais login/mot de passe)
* 404 Not Found = ressource non trouvée
* 500 Internal Server Error
* 503 Service Unavailable = serveur surchargé
---
## Entêtes
```
Host: sylvain.eliade.net
User-Agent: telnet/1.0
```
Chaque entête est une clé (en général avec une majuscule au début de chaque mot, les mots étant séparés par des tirets), suivi de deux points `:`, d'un espace et de la valeur de l'entête.
Liste des entêtes : [https://en.wikipedia.org/wiki/List_of_HTTP_header_fields](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields)
---
### Entêtes courants pour les requêtes
* `Host` : pour indiquer le nom de domaine que l'on essaye d'atteindre (car le serveur HTTP ne sais pas quelle requête DNS on a fait pour le contacter)
* `Accept-Language` : indique les langues préférées du client (`fr-BE, fr, en-AU, en`)
* `Accept` : les formats de fichier gérés par le client (`text/html, image/jpeg…`)
* `Connection` : pour garder la connexion TCP ouverte pour faire plusieurs requêtes de suite
* `User-Agent` : nom du client utilisé
* `Cookie` : contenu d'un cookie
* `Authorization` : identifiants de connexion HTTP (accès par mot de passe)
---
### Entêtes courants pour les réponses
* `Connection` : état de la connexion TCP
* `Date` : date de réponse
* `Content-Type` : type du contenu (`text/html; charset=utf-8`)
* `Location` : nouvelle adresse du contenu quand il a changé d'adresse
* `Server` : nom du serveur
* `Set-Cookie` : le client doit enregistrer ce cookie
* `WWW-Authenticate` : demande d'authentification
---
## Aparté : les URLs
Uniform Resource Locator (interchangeable avec URI, Uniform Resource Identifier)
`protocol://[user[:password]@]host[:port]path[?query][#fragment]`
Entre crochets les parties facultatives.
---
* protocol : http ou https
* user[:password] : nom d'utilisateur (et éventuellement mot de passe), pour l'authentification HTTP
* host : nom de domaine (ou adresse IP, pour une IPv6 elle doit être entre crochets, exemple : `http://[::1]/page`)
* port : numéro de port optionnel
* path : chemin de la ressource
* query (ou query string) : liste de clés et valeurs, séparées par des `&`
* fragment : identifiant d'une sous-ressource à l'intérieur de la ressource (en pratique, utilisé pour se rendre à une point particulier de la page web, ou en javascript)
---
`https://catalogue.cesi.fr/recherche/?domaine=informatique&niveau=bac4#type`
* protocol: `https`
* host: `catalogue.cesi.fr`
* path: `/recherche/`
* query: `domaine=informatique&niveau=bac4`
* fragment: `type`
---
## Les serveurs HTTP les plus courants
* Apache (29% des serveurs)
* nginx (29%) : plus rapide qu'Apache sur les fichiers statiques, même performance sur le contenu dynamique (PHP)
* Microsoft IIS (19%)
Apache est le plus courant, historiquement le plus utilisé, mais on trouve de plus en plus du nginx aussi. La configuration de nginx est un peu plus lisible que celle d'Apache.
---
## Apache et ses MPM
Apache possède plusieurs MPM (multi-processing module) qui ont des comportements différents :
* prefork : moins performant (sans threads), chaque processus ne peut traiter qu'une seule requête à la fois
* worker ou event : plus performant, chaque processus a plusieurs threads, et peut donc traiter plusieurs requêtes à la fois
Quel MPM choisir ? En production on utilisera *worker* ou *event*, car plus rapides, mais pour tester des trucs rapidement avec PHP on peut utiliser *prefork* qui est plus simple à metter en place.
---
## Un mot sur l'utilisateur www-data
Par défaut Apache est lancé avec l'utilisateur `www-data`. Ça va si on n'a qu'un seul site hébergé sur la machine.
Si on veut héberger plusieurs sites, il vaut mieux pouvoir avoir un utilisateur par site, pour pas qu'un site puisse aller modifier les fichiers d'un autre site.
Pour cela une version de *prefork* appelée **ITK** (`apt install libapache2-mpm-itk`) permet d'avoir des processus Apache qui se lancent avec les droits d'utilisateurs différents.
---
## Installation Apache sous Debian
* Installer le serveur : `apt install apache2`
* Statut du serveur : `apache2ctl status` (permet de voir les requêtes traitées en ce moment, le nombre de *workers* etc.)
* Tester si la config n'a pas d'erreur : `apache2ctl configtest`
* Recharger la configuration après modification : `apache2ctl graceful`
---
## Gérer les modules Apache sous Debian
* Activer un module : `a2enmod NOM_DU_MODULE` (exemple : `a2enmod rewrite`)
* L'outil préviendra s'il y a un conflit entre deux modules incompatibles :)
* Désactiver : `a2dismod NOM_DU_MODULE`
* Même chose pour les MPM : `a2dismod mpm_prefork` puis `a2enmod mpm_worker`
Astuce : lancer `a2enmod` sans argument liste les modules disponibles.
La configuration du module est dans le fichier `/etc/apache2/mods-available/NOM_DU_MODULE.conf`
---
## Configuration Apache
Syntaxe simple. Ce n'est pas du XML !
```
Listen 80
KeepAlive Off # Ne pas autoriser les connexions persistantes
Require all granted
Options -Indexes
```
---
## VirtualHost
Apache permet d'héberger plusieurs sites sur le même serveur avec des hôtes virtuels. L'hôte est reconnu avec l'entête "Host". Pour cela on utilise des hôtes virtuels.
```
ServerName cadoles.com
DocumentRoot /var/www/monsite
ServerName mail.cadoles.com
DocumentRoot /var/www/roundcube
```
Le premier vhost de la liste sera utilisé comme vhost "par défaut" si aucun vhost n'est trouvé pour l'hôte demandé.
---
### VirtualHost dans Debian/Ubuntu
Les vhost disponibles sont séparés par fichiers dans `/etc/apache2/sites-available`, triés par ordre alpha-numérique.
Ensuite : `a2ensite nomduvhost` pour activer, ou `a2dissite nomduvhost` pour désactiver.
Ne pas oublier de tester la config et recharger ensuite !
Astuce : lancer `a2ensite` ou `a2dissite` sans argument liste les sites disponibles.
---
## Fichiers .htaccess
Apache permet de configurer des options pour un répertoire donné à l'aide d'un fichier `.htaccess` (en UNIX, les fichiers avec un point au début sont des fichiers "cachés").
C'est pratique, mais attention, cela veut dire qu'Apache sera beaucoup plus lent, car il va chercher ce fichier dans tous les sous-répertoires à chaque requête !
Donc il est recommandé de désactiver ce comportement par défaut, et de ne l'activer que pour les sites qui en ont besoin. Tant que possible il vaut mieux mettre toute la configuration dans les fichiers de configuration Apache du vhost.
---
```
AllowOverride None
AllowOverride All
```
[AllowOverride](https://httpd.apache.org/docs/2.4/mod/core.html#allowoverride) permet de configurer le type de directive autorisée dans le fichier `.htaccess`.
None = aucune directive autorisée = Apache ne va même pas lire les fichier `.htaccess`
---
## Restriction d'accès
Un exemple courant de `.htaccess` est la restriction d'accès par mot de passe. Pour cela il faut dire à Apache de n'autoriser que les utilisateurs connectés avec `Require valid-user` :
```
Require valid-user
AuthType basic
AuthName "Accès restreint"
AuthUserFile /var/www/monsite/secret/.htpasswd
```
---
### Fichier htpasswd
Pour créer le fichier `.htpasswd` qui contiendra la liste de nos utilisateurs autorisés et leurs mots de passe nous devons utiliser l'outil `htpasswd`.
A installer avec `apt install apache2-utils`.
---
* Créer le fichier avec `htpasswd -c /var/www/monsite/secret/.htpasswd NOM_UTILISATEUR` (`-c` comme **Création** du fichier)
* L'outil demande de taper, puis re-taper le mot de passe
* Pour ajouter un utilisateur ou modifier son mot de passe, simplement : `htpasswd /var/www/monsite/secret/.htpasswd NOM_UTILISATEUR` (sans le `-c` donc)
```
sylvain:$apr1$vfxnPOnt$gI7MkAizYirxT/CrUfCqU0
```
---
## Exercice 1
Faire une requête avec `curl` sur `http://www.cesi.fr/`. Quel est le code HTTP retourné ? Quel est le serveur web utilisé ?
---
## Exercice 2
Installation de Apache2. Faire une requête sur `http://localhost/` pour voir si ça fonctionne.
Puis essayer d'accéder à l'IP de la VM depuis un navigateur de la machine hôte pour voir si ça fonctionne bien.
(Pour obtenir l'IP : `ip addr` depuis la console)
---
## Exercice 3
Prérequis : créer un répertoire `/var/www/cesi.test` et un fichier `/var/www/cesi.test/index.html` avec :
```
mkdir /var/www/cesi.test
echo "Hello monde !" > /var/www/cesi.test/index.html
```
Exercice : Mettre en place un VirtualHost `cesi.test` proprement, l'activer.
Pour vérifier son fonctionnement, ajouter la ligne suivante dans `/etc/hosts` : `127.0.0.1 cesi.test`. Puis faire `curl http://cesi.test/`, le message "Hello monde" devrait apparaître.
---
## Exercice 4
Prérequis : créer un répertoire `/var/www/cesi.test/secret` : `mkdir /var/www/cesi.test/secret`
Désactiver les vhosts existants, sauf celui de `cesi.test`. Recharger apache.
Mettre en place une protection par mot de passe du répertoire `/var/www/cesi.test/secret` avec un fichier `.htaccess`.
Vérifier que ça marche correctement en utilisant le navigateur de la machine hôte sur l'IP de la VM.
---
## Exercice 5 (facultatif)
Tester la charge du serveur avec ApacheBench :
* installer `ab` : `apt install apache2-utils`
* dans une première console, lancer `watch -d -n 0.1 sudo apache2ctl status`
* lancer dans une seconde console `ab -n 5000 -c 100 http://localhost/` (va lancer 5000 requêtes, par vagues de 100 en même temps)
* observer l'évolution du nombre de workers, et de la charger serveur (*Server load*)
---
## Exercice 6 (facultatif)
Changer de MPM, passer de *prefork* (celui utilisé par défaut normalement) à *event*.
Répéter le test de l'exercice 5 et observer les différences.
---
## Exercice 7 (facultatif)
On nous demande de faire de la réécriture d'adresse.
Faire en sorte que `http://cesi.test/etu` redirige vers `http://localhost/infos-etudiant` en utilisant la directive `Redirect` dans le vhost créé précédemment (voir la [documentation de Redirect](https://httpd.apache.org/docs/2.4/mod/mod_alias.html#redirect) pour un exemple).
Pour cela il faudra activer le module `alias`.
Il est courant d'utiliser `RewriteRule` pour faire cela (module `rewrite`), mais il est plus lent et complexe ([Documentation](https://httpd.apache.org/docs/2.4/rewrite/intro.html)), mais permet plus de possibilités.
---
## Exercice 8 (facultatif)
Installer `nginx` et créer un virtualhost `cesi.test`.
Un exemple de configuration de virtualhost est dispo dans `/etc/nginx/sites-available/default`.
Pour créer le vhost, créer un fichier `/etc/nginx/sites-available/cesi.test`.
Pour l'activer exécuter `ln -s /etc/nginx/sites-available/cesi.test /etc/nginx/sites-enabled/cesi.test`, cela va créer un lien symbolique (pas de commande comme avec Apache type `a2ensite`).
Puis `nginx -t` pour vérifier la configuration et `service nginx reload` pour recharger.