DOC

JAVA - TP 2

By Alvin Knight,2014-04-24 14:24
12 views 0
JAVA - TP 2

Exercice Serveur HTTP Multi-Thread

Objectif du TP

    L'objectif de ce TP est d'écrire un serveur HTTP multi-thread. Pour cela, vous devez :

     - suivre la décomposition proposée ;

     - implémenter les classes demandées ;

     - mettre des commentaires pour la génération de la documentation avec javadoc ;

     - utiliser un makefile pour compiler, générer la documentation et lancer le serveur.

Vous placerez l'ensemble de vos classes dans un package httpd.

    A travers ce TP, vous allez mettre en oeuvre différentes classes des packages :

     - java.lang

     - java.util

     - java.io

     - java.net

1. Structure générale du serveur

Le programme se composera pour l'instant de deux classes :

    - httpd.Main : la classe contenant la méthode main(). Cette classe sert à lire le fichier de

    configuration et à demarrer le serveur.

    - httpd.Httpd : la classe qui implémente le serveur HTTP.

Le serveur se lance par :

    java httpd.Main config

1.1 Configuration du serveur

    L'ensemble des paramètres de configuration du serveur est contenu dans un fichier texte qui est passé en paramètre au programme. Pour lire et exploiter le contenu de ce fichier, on utilisera la classe java.util.Properties (voir la méthode load()). Ce fichier contiendra, entre autre, le numéro du port d'écoute du serveur (champs Port) et le répertoire racine des documents web (champs WebRoot).

    Exemple de fichier : # Numero de port du serveur

    Port=8080

# Repertoire racine des documents web

WebRoot=www

1.2 Boucle de traitement des requêtes

    Le protocole HTTP est un protocole sans état basé sur TCP. L'algorithme du serveur est le suivant :

Ouvrir une socket sur le port indiqué

    Boucle infinie

     Attendre une requête

     Récupérer la socket de travail

     Lire le contenu de la requête

     Analyser la requête

     Construire la réponse adaptée

     Renvoyer la réponse

     Fermer la socket

    Fin de boucle

    Pour ouvrir la socket d'écoute du serveur, on utilisera la classe java.net.ServerSocket. L'attente de requête se fait par la méthode accept() qui retourne à chaque nouvelle requête une socket de travail (instance de la classe java.net.Socket). Pour récupérer le contenu de cette socket, il suffit de lire sur le flux retourné par getInputStream().

1.3 Traitement d'une requête

    Pour l'instant, le serveur ne traitera que les requêtes GET. Ces requêtes sont de la forme : GET /ressource HTTP/1.0\n\n

Exemple de requête :

    GET /rep1/index.html HTTP/1.0\n\n

    Cette requête demande à obtenir le fichier index.html situé dans le répertoire rep1, lui même situé dans le répertoire racine des documents Web. Le serveur lit la requête (classe java.io.DataInputStream méthode readLine()), l'analyse (classe java.util.StringTokenizer) et renvoit une réponse (classe java.io.PrintStream) de la forme :

    Header\n

    \n

    Body

    La partie Header se compose de plusieurs champs contenant des informations utiles pour le programme client (statut de la réponse, date, nom du serveur, type du document retourné, ...) La partie Body contient soit le document si la requête a pu être correctement traité, soit un message d'erreur pour l'utilisateur.

    Si la ressource est accessible, la réponse renvoyée est de la forme :

    HTTP/1.0 200 OK

    Date: Wed, 22 Oct 1997 21:49:50 GMT

    Server: JavaHttp/1.0

    Content-type: text/html

Le contenu du fichier ...

Si la requête est mal formée, la réponse renvoyée est de la forme :

    HTTP/1.0 400 Bad Request

    Date: Wed, 22 Oct 1997 21:39:48 GMT

Server: JavaHttpd/1.0

    Content-type: text/html

<HEAD><TITLE>Mauvaise requête</TITLE></HEAD>

    <BODY><H1>Mauvaise requête</H1>

    Votre browser a envoyé une requête que ce serveur ne peut pas traiter.<P>

    </BODY>

    Si la requête est bien formée, le serveur vérifie que la ressource est bien accessible à partir du répertoire racine précisé dans le fichier de configuration (champs WebRoot). Si ce n'est pas le cas, la réponse renvoyée est de la forme :

    HTTP/1.0 404 Not found

    Date: Wed, 22 Oct 1997 21:41:59 GMT

    Server: JavaHttpd/1.0

    Content-type: text/html

<HEAD><TITLE>Fichier non trouvé</TITLE></HEAD>

    <BODY><H1>Fichier non trouvé</H1>

    La ressource /rep1/une_ressource n'est pas présente sur ce serveur.<P>

    </BODY>

2. Typage des ressources

    Dans cette première version du serveur, on suppose que les documents renvoyés sont tous du type HTML (ce qui est indiqué dans les headers des réponses par Content-type: text/html). Or les documents peuvent être de nature variée (images GIF, JPEG, texte non formaté, vidéo AVI, ...). C'est au serveur HTTP d'indiquer le type du document renvoyé. Pour cela, il se base sur l'extension du nom du fichier pour établir le mime type correspondant. Les mime types sont des chaînes de caractères de la forme :

    type/sous-type

