|
Définition du Proxy (extrait de l'énoncé)
L'objectif de ce projet est d'écrire un relais
(proxy) filtrant HTTP/1.1 concurrent.
A propos...
Le projet Le projet a été réalisé par Patrice Lamarque dans le cadre d'un projet de maîtrise à l'UMLV. Ce programme est un proxy HTTP/1.1 entièrement écrit en java. Il utilise Java 2 et a été écrit à l'aide du JDK 1.3 de Sun. Il a été développé partiellement en environnement Unix et partiellement en environnement Windows. Le programme a été testé (avec plus ou moins de succès) sur les navigateurs Internet Explorer (v5.01 et v5.5), Netscape Navigator (v4.71) et Mozilla (v0.9).
Archive L'archive fournie est au format tar.gz. La racine de l'archive contient ce fichier (rapport.html) ainsi que 3 répertoires :
Fonctionnalités
Dans l'énoncé du projet, il est spécifié que certaines fonctionnalités sont à implémenter en priorité et que certaines sont optionnelles. La plupart des fonctionnalités de base ont été implémentées et validées, certaines par contre on été implémentées mais ne disposent pas de la fiabilité nécessaire, enfin certaines n'ont pas du tout été implémentées.
Fonctionnalités non validées
La gestion des flux est d'une importance critique dans une application réseau comme celle-ci. Le langage java fournit une API riche pour la gestion des flux, permettant de manipuler des objets de haut niveau. Cependant, cette dernière est complexe et manque de performance.
J'ai décomposé la gestion des flux pour le Proxy en 3 parties : les flux entrants, les flux sortants et les entêtes HTTP.
La classe HTTPHeader
dérive de la classe Header. Cette
dernière permet de lire sur un flux, des lignes contenant des paires
clé-valeur. En interne, elle est implémentée par
une table de hachages ce qui permet de fournir des méthodes simples
de manipulation et de lecture.
La classe HTTPInputStream
hérite de la classe DataInputStream qui vient avec le JDK. Les flux Sortant (HTTPOutputStream) La classe HTTPOutputStream
hérite de la classe DataOutputStream
qui vient avec le JDK.
Second point critique, la gestion des connexions sur un Proxy va déterminer ses performances. Un proxy concurrent doit être capable de supporter une charge importante de connexions clientes et serveur simultanées. Pour faire face à une telle problématique, Java met à notre disposition les processus légers (Threads). J'ai distingué et implémenté différemment la gestion des connexions serveur et la gestion des connexions client.
Le système implémenté fait appel à 3 classes : RestartableThread, Connection et ConnectionPool
Les Connections seront stockées dans un état
inactif dans un pool (voir ci-dessous) qui devra les réactiver
à la demande. Pour simuler ce phénomène, la classe
Connection hérite de la classe RestartableThread.
Il s'agit d'une classe héritant elle-même de la classe Thread. Ici, la méthode run()
a été écrite pour exécuter une méthode
doRun() (qui doit être écrite dans
les sous-classes) puis arrêter le processus léger à
l'aide d'un moniteur. Ainsi Le code que doit exécuter un objet RestartableThread doit se trouver dans la méthode doRun(). L'arrêt est automatique après exécution de ce code. Il faut appeler explicitement la méthode start() pour que le estartableThreadsoit réactivé.
Les connexions client (Connection) La classe Connection représente une connexion client, c'est à dire une connexion réalisée par le User-Agent vers le proxy à destination d'un serveur. Elle hérite de RestartableThread et redéfini donc la méthode doRun(). C'est dans cette méthode que devront être définis tous les services du proxy (filtrage, authentification, cache, etc ). Une Connection dispose
d'un flux entrant et d'un flux sortant pour gérer respectivement
la requête et la réponse HTTP.
Le pool de connexions client (ConnectionPool) Afin d'éviter de créer de nouveaux processus à chaque connexion, il faut un mécanisme permettant de garder une réserve de connexions déjà allouées et prêtes à l'emploi. La classe ConnectionPool offre un tel mécanisme. Définie selon les spécifications de l'énoncé, elle gère à l'aide de deux Vector l'ensemble des connexions libres et utilisées sur le serveur. Le nombre de connexions est borné par les valeurs MAX_THREAD et MIN_THREAD.
Ces quatres valeurs sont configurables au sein du fichier de configuration général du proxy.
Gestion des connexions serveur Le système fait appel à deux classes ServConnection et ServConnectionManager. Les connexions serveur (ServConnection) La classe ServConnection englobe les flux de lecture et d'écriture sur les serveur. Elle garde trace du temps d'inactivité de la connexion afin de permettre au gestionnaire de connexions serveur d'éliminer les connexions trop anciennes.
La classe ServConnectionManager, n'est pas à proprement parler un pool de connexion comme celui des connexions client. Il s'agit en fait d'un gestionnaire permettant de maintenir des connexions serveur pendant un temps limité. Ces connexions ne seront pas gardées indéfiniment mais pendant une durée définie par la valeur KEEP_ALIVE_TIME. Une thread se charge de supprimer les connexions serveur trop anciennes.
Ecoute sur plusieurs ports Le lanceur (ProxyLauncher) a la responsabilité de charger la configuration et configurer le proxy. Parmi les directives du fichier de configuration on trouve LISTENING_PORTS dans la section PORTS. Une liste de numéros ports (séparés par des blancs) doit être fournie comme valeur.
L'énoncé spécifie que l'on doit pouvoir interdire à des machines clientes le service du proxy, tout comme l'on souhaite interdire l'accès à certains serveurs HTTP. Cette fonctionnalité est réalisée à l'aide de la classe Policy. Un objet Policy correspond à un ensemble de règles d'acceptation ou de refus de service. Ces règles sont définies dans des fichiers dont le nom est configurable dans le fichier de configuration central. Un exemple de règles est par exemple :
La politique de filtrage est interrogée à
partir de la méthode accept() qui effectue
la vérification. Configuration En interne la configuration est stockée sous
la forme d'une table de hachages dont les clés sont les noms des
sections et les valeurs des objets Properties.
Cet objet Properties contient lui les différentes
paires clé-valeur de la section.
La journalisation est assurée par la classe Logger. Celle-ci permet de journaliser dans deux fichiers séparés, les accès et les erreurs et/ou messages du proxy.
Les messages sont journalisés sous la forme :[TYPE] [DATE] [MESSAGE]. Trois types de messages on été définis : MESSAGE, WARNING, ERROR. Exemple de log de message:
Gestion du Keep-Alive La gestion du Keep-Alive a posé et pose toujours
de nombreux problèmes.
|