summaryrefslogtreecommitdiff
path: root/lib/HttpServ.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/HttpServ.cc')
-rw-r--r--lib/HttpServ.cc946
1 files changed, 473 insertions, 473 deletions
diff --git a/lib/HttpServ.cc b/lib/HttpServ.cc
index a8e7301..a4101a7 100644
--- a/lib/HttpServ.cc
+++ b/lib/HttpServ.cc
@@ -1,473 +1,473 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "Socket.h"
-#include "Action.h"
-#include "HttpServ.h"
-#include "Buffer.h"
-#include "ReadJob.h"
-#include "CopyJob.h"
-#include "Task.h"
-#include "gettext.h"
-
-String endhl = "\r\n", endnl = "\n";
-
-class ProcessRequest : public Task {
- public:
- ProcessRequest(Action *, const Socket &, const String &, int);
- virtual ~ProcessRequest() {}
- virtual String GetName();
- protected:
- virtual int Do() throw (GeneralException);
- private:
- String GetMime(const String &);
- bool ParseUri(String &, String &, String &, Handle *);
- void ParseVars(Handle *, int);
- void ShowError(Handle *);
- void SendHeads(Handle *, const String &, const String & = "", time_t = -1);
- void SendRedirect(Handle *);
-
- String file, domain, t;
- Buffer b;
- Task * c, * a;
- Action * f;
- int len, localport;
- Action * p;
- Socket s;
-
- String name, host, gvars;
- Variables * Vars, * Heads;
- bool bad, hasvars, post;
-};
-
-ProcessRequest::ProcessRequest(Action * ap, const Socket & as, const String & aname, int aport) : localport(aport), p(ap), s(as), name(aname) {
- SetBurst();
-}
-
-String ProcessRequest::GetName() {
- return _("Processing HTTP request");
-}
-
-int ProcessRequest::Do() throw(GeneralException) {
- switch (current) {
- case 0:
- if (!s.IsConnected()) return TASK_DONE;
-
- c = new ReadJob(&s, &b);
- WaitFor(c);
- current = 1;
- Suspend(TASK_ON_HOLD);
-
- case 1:
- delete c;
-
- bad = false;
-
-// std::cerr << "---- Got a request from handle " << s.GetHandle() << " \n";
-
- post = ParseUri(file, domain, gvars, &b);
-
- Heads = new Variables();
- Vars = new Variables();
-
- len = -1;
- do {
- int p;
- b >> t;
-// std::cerr << "Read Request (n): " << t << std::endl;
- if ((t.strstr("Content-Length: ") == 0) || (t.strstr("Content-length: ") == 0)) {
-// std::cerr << "Saw 'Content-Lenght:', reading length from '" << t.extract(16) << "'\n";
- len = t.extract(16).to_int();
- }
- if (t.strstr("Host: ") == 0) {
- host = t.extract(6);
- }
-
- if ((p = t.strchr(':')) >= 0) {
- String s = t.extract(0, p - 1);
- s += '=';
- s += t.extract(p + 2);
- Heads->Add(s);
- }
- } while (t.strlen());
-
-// std::cerr << "---- Processing it.\n";
-
- hasvars = false;
-
- if (post) {
- // On a pas eu de ligne 'Content-Length' mais on a eu une méthode POST.
- // Cela est une erreur.
- if (len == -1) {
-// std::cerr << "Error: method POST but no Content-Length\n";
- bad = true;
- } else {
-// std::cerr << "Got a POST request. Parsing variables. (len = " << len << ")\n";
- // Les variables seront initialisées ici.
- hasvars = true;
- }
- }
-
- current = 2;
- if (hasvars && (len)) {
- c = new CopyJob(&s, &b, len);
- WaitFor(c);
- Suspend();
- } else {
- c = 0;
- }
-
- case 2:
- if (gvars != "") {
- Buffer b2;
- b2 << gvars;
- ParseVars(&b2, gvars.strlen());
- }
- if (hasvars) {
- if (c) delete c;
- ParseVars(&b, len);
- }
-
- std::cerr << " Domain = '" << domain << "' - File = '" << file << "'\n";
-
- if (!bad) {
- // Nous vérifions le domaine.
- if (domain != "") {
- bad = true;
- // Les domaines valides sont '/', '/bin' et '/image'.
- if (domain == "/image") bad = false;
- if (domain == "/bin") bad = false;
- if (domain == "/") bad = false;
- if (bad) {
- std::cerr << _("Error: bad domain.\n");
- }
- } else {
- // L'url sans domaine ni fichier est valide. (cela arrive sur certains navigateurs...)
- bad = (file != "");
- }
- }
-
- a = 0;
-
- if (bad) {
- ShowError(&b);
- } else {
- if (((domain == "") || (domain == "/")) && (file == "")) {
- // Si le navigateur a demandé l'URL '/', alors on renvoie une notification
- // de redirection.
- SendRedirect(&b);
- } else if (domain == "/bin") {
- // Le domaine 'bin' est réservé aux actions. On cherche donc l'action à effectuer.
- if ((f = p->Look4URL(file))) {
- SendHeads(&b, "text/html");
- a = f->Do(Vars, Heads, &s);
- } else {
- ShowError(&b);
- }
- } else {
- // Dans tous les autres cas de domaine, on cherche le fichier dans le répertoire datas.
- // On utilise try au cas où le fichier n'existe pas et donc que le constructeur
- // d'input renvoie une erreur.
- try {
- Handle * i = new Input(String("datas/") + file);
- SendHeads(&b, GetMime(file), String("Accept-Ranges: bytes") + endhl + "Content-Length: " + (unsigned long long int) i->GetSize() + endhl, i->GetModif());
- i->SetNonBlock();
- a = new CopyJob(i, &s);
- std::cerr << _("File found, dumping.\n");
- }
- catch (IOGeneral e) {
- ShowError(&b);
- std::cerr << _("File not found, error showed.\n");
- }
- }
- }
-
- if (a) a->Stop();
-
- delete Vars;
- delete Heads;
-// std::cerr << "---- Sending header buffer.\n";
- c = new CopyJob(&b, &s, -1, false);
- WaitFor(c);
- current = 3;
- Suspend();
-
- case 3:
- delete c;
-
- if (a) {
-// std::cerr << "---- Sending contents.\n";
- a->Restart();
- WaitFor(a);
- current = 4;
- Suspend();
- }
-
- case 4:
- if (a) delete a;
-// std::cerr << "---- End of Request.\n";
- }
- return TASK_DONE;
-}
-
-void ProcessRequest::ParseVars(Handle * s, int len) {
- String t, v;
- char conv[3], l;
- int hconv, nbvars;
- ssize_t pos = 0, next;
-
- t = "";
- for (int i = 0; i < len; i++) {
- s->read(&l, 1);
- t += l;
- }
-// std::cerr << "Post variables line: '" << t << "'\n";
-
-
- // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc le nombre d'occurences
- // du caractère '=' indique le nombre de variables.
- nbvars = t.strchrcnt('=');
-
- for (int i = 0; i < nbvars; i++) {
- // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc on cherche le caractère
- // & dans la chaine POST.
- next = t.strchr('&', pos);
- if (next < 0) next = t.strlen();
- v = "";
- while (pos != next) {
- switch (t[pos]) {
- // Le navigateur encode les caractères spéciaux à l'aide du format %XX où XX indique
- // la valeur hexadécimale du caractère. Nous encodons surtout les caractères
- // ' ', '=', '%', et '/' avec cette technique.
- case '%':
- pos++;
- conv[0] = t[pos++];
- conv[1] = t[pos++];
- conv[2] = '\0';
- sscanf(conv, "%x", &hconv);
- v += ((char) hconv);
- break;
- // Certains navigateurs utilisent '+' pour indiquer ' ' (qui est illégal) au lieu
- // d'utiliser %20.
- case '+':
- v += ' ';
- pos++;
- break;
- default:
- v += t[pos++];
- }
- }
-// std::cerr << "Pushing HTTP variable: " << v << std::endl;
- Vars->Add(v);
- pos++;
- }
-}
-
-/*
- * Cette fonction renverra true si la méthode est une méthode POST.
- * Les Strings domain et file seront modifiées afin de renvoyer le domaine
- * et le fichier lut. La string s doit donner la première ligne de la requète,
- * c'est à dire la méthode demandée par le client.
- */
-
-bool ProcessRequest::ParseUri(String & file, String & domain, String & gvars, Handle * s) {
- String t, Uri;
- bool post = false;
- const char * p = 0;
- ssize_t sppos;
-
- *s >> t;
- std::cerr << _("Read Request (1): ") << t << std::endl;
-
- int IPos = t.strchr('?');
-
- gvars = "";
-
- if (IPos >= 0) {
- int HPos = t.strchr(' ', IPos);
- char * sdup = t.strdup(0, IPos - 1);
- gvars = t.extract(IPos + 1, HPos - 1);
- t = sdup;
- free(sdup);
- }
-
-// std::cerr << "New request: " << t << ", gvars = " << gvars << std::endl;
-
- bad = false;
-
- // p nous indiquera la position de la chaîne URL.
- switch (t[0]) {
- case 'P': /* POST? */
- if (t.extract(1, 4) == "OST ") {
- p = t.to_charp(5);
- post = true;
- } else {
-// std::cerr << "Error: unknow request.\n";
- bad = true;
- }
- break;
- case 'G': /* GET? */
- if (t.extract(1, 3) == "ET ") {
- p = t.to_charp(4);
- } else {
-// std::cerr << "Error: unknow request.\n";
- bad = true;
- }
- break;
- default:
-// std::cerr << "Error: unknow request.\n";
- bad = true;
- }
-
- if (!bad) {
- ssize_t poshttp, posslash;
- Uri = p;
- sppos = Uri.strrchr(' ');
- p = Uri.to_charp(0, sppos - 1);
- Uri = p;
- // On enlève tout le host spécifié éventuellement dans la requete.
- if ((poshttp = Uri.strstr("http://")) > 0) {
- Uri = Uri.to_charp(poshttp + 7);
- posslash = Uri.strchr('/');
- // Certains navigateurs indiqueront uniquement http://host comme URL.
- if (posslash >= 0) {
- host = Uri.extract(0, posslash - 1);
- Uri = Uri.to_charp(posslash);
- } else {
- host = Uri;
- Uri = "";
- }
- }
- posslash = Uri.strrchr('/');
- file = Uri.to_charp(posslash + 1);
- if (posslash > 0) {
- domain = Uri.to_charp(0, posslash - 1);
- } else {
- domain = "";
- }
- }
- return post;
-}
-
-/*
- * Ceci sert à rediriger le navigateur vers l'url de démarrage.
- */
-void ProcessRequest::SendRedirect(Handle * s) {
- *s << "HTTP/1.1 301 Moved Permanently" << endhl <<
- "Server: " << name << endhl <<
- "Location: http://" << host << "/bin/start" << endhl <<
- "Cache-Control: no-cache" << endhl <<
- "Connection: closed" << endhl <<
- "Content-Type: text/html" << endhl << endhl <<
- "<HTML><HEAD><TITLE>301 - Moved Permanently</TITLE></HEAD>" << endnl <<
- "<BODY><center><b><h2>You should be redirected to the " << endnl << endnl <<
- "<a href=\"http://" << host << "/bin/start\">start page</a></h2></b></center>" << endnl <<
- "</BODY></HTML>" << endnl;
-}
-
-/*
- * Nous envoyons les entetes de réponse HTTP.
- */
-
-void ProcessRequest::SendHeads(Handle * s, const String & mime, const String & extra, time_t lm) {
- time_t t = time(NULL);
- struct tm * ft = gmtime(&t);
- char buf[1024];
- strftime(buf, 1024, "%a, %d %b %Y %H:%M:%S GMT", ft);
- *s << "HTTP/1.1 200 OK" << endhl <<
- "Date: " << buf << endhl <<
- "Server: " << name << endhl;
- if (lm >=0) {
- ft = gmtime(&lm);
- strftime(buf, 1024, "%a, %d %b %Y %H:%M:%S GMT", ft);
- }
- *s << "Last-Modified: " << buf << endhl << extra <<
- "Connection: closed" << endhl <<
- "Content-Type: " << mime << endhl << endhl;
-}
-
-/*
- * Affichage d'une erreur 404.
- */
-
-void ProcessRequest::ShowError(Handle * s) {
- *s << "HTTP/1.1 404 Not Found" << endhl <<
- "Server: " << name << endhl <<
- "Cache-Control: no-cache" << endhl <<
- "Connection: closed" << endhl <<
- "Content-Type: text/html" << endhl << endhl <<
- "<HTML><HEAD><TITLE>404 - Error</TITLE></HEAD>" << endnl <<
- "<BODY><center><b><h2>The server was unable to process your query</h2></b></center>" << endnl <<
- "Click <A HREF=\"/\">here</A> to go the main page." <<
- "</BODY></HTML>" << endnl;
-}
-
-/*
- * Sert à déterminer le type mime à partir de l'extension du fichier.
- * Par défaut, nous mettons "text/plain".
- */
-
-String ProcessRequest::GetMime(const String & f) {
- String ext;
- size_t ppos;
-
- ppos = f.strrchr('.');
-
- if (ppos >= 0) {
- ext = f.extract(ppos + 1);
- if (ext == "jpg") return "image/jpeg";
- if (ext == "jpeg") return "image/jpeg";
- if (ext == "htm") return "text/html";
- if (ext == "html") return "text/html";
- if (ext == "gif") return "image/gif";
- if (ext == "png") return "image/png";
- if (ext == "class") return "application/octet-stream";
- }
-
- return "text/plain";
-}
-
-HttpServ::HttpServ(Action * ap, int port, const String & nname) throw (GeneralException) {
- bool r = true;
-
- p = ap;
- name = nname;
- localport = port;
-
-// std::cerr << "Initialising Mini HTTP-Server on port " << localport << std::endl;
-
- r = Listener.SetLocal("", port);
- if (!r) {
- throw GeneralException(_("Initialisation of the Mini HTTP-Server failed: can't bind"));
- }
-
- r = Listener.Listen();
-
- if (!r) {
- throw GeneralException(_("Initialisation of the Mini HTTP-Server failed: can't listen"));
- }
-
- Listener.SetNonBlock();
- WaitFor(&Listener, W4_STICKY | W4_READING);
-
-// std::cerr << "Mini HTTP-Server '" << name << "' ready and listening for port " << port << std::endl;
-}
-
-HttpServ::~HttpServ(void) {
- Listener.close();
-}
-
-int HttpServ::Do() throw (GeneralException) {
- try {
- Socket s = Listener.Accept();
- s.SetNonBlock();
- new ProcessRequest(p, s, name, localport);
- }
- catch (GeneralException) {
- }
- return TASK_ON_HOLD;
-}
-
-String HttpServ::GetName() {
- return String("Mini HTTP-Server '") + name + "'";
-}
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "Socket.h"
+#include "Action.h"
+#include "HttpServ.h"
+#include "Buffer.h"
+#include "ReadJob.h"
+#include "CopyJob.h"
+#include "Task.h"
+#include "gettext.h"
+
+String endhl = "\r\n", endnl = "\n";
+
+class ProcessRequest : public Task {
+ public:
+ ProcessRequest(Action *, const Socket &, const String &, int);
+ virtual ~ProcessRequest() {}
+ virtual String GetName();
+ protected:
+ virtual int Do() throw (GeneralException);
+ private:
+ String GetMime(const String &);
+ bool ParseUri(String &, String &, String &, Handle *);
+ void ParseVars(Handle *, int);
+ void ShowError(Handle *);
+ void SendHeads(Handle *, const String &, const String & = "", time_t = -1);
+ void SendRedirect(Handle *);
+
+ String file, domain, t;
+ Buffer b;
+ Task * c, * a;
+ Action * f;
+ int len, localport;
+ Action * p;
+ Socket s;
+
+ String name, host, gvars;
+ Variables * Vars, * Heads;
+ bool bad, hasvars, post;
+};
+
+ProcessRequest::ProcessRequest(Action * ap, const Socket & as, const String & aname, int aport) : localport(aport), p(ap), s(as), name(aname) {
+ SetBurst();
+}
+
+String ProcessRequest::GetName() {
+ return _("Processing HTTP request");
+}
+
+int ProcessRequest::Do() throw(GeneralException) {
+ switch (current) {
+ case 0:
+ if (!s.IsConnected()) return TASK_DONE;
+
+ c = new ReadJob(&s, &b);
+ WaitFor(c);
+ current = 1;
+ Suspend(TASK_ON_HOLD);
+
+ case 1:
+ delete c;
+
+ bad = false;
+
+// std::cerr << "---- Got a request from handle " << s.GetHandle() << " \n";
+
+ post = ParseUri(file, domain, gvars, &b);
+
+ Heads = new Variables();
+ Vars = new Variables();
+
+ len = -1;
+ do {
+ int p;
+ b >> t;
+// std::cerr << "Read Request (n): " << t << std::endl;
+ if ((t.strstr("Content-Length: ") == 0) || (t.strstr("Content-length: ") == 0)) {
+// std::cerr << "Saw 'Content-Lenght:', reading length from '" << t.extract(16) << "'\n";
+ len = t.extract(16).to_int();
+ }
+ if (t.strstr("Host: ") == 0) {
+ host = t.extract(6);
+ }
+
+ if ((p = t.strchr(':')) >= 0) {
+ String s = t.extract(0, p - 1);
+ s += '=';
+ s += t.extract(p + 2);
+ Heads->Add(s);
+ }
+ } while (t.strlen());
+
+// std::cerr << "---- Processing it.\n";
+
+ hasvars = false;
+
+ if (post) {
+ // On a pas eu de ligne 'Content-Length' mais on a eu une méthode POST.
+ // Cela est une erreur.
+ if (len == -1) {
+// std::cerr << "Error: method POST but no Content-Length\n";
+ bad = true;
+ } else {
+// std::cerr << "Got a POST request. Parsing variables. (len = " << len << ")\n";
+ // Les variables seront initialisées ici.
+ hasvars = true;
+ }
+ }
+
+ current = 2;
+ if (hasvars && (len)) {
+ c = new CopyJob(&s, &b, len);
+ WaitFor(c);
+ Suspend();
+ } else {
+ c = 0;
+ }
+
+ case 2:
+ if (gvars != "") {
+ Buffer b2;
+ b2 << gvars;
+ ParseVars(&b2, gvars.strlen());
+ }
+ if (hasvars) {
+ if (c) delete c;
+ ParseVars(&b, len);
+ }
+
+ std::cerr << " Domain = '" << domain << "' - File = '" << file << "'\n";
+
+ if (!bad) {
+ // Nous vérifions le domaine.
+ if (domain != "") {
+ bad = true;
+ // Les domaines valides sont '/', '/bin' et '/image'.
+ if (domain == "/image") bad = false;
+ if (domain == "/bin") bad = false;
+ if (domain == "/") bad = false;
+ if (bad) {
+ std::cerr << _("Error: bad domain.\n");
+ }
+ } else {
+ // L'url sans domaine ni fichier est valide. (cela arrive sur certains navigateurs...)
+ bad = (file != "");
+ }
+ }
+
+ a = 0;
+
+ if (bad) {
+ ShowError(&b);
+ } else {
+ if (((domain == "") || (domain == "/")) && (file == "")) {
+ // Si le navigateur a demandé l'URL '/', alors on renvoie une notification
+ // de redirection.
+ SendRedirect(&b);
+ } else if (domain == "/bin") {
+ // Le domaine 'bin' est réservé aux actions. On cherche donc l'action à effectuer.
+ if ((f = p->Look4URL(file))) {
+ SendHeads(&b, "text/html");
+ a = f->Do(Vars, Heads, &s);
+ } else {
+ ShowError(&b);
+ }
+ } else {
+ // Dans tous les autres cas de domaine, on cherche le fichier dans le répertoire datas.
+ // On utilise try au cas où le fichier n'existe pas et donc que le constructeur
+ // d'input renvoie une erreur.
+ try {
+ Handle * i = new Input(String("datas/") + file);
+ SendHeads(&b, GetMime(file), String("Accept-Ranges: bytes") + endhl + "Content-Length: " + (unsigned long long int) i->GetSize() + endhl, i->GetModif());
+ i->SetNonBlock();
+ a = new CopyJob(i, &s);
+ std::cerr << _("File found, dumping.\n");
+ }
+ catch (IOGeneral e) {
+ ShowError(&b);
+ std::cerr << _("File not found, error showed.\n");
+ }
+ }
+ }
+
+ if (a) a->Stop();
+
+ delete Vars;
+ delete Heads;
+// std::cerr << "---- Sending header buffer.\n";
+ c = new CopyJob(&b, &s, -1, false);
+ WaitFor(c);
+ current = 3;
+ Suspend();
+
+ case 3:
+ delete c;
+
+ if (a) {
+// std::cerr << "---- Sending contents.\n";
+ a->Restart();
+ WaitFor(a);
+ current = 4;
+ Suspend();
+ }
+
+ case 4:
+ if (a) delete a;
+// std::cerr << "---- End of Request.\n";
+ }
+ return TASK_DONE;
+}
+
+void ProcessRequest::ParseVars(Handle * s, int len) {
+ String t, v;
+ char conv[3], l;
+ int hconv, nbvars;
+ ssize_t pos = 0, next;
+
+ t = "";
+ for (int i = 0; i < len; i++) {
+ s->read(&l, 1);
+ t += l;
+ }
+// std::cerr << "Post variables line: '" << t << "'\n";
+
+
+ // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc le nombre d'occurences
+ // du caractère '=' indique le nombre de variables.
+ nbvars = t.strchrcnt('=');
+
+ for (int i = 0; i < nbvars; i++) {
+ // Les variables sont sous la forme 'var1=val1&var2=val2&val3=var3'. Donc on cherche le caractère
+ // & dans la chaine POST.
+ next = t.strchr('&', pos);
+ if (next < 0) next = t.strlen();
+ v = "";
+ while (pos != next) {
+ switch (t[pos]) {
+ // Le navigateur encode les caractères spéciaux à l'aide du format %XX où XX indique
+ // la valeur hexadécimale du caractère. Nous encodons surtout les caractères
+ // ' ', '=', '%', et '/' avec cette technique.
+ case '%':
+ pos++;
+ conv[0] = t[pos++];
+ conv[1] = t[pos++];
+ conv[2] = '\0';
+ sscanf(conv, "%x", &hconv);
+ v += ((char) hconv);
+ break;
+ // Certains navigateurs utilisent '+' pour indiquer ' ' (qui est illégal) au lieu
+ // d'utiliser %20.
+ case '+':
+ v += ' ';
+ pos++;
+ break;
+ default:
+ v += t[pos++];
+ }
+ }
+// std::cerr << "Pushing HTTP variable: " << v << std::endl;
+ Vars->Add(v);
+ pos++;
+ }
+}
+
+/*
+ * Cette fonction renverra true si la méthode est une méthode POST.
+ * Les Strings domain et file seront modifiées afin de renvoyer le domaine
+ * et le fichier lut. La string s doit donner la première ligne de la requète,
+ * c'est à dire la méthode demandée par le client.
+ */
+
+bool ProcessRequest::ParseUri(String & file, String & domain, String & gvars, Handle * s) {
+ String t, Uri;
+ bool post = false;
+ const char * p = 0;
+ ssize_t sppos;
+
+ *s >> t;
+ std::cerr << _("Read Request (1): ") << t << std::endl;
+
+ int IPos = t.strchr('?');
+
+ gvars = "";
+
+ if (IPos >= 0) {
+ int HPos = t.strchr(' ', IPos);
+ char * sdup = t.strdup(0, IPos - 1);
+ gvars = t.extract(IPos + 1, HPos - 1);
+ t = sdup;
+ free(sdup);
+ }
+
+// std::cerr << "New request: " << t << ", gvars = " << gvars << std::endl;
+
+ bad = false;
+
+ // p nous indiquera la position de la chaîne URL.
+ switch (t[0]) {
+ case 'P': /* POST? */
+ if (t.extract(1, 4) == "OST ") {
+ p = t.to_charp(5);
+ post = true;
+ } else {
+// std::cerr << "Error: unknow request.\n";
+ bad = true;
+ }
+ break;
+ case 'G': /* GET? */
+ if (t.extract(1, 3) == "ET ") {
+ p = t.to_charp(4);
+ } else {
+// std::cerr << "Error: unknow request.\n";
+ bad = true;
+ }
+ break;
+ default:
+// std::cerr << "Error: unknow request.\n";
+ bad = true;
+ }
+
+ if (!bad) {
+ ssize_t poshttp, posslash;
+ Uri = p;
+ sppos = Uri.strrchr(' ');
+ p = Uri.to_charp(0, sppos - 1);
+ Uri = p;
+ // On enlève tout le host spécifié éventuellement dans la requete.
+ if ((poshttp = Uri.strstr("http://")) > 0) {
+ Uri = Uri.to_charp(poshttp + 7);
+ posslash = Uri.strchr('/');
+ // Certains navigateurs indiqueront uniquement http://host comme URL.
+ if (posslash >= 0) {
+ host = Uri.extract(0, posslash - 1);
+ Uri = Uri.to_charp(posslash);
+ } else {
+ host = Uri;
+ Uri = "";
+ }
+ }
+ posslash = Uri.strrchr('/');
+ file = Uri.to_charp(posslash + 1);
+ if (posslash > 0) {
+ domain = Uri.to_charp(0, posslash - 1);
+ } else {
+ domain = "";
+ }
+ }
+ return post;
+}
+
+/*
+ * Ceci sert à rediriger le navigateur vers l'url de démarrage.
+ */
+void ProcessRequest::SendRedirect(Handle * s) {
+ *s << "HTTP/1.1 301 Moved Permanently" << endhl <<
+ "Server: " << name << endhl <<
+ "Location: http://" << host << "/bin/start" << endhl <<
+ "Cache-Control: no-cache" << endhl <<
+ "Connection: closed" << endhl <<
+ "Content-Type: text/html" << endhl << endhl <<
+ "<HTML><HEAD><TITLE>301 - Moved Permanently</TITLE></HEAD>" << endnl <<
+ "<BODY><center><b><h2>You should be redirected to the " << endnl << endnl <<
+ "<a href=\"http://" << host << "/bin/start\">start page</a></h2></b></center>" << endnl <<
+ "</BODY></HTML>" << endnl;
+}
+
+/*
+ * Nous envoyons les entetes de réponse HTTP.
+ */
+
+void ProcessRequest::SendHeads(Handle * s, const String & mime, const String & extra, time_t lm) {
+ time_t t = time(NULL);
+ struct tm * ft = gmtime(&t);
+ char buf[1024];
+ strftime(buf, 1024, "%a, %d %b %Y %H:%M:%S GMT", ft);
+ *s << "HTTP/1.1 200 OK" << endhl <<
+ "Date: " << buf << endhl <<
+ "Server: " << name << endhl;
+ if (lm >=0) {
+ ft = gmtime(&lm);
+ strftime(buf, 1024, "%a, %d %b %Y %H:%M:%S GMT", ft);
+ }
+ *s << "Last-Modified: " << buf << endhl << extra <<
+ "Connection: closed" << endhl <<
+ "Content-Type: " << mime << endhl << endhl;
+}
+
+/*
+ * Affichage d'une erreur 404.
+ */
+
+void ProcessRequest::ShowError(Handle * s) {
+ *s << "HTTP/1.1 404 Not Found" << endhl <<
+ "Server: " << name << endhl <<
+ "Cache-Control: no-cache" << endhl <<
+ "Connection: closed" << endhl <<
+ "Content-Type: text/html" << endhl << endhl <<
+ "<HTML><HEAD><TITLE>404 - Error</TITLE></HEAD>" << endnl <<
+ "<BODY><center><b><h2>The server was unable to process your query</h2></b></center>" << endnl <<
+ "Click <A HREF=\"/\">here</A> to go the main page." <<
+ "</BODY></HTML>" << endnl;
+}
+
+/*
+ * Sert à déterminer le type mime à partir de l'extension du fichier.
+ * Par défaut, nous mettons "text/plain".
+ */
+
+String ProcessRequest::GetMime(const String & f) {
+ String ext;
+ size_t ppos;
+
+ ppos = f.strrchr('.');
+
+ if (ppos >= 0) {
+ ext = f.extract(ppos + 1);
+ if (ext == "jpg") return "image/jpeg";
+ if (ext == "jpeg") return "image/jpeg";
+ if (ext == "htm") return "text/html";
+ if (ext == "html") return "text/html";
+ if (ext == "gif") return "image/gif";
+ if (ext == "png") return "image/png";
+ if (ext == "class") return "application/octet-stream";
+ }
+
+ return "text/plain";
+}
+
+HttpServ::HttpServ(Action * ap, int port, const String & nname) throw (GeneralException) {
+ bool r = true;
+
+ p = ap;
+ name = nname;
+ localport = port;
+
+// std::cerr << "Initialising Mini HTTP-Server on port " << localport << std::endl;
+
+ r = Listener.SetLocal("", port);
+ if (!r) {
+ throw GeneralException(_("Initialisation of the Mini HTTP-Server failed: can't bind"));
+ }
+
+ r = Listener.Listen();
+
+ if (!r) {
+ throw GeneralException(_("Initialisation of the Mini HTTP-Server failed: can't listen"));
+ }
+
+ Listener.SetNonBlock();
+ WaitFor(&Listener, W4_STICKY | W4_READING);
+
+// std::cerr << "Mini HTTP-Server '" << name << "' ready and listening for port " << port << std::endl;
+}
+
+HttpServ::~HttpServ(void) {
+ Listener.close();
+}
+
+int HttpServ::Do() throw (GeneralException) {
+ try {
+ Socket s = Listener.Accept();
+ s.SetNonBlock();
+ new ProcessRequest(p, s, name, localport);
+ }
+ catch (GeneralException) {
+ }
+ return TASK_ON_HOLD;
+}
+
+String HttpServ::GetName() {
+ return String("Mini HTTP-Server '") + name + "'";
+}