001: /**
002: * <p>
003: * Title: Connection
004: * </p>
005: *
006: * <p>
007: * Description: Represente la connection d'un client au serveur.
008: * </p>
009: *
010: * <p>
011: * Copyright: Copyright (c) 2005
012: * </p>
013: *
014: * commentaire inutile
015: *
016: * <p>
017: * Company:
018: * </p>
019: *
020: * @author Adlani Anouar - Detante Antoine - Klein Gregory - Pepin Pierre
021: * @version 1.0
022: */package httpserver;
023:
024: import java.net.*;
025: import java.util.Date;
026: import java.io.*;
027:
028: public class Connection extends Thread {
029: /**
030: * Socket du client (permet d'obtenir les flux)
031: */
032: private Socket socketClient;
033: /**
034: * Flux de sortie (permet d'envoyer des chaines au client)
035: */
036: private BufferedReader input;
037: /**
038: * Flux d'entree (permet de recevoir les chaines du client)
039: */
040: private OutputStream output;
041: /**
042: * Types mime (permet de tester les fichiers demandés)
043: */
044: private Typesmime tm;
045:
046: /**
047: * Creer une instance de Connection
048: * @param client Socket du client qui a instancié la connection
049: * (obtenu par ServerSocket.accept() dans la classe Serveur)
050: * @throws IOException Exception levee si erreur lors de l'ouverture des flux
051: */
052: public Connection(Socket client) throws IOException {
053: this .socketClient = client;
054: this .tm = new Typesmime();
055: }
056:
057: /**
058: * Creer une instance de Connection
059: * @param client Socket du client qui a instancié la connection
060: * (obtenu par ServerSocket.accept() dans la classe Serveur)
061: * @param typesMimeUtilisés une instance de la classe Typesmime pou gerer les types de fichiers
062: * @throws IOException Exception levee si erreur lors de l'ouverture des flux
063: */
064: public Connection(Socket client, Typesmime typesMimeUtilises)
065: throws IOException {
066: socketClient = client;
067: this .tm = typesMimeUtilises;
068: this .ouvreFlux();
069: }
070:
071: /**
072: * Ouvre les flux d'entree et de sortie sur le client
073: * @throws IOException levee si erreur lors de l'ouverture des flux
074: */
075: public void ouvreFlux() throws IOException {
076: input = new BufferedReader(new InputStreamReader(socketClient
077: .getInputStream()));
078: output = socketClient.getOutputStream();
079: }
080:
081: /**
082: * Ferme les flux du client
083: * @throws IOException si erreur pendant la fermeture des flux
084: */
085: public void fermerFlux() throws IOException {
086: input.close();
087: output.close();
088: socketClient.close();
089: System.out.println("[info] Deconnection du client "
090: + socketClient.getInetAddress().getHostAddress());
091: }
092:
093: /**
094: * Methode principale du thread
095: * Recoit une requete, construit la reponse et envoi la reponse au client
096: *
097: */
098: public void run() {
099: try {
100: // on recoit la requete...
101: RequeteHTTP requete = this .recoitRequete();
102: System.out.println("[info] " + requete.getClass().getName()
103: + " recue pour le fichier " + requete.getUrl());
104: // on construit la reponse a cette requete
105: ReponseHTTP reponse = this .construitReponse(requete);
106: if (reponse instanceof ReponseComplete)
107: System.out
108: .println("[info] reponse complete envoyee (code reponse "
109: + ((ReponseComplete) reponse)
110: .getEntete().getCodeNumber()
111: + ")");
112: else
113: System.out.println("[info] reponse simple envoyee");
114: // on envoi la reponse
115: this .envoiReponse(reponse);
116: // et on ferme les flux (pa de keep alive!)
117: this .fermerFlux();
118: } catch (IOException ex) {
119: // si une erreur survient...
120: System.err
121: .println("[erreur] Erreur lors du traitement de la requete");
122: ReponseComplete reponseErreur = new ReponseComplete();
123: // on envoi au client une reponse avec simplement une entete d'erreur
124: reponseErreur
125: .setEnteteReponse(EnteteReponse.reponseInternalServerError);
126: }
127: }
128:
129: /**
130: * Construit une ReponseHTTP pour la requete passee en parametre
131: * (actuellement uniquement methode GET !!)
132: * @param requete requete dont on veut creer la reponse
133: * @return ReponseHTTP en retour de la requete
134: */
135: public ReponseHTTP construitReponse(RequeteHTTP requete) {
136: ReponseHTTP reponse = null;
137: // si la methode est une methode GET : construction reponseGET
138: if (requete instanceof RequeteGET) {
139: reponse = this .construitReponseGET(requete);
140: } else {
141: //si la methode est une methode HEAD ; construction reponseHEAD
142: if (requete instanceof RequeteHEAD) {
143: reponse = this .construitReponseHEAD(requete);
144: } else {
145: //si la methode est une methode POST : construction reponsePOST
146: if (requete instanceof RequetePOST) {
147: reponse = this .construitReponsePOST(requete);
148: } else {
149: //sinon construction reponeComplete
150: reponse = new ReponseComplete();
151: ((ReponseComplete) reponse)
152: .setEnteteReponse(EnteteReponse.reponseNotImplemented);
153: }
154: }
155: }
156: return reponse;
157: }
158:
159: /**
160: * Methode qui construit une requete de reponse pour une requete client de type GET
161: * @param nomFichier String nom du fichier demandé par le client
162: * @return String reponse à envoyé au client
163: */
164: public ReponseHTTP construitReponseGET(RequeteHTTP requete) {
165: ReponseHTTP reponse = null;
166: String nomFichier = requete.getUrl();
167: // si aucune page n'est demandee dans l'url, alors
168: // on envoie la page definie par defaut dans la classe Serveur (index.html)
169: if (nomFichier.equalsIgnoreCase("")
170: || nomFichier.equalsIgnoreCase("/")) {
171: System.out.println("[info] envoi de la page par defaut ("
172: + Serveur.defaultPage + ")");
173: try {
174: EntiteText entite = EntiteText.getFromFile(Serveur.root
175: + File.separator + Serveur.defaultPage);
176: EnteteEntite enteteEntite = entite
177: .getEnteteEntite(Serveur.root + File.separator
178: + Serveur.defaultPage);
179: reponse = new ReponseComplete(EnteteReponse.reponseOK,
180: entite);
181: ((ReponseComplete) reponse)
182: .setEnteteEntite(enteteEntite);
183: } catch (IOException ex) {
184: System.out.println("[info] la page "
185: + Serveur.defaultPage + " n'existe pas !");
186: reponse = new ReponseComplete();
187: ((ReponseComplete) reponse)
188: .setEnteteReponse(EnteteReponse.reponseNotFound);
189: try {
190: reponse.setEntite(EntiteText
191: .getFromFile(Serveur.config.get404Page()));
192: } catch (Exception e) {
193:
194: }
195: }
196: } else {
197: //String param = nomFichier.substring(0,nomFichier.indexOf('?'));
198: //nomFichier = nomFichier.substring(nomFichier.indexOf('?')-1);
199: String typeMime = tm.extensionAType(tm
200: .rendreExtension(nomFichier));
201: nomFichier = tm.resourceAFichier(nomFichier);
202: nomFichier.substring(1);
203:
204: // si le type du fichier est du texte...
205: if (typeMime.startsWith("text/")) {
206: try {
207: EntiteText entite = EntiteText
208: .getFromFile(Serveur.root + File.separator
209: + nomFichier);
210: EnteteEntite enteteEntite = entite
211: .getEnteteEntite(Serveur.root
212: + File.separator
213: + Serveur.defaultPage);
214: reponse = new ReponseComplete(
215: EnteteReponse.reponseOK, entite);
216: ((ReponseComplete) reponse)
217: .setEnteteEntite(enteteEntite);
218:
219: } catch (IOException ex) {
220: System.out.println("[info] la page " + Serveur.root
221: + nomFichier + " n'existe pas");
222: reponse = new ReponseComplete();
223: ((ReponseComplete) reponse)
224: .setEnteteReponse(EnteteReponse.reponseNotFound);
225: try {
226: reponse.setEntite(EntiteText
227: .getFromFile(Serveur.config
228: .get404Page()));
229: } catch (Exception e) {
230:
231: }
232: }
233: } else {
234: if (typeMime.startsWith("image/")) {
235: try {
236: EntiteImage entite = EntiteImage
237: .getFromFile(Serveur.root + nomFichier);
238: reponse = new ReponseComplete(
239: EnteteReponse.reponseOK, entite);
240: EnteteEntite enteteEntite = entite
241: .getEnteteEntite(Serveur.root
242: + nomFichier);
243: ((ReponseComplete) reponse)
244: .setEnteteEntite(enteteEntite);
245: } catch (IOException ex) {
246: System.out.println("[info] la page "
247: + Serveur.root + nomFichier
248: + " n'existe pas");
249: reponse = new ReponseComplete();
250: ((ReponseComplete) reponse)
251: .setEnteteReponse(EnteteReponse.reponseNotFound);
252: try {
253: reponse.setEntite(EntiteText
254: .getFromFile(Serveur.config
255: .get404Page()));
256: } catch (Exception e) {
257:
258: }
259: }
260: } else {
261: if (typeMime.startsWith("application/x-httpd-php")) {
262: try {
263: //System.out.println(param);
264: EntiteText entite = EntitePHP
265: .getFromFile(Serveur.root
266: + File.separator
267: + nomFichier);
268: reponse = new ReponseComplete(
269: EnteteReponse.reponseOK, entite);
270: } catch (IOException ex) {
271: System.out.println("[info] la page "
272: + Serveur.root + nomFichier
273: + " n'existe pas");
274: reponse = new ReponseComplete();
275: ((ReponseComplete) reponse)
276: .setEnteteReponse(EnteteReponse.reponseNotFound);
277: try {
278: reponse.setEntite(EntiteText
279: .getFromFile(Serveur.config
280: .get404Page()));
281: } catch (Exception e) {
282:
283: }
284: }
285: } else {
286: // sinon on envoie juste une reponse en precisant dans l'entete que
287: // le type de fichier n'est pas encore implemente :
288: //reponse=new ReponseComplete();
289: //((ReponseComplete)reponse).setEnteteReponse(EnteteReponse.reponseNotImplemented);
290: try {
291: EntiteImage entite = EntiteImage
292: .getFromFile(Serveur.root
293: + nomFichier);
294: reponse = new ReponseComplete(
295: EnteteReponse.reponseOK, entite);
296: } catch (IOException ex) {
297: System.out.println("[info] la page "
298: + Serveur.root + nomFichier
299: + " n'existe pas");
300: reponse = new ReponseComplete();
301: ((ReponseComplete) reponse)
302: .setEnteteReponse(EnteteReponse.reponseNotFound);
303: try {
304: reponse.setEntite(EntiteText
305: .getFromFile(Serveur.config
306: .get404Page()));
307: } catch (Exception e) {
308:
309: }
310: }
311: }
312: }
313: }
314: }
315: return reponse;
316: }
317:
318: /**
319: * Methode qui construit une requete de reponse pour une requete client de type HEAD
320: * @param requete RequetteHTTP requete envoyé par le client
321: * @return String reponse à envoyer au client
322: */
323: public ReponseHTTP construitReponseHEAD(RequeteHTTP requete) {
324: ReponseHTTP reponse = null;
325: String nomFichier = requete.getUrl();
326:
327: //nomFichier = nomFichier.substring(nomFichier.indexOf('?')-1);
328: String typeMime = tm.extensionAType(tm
329: .rendreExtension(nomFichier));
330: nomFichier = tm.resourceAFichier(nomFichier);
331: nomFichier.substring(1);
332: EnteteEntite entete = new EnteteEntite();
333: // si le type du fichier est du texte...
334: entete.setContentType(typeMime);
335: if (typeMime.startsWith("application/x-httpd-php")) {
336: entete.setAllow("GET, POST, HEAD");
337: } else {
338: entete.setAllow("GET, HEAD");
339: }
340: File fichier = new File(Serveur.root + File.separator
341: + nomFichier);
342: int fileLength = 0;
343: long dateModif;
344: try {
345: fileLength = (int) fichier.length();
346: dateModif = fichier.lastModified();
347: } catch (SecurityException e) {
348: ReponseHTTP reponseErreur = new ReponseComplete();
349: ((ReponseComplete) reponseErreur)
350: .setEnteteReponse(EnteteReponse.reponseNotFound);
351: try {
352: reponse.setEntite(EntiteText.getFromFile(Serveur.config
353: .get404Page()));
354: } catch (Exception ex) {
355:
356: }
357: return reponseErreur;
358: }
359: Date date = new Date(dateModif);
360: String dateStr = new String(date.toGMTString());
361: entete.setContentLength("" + fileLength);
362: entete.setLastModified(dateStr);
363: reponse = new ReponseComplete();
364: ((ReponseComplete) reponse)
365: .setEnteteReponse(EnteteReponse.reponseOK);
366: ((ReponseComplete) reponse).setEnteteEntite(entete);
367: return reponse;
368: }
369:
370: /**
371: * Methode qui construit une requete de reponse pour une requete client de type HEAD
372: * @param requete RequetteHTTP requete envoyé par le client
373: * @return String reponse à envoyer au client
374: */
375: public ReponseHTTP construitReponsePOST(RequeteHTTP requete) {
376:
377: ReponseHTTP reponse = null;
378: String nomFichier = requete.getUrl();
379: String parm = ((RequetePOST) requete).getParam();
380: String typeMime = tm.extensionAType(tm
381: .rendreExtension(nomFichier));
382: nomFichier = tm.resourceAFichier(nomFichier);
383: nomFichier.substring(1);
384:
385: if (typeMime.startsWith("application/x-httpd-php")) {
386: try {
387: EntiteText entite = EntitePHP.getFromFile(Serveur.root
388: + File.separator + nomFichier);
389: reponse = new ReponseComplete(EnteteReponse.reponseOK,
390: entite);
391: } catch (IOException ex) {
392: System.out.println("[info] la page " + Serveur.root
393: + nomFichier + " n'existe pas");
394: reponse = new ReponseComplete();
395: ((ReponseComplete) reponse)
396: .setEnteteReponse(EnteteReponse.reponseNotFound);
397: }
398: } else {
399: reponse = new ReponseComplete();
400: ((ReponseComplete) reponse)
401: .setEnteteReponse(EnteteReponse.reponseNotImplemented);
402: }
403: return reponse;
404: }
405:
406: /**
407: * Recoit la requete envoyee par le client...
408: * @return la RequeteHTTP
409: * @throws IOException si erreur de reception
410: */
411: public RequeteHTTP recoitRequete() throws IOException {
412: StringBuffer sb = new StringBuffer();
413: String buffer;
414: // la derniere ligne de la requete doit etre une ligne vide...
415: while (!((buffer = input.readLine()).equalsIgnoreCase(""))) {
416: sb.append(buffer + " \n");
417: // on ajoute dans un StringBuffer toutes les lignes de la requete
418: }
419: // on recupere une instance de RequeteHTTP a partir d'une chaine grace a de la methode getFromString
420: RequeteHTTP requete = RequeteHTTP.getFromString(sb.toString());
421: if (requete instanceof RequeteGET) {
422: // si c'est une requete get, alors on sait que les lignes suivants la premiere
423: // constitue l'entete de la requete, on construit donc
424: // cette entete
425: EnteteEntite enteteEntite = EnteteEntite.getFromString(sb
426: .toString());
427: EnteteRequete entete = EnteteRequete.getFromString(sb
428: .toString());
429: requete.setEntete(entete);
430: }
431: return requete;
432: }
433:
434: /**
435: * Envoi la reponse passee en parametre au client
436: * @param reponse la reponse a envoyee
437: */
438: public void envoiReponse(ReponseHTTP reponse) {
439: PrintWriter poutput = new PrintWriter(output);
440: EntiteHTTP e = reponse.getEntite();
441: if (reponse instanceof ReponseComplete) {
442: // envoi de l'entete de la reponse...
443: if (((ReponseComplete) reponse).aEntete()) {
444: try {
445: ((ReponseComplete) reponse).getEntete()
446: .envoyerEntete(poutput);
447: } catch (IOException ex) {
448: System.err
449: .print("[erreur] Erreur lors de l'envoi de l'entete de la reponse : "
450: + ex.getMessage());
451: }
452: // envoi de l'entete de l'entite...
453: if (((ReponseComplete) reponse).getEnteteEntite() != null) {
454: poutput.print(((ReponseComplete) reponse)
455: .getEnteteEntite().toString());
456: }
457: }
458: poutput.println();
459: poutput.flush();
460: }
461:
462: // puis envoie de l'entite...
463: //if((e!=null)&&(e.getType().equalsIgnoreCase("text"))){
464: if ((e != null) && (e.getType().startsWith("text"))) {
465: try {
466: // avec le PrintWriter pour une entite texte
467: ((EntiteText) e).envoyerEntite(poutput);
468: } catch (IOException ex) {
469: System.err
470: .println("[erreur] Erreur lors de l'envoi de l'entite de la reponse : "
471: + ex.getMessage());
472: }
473: }
474: if ((e != null) && e.getType().equalsIgnoreCase("image")) {
475: try {
476: // avec l'OutputStream pour une entite image (ou tout entite binaire)
477: ((EntiteImage) e).envoyerEntite(output);
478: } catch (IOException ex) {
479: System.err
480: .println("[erreur] Erreur lors de l'envoi de l'entite de la reponse : "
481: + ex.getMessage());
482: }
483: }
484: try {
485: // enfin on flush les flux
486: poutput.flush();
487: output.flush();
488: } catch (IOException ex) {
489: System.err
490: .println("[erreur] Erreur lors du flush des flux");
491: }
492: poutput.close();
493: }
494: }
|