Exemples : Mime typeType

     text/htmlFichier HTML

     text/plainFichier texte

     image/gifImage GIF

     image/jpegImage JPEG

    Modifiez le serveur pour qu'il effectue le typage des ressources. Pour cela, on utilisera le fichier mimetypes (lisible comme le fichier de configuration par java.io.Properties.load()) contenant la liste des extensions possibles et les mime type associés. Le nom de ce fichier sera indiqué dans le fichier de configuration (champ MimeTypeFile). Si l'extension du fichier demandé n'est pas connue, le serveur renverra un mime type par défaut (e.g.: text/plain) indiqué dans le fichier de configuration (champ DefaultMimeType).

3. Traitement multi-thread

    Actuellement, le serveur ne peut traiter qu'une requête à la fois. Pour pourvoir traiter plusieurs requêtes simultanément, nous allons créer des objets capables de prendre en charge les requêtes et qui s'exécuteront dans différentes threads . Ces objets seront des instances d'une nouvelle classe : httpd.HttpConnection. Pour que ces instances soient threadables, cette classe doit implémenter l'interface java.lang.Runnable. Une grande partie du code de la classe Httpd sera délocalisée dans cette nouvelle classes (au sein de la méthode run()). La boucle de traitement des requêtes (située dans la classe Httpd) devient alors :

Ouvrir une socket sur le port indiqué

    Boucle infinie

     Attendre une requête

     Récuperer la socket de travail

     Créer une instance de HttpConnection avec en parametre la socket et la configuration Fin de boucle

    La méthode run() de la classe HttpConnection contient le reste du traitement : Lire le contenu de la requête

    Analyser la requête

    Construire la réponse adaptée

    Renvoyer la réponse

    Fermer la socket

4. Journalisation des accés

    On souhaite pouvoir suivre l'ensemble des requêtes auxquelles répond notre serveur. Pour cela, on enregistre chaque requête traitée dans un fichier de journalisation. Les enregistrements sont de la forme :

    [adresse IP du client] [date] [requête] [statut de la reponse]

Exemple :

    [127.0.0.1] [Sat Mar 08 14:51:47] [GET /icons/dir.gif HTTP/1.0] [200]

    [128.93.7.60] [Sat Mar 08 14:53:44] [GET /docs/index.html HTTP/1.0] [404]

Ecrivez une classe httpd.HttpLog de la forme :

    package httpd;

class HttpLog {

     HttpLog(String logFile) {...}

     add(String address, String request, int status) {...}

    }

    Cette classe sera instanciée avant le démarrage du serveur (dans la classe Httpd) avec le nom du fichier de journalisation (indiqué dans le fichier de configuration dans le champ LogFile) et sera fournie à chaque instance de HttpConnection pour qu'elles puissent y ajouter leur requête une fois celle-ci traitée.

    Remarque : le serveur étant multi-thread, assurez vous que l'ajout d'une entrée (méthode add) soit exclusif.

5. Gestion des répertoires

    5.1 Renvoi d'un fichier d'index

    Lorsqu'une requête demande une ressource correspondant à un répertoire, il est devenu conventionnel de renvoyé, s'il est présent, un fichier particulier (traditionnellement nommé index.html).

    Par exemple la requête :

    GET /rep1 HTTP/1.0\n\n renverra le fichier index.html contenu dans le répertoire rep1.

    Modifier la classe HttpConnection pour prendre en compte cette fonctionnalité (le nom du fichier d'index sera indiqué dans le fichier de configuration dans le champ DirectoryIndex). Pour tester si une ressource est un répertoire, utilisez la méthode isDirectory() de la classe java.io.File.

5.2 Renvoi du contenu du répertoire

    Il est aussi devenu traditionnel que si ce fichier d'index n'existe pas on retourne une page HTML représentant le contenu du répertoire. Cette page indique généralement la nature des fichiers (au moyen d'une icône), le nom du fichier (avec un lien pour y accéder) et diverses informations (taille du fichier, date, ...). Modifiez la classe HttpConnection pour prendre en compte cette fonctionnalité. Exemple de page représentant le contenu d'un répertoire :

Contenu du répertoire /home/deruelle/java/classes/httpd

     Répertoire parent

     HttpConnec... 3 Kb Wed Oct 22 23:19:02 1997

     Httpd.class 1 Kb Sat Mar 8 14:51:43 1997

     Httpd.java 1 Kb Sat Mar 8 14:46:37 1997

     www/ 1 Kb Wed Oct 22 22:34:13 1997 Directory

     config 52 bytes Wed Oct 22 22:31:03 1997

     logs 501 bytes Wed Oct 22 22:35:09 1997

     mimetypes 2 Kb Sat Mar 8 13:23:21 1997

     sujet.html 8 Kb Sun Oct 26 17:01:15 1997 Hypertext Markup Language

Report this document

For any questions or suggestions please email
cust-service@docsford.com