]> git.llucax.com Git - z.facultad/75.42/plaqui.git/commitdiff
Pocos cambios a la vista del "usuario":
authorLeandro Lucarella <llucax@gmail.com>
Wed, 12 Nov 2003 03:36:58 +0000 (03:36 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Wed, 12 Nov 2003 03:36:58 +0000 (03:36 +0000)
- Ya se envían comandos con la señal command_received() apropiadamente.
- Las respuestas son asincrónicas, ya que los comandos van a encolarse para
  esperar que el modelo se actulice.
- Ya se pueden enviar respuestas via ControlServer::send().
Muchos cambios internos entre los que se destacan el correcto funcionamiento de
las excepciones (que venía postergado).

22 files changed:
Server/include/plaqui/server/controlclient.h
Server/include/plaqui/server/controlserver.h
Server/include/plaqui/server/httperror.h [new file with mode: 0644]
Server/include/plaqui/server/httpheaders.h
Server/include/plaqui/server/httpmessage.h
Server/include/plaqui/server/httprequest.h
Server/include/plaqui/server/httpresponse.h
Server/include/plaqui/server/server.h
Server/include/plaqui/server/string.h
Server/include/plaqui/server/tcpserver.h
Server/src/Makefile
Server/src/controlserver.cpp
Server/src/httperror.cpp [new file with mode: 0644]
Server/src/httpheaders.cpp
Server/src/httpmessage.cpp
Server/src/httprequest.cpp
Server/src/httpresponse.cpp
Server/src/runnable.cpp
Server/src/server.cpp
Server/src/string.cpp
Server/src/tcpserver.cpp
Server/tests/Makefile

index 73acdcfda36d704c60ae5d7c7ece035aba3d20ce..faf3a275e1c826eca99883e5bb02a34280ebb1e6 100644 (file)
@@ -38,6 +38,15 @@ namespace Server {
        /// Conexión para enviar comandos de control a una planta.
        class ControlClient: public Connection {
 
+               // Atributos.
+
+               private:
+
+                       /// Mutex para el socket.
+                       Glib::Mutex socket_mutex;
+                       
+               // Métodos.
+
                private:
 
                        /**
index 5b6eb23e553ec43c73604dc569493df289ba6024..7c5ea6efbad3085a13dbfa80ebc075ed75d15964 100644 (file)
@@ -30,7 +30,9 @@
 
 #include "plaqui/server/connection.h"
 #include "plaqui/server/command.h"
+#include "plaqui/server/httpresponse.h"
 #include <socket++/sockinet.h>
+#include <sigc++/signal.h>
 
 namespace PlaQui {
 
@@ -50,6 +52,9 @@ namespace Server {
 
                private:
 
+                       /// Mutex para el socket.
+                       Glib::Mutex socket_mutex;
+                       
                        /// Señal para indicar que se recibió un comando.
                        SignalCommandReceived command_received;
 
@@ -77,6 +82,11 @@ namespace Server {
                         */
                        ControlServer(const sockbuf::sockdesc& sd);
 
+                       /**
+                        * Envia una respuesta.
+                        */
+                       void send(const HTTPResponse& response);
+
                        /**
                         * Obtiene la señal que avisa cuando se recibió un comando.
                         */
diff --git a/Server/include/plaqui/server/httperror.h b/Server/include/plaqui/server/httperror.h
new file mode 100644 (file)
index 0000000..1cc4ee8
--- /dev/null
@@ -0,0 +1,70 @@
+// vim: set noexpandtab tabstop=4 shiftwidth=4:
+//----------------------------------------------------------------------------
+//                                  PlaQui
+//----------------------------------------------------------------------------
+// This file is part of PlaQui.
+//
+// PlaQui is free software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 2 of the License, or (at your option) any later
+// version.
+//
+// PlaQui is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along
+// with PlaQui; if not, write to the Free Software Foundation, Inc., 59 Temple
+// Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------------
+// Creado:  mar nov 11 11:47:25 ART 2003
+// Autores: Leandro Lucarella <llucare@fi.uba.ar>
+//----------------------------------------------------------------------------
+//
+// $Id$
+//
+
+#ifndef PLAQUI_HTTPERROR_H
+#define PLAQUI_HTTPERROR_H
+
+#include <stdexcept>
+#include <string>
+#include <istream>
+#include <ostream>
+
+namespace PlaQui {
+
+namespace Server {
+
+       /// Error HTTP.
+       class HTTPError: public std::runtime_error {
+
+               // Atributos.
+
+               public:
+
+                       /// Código de error.
+                       unsigned code;
+
+               // Métodos.
+
+               public:
+
+                       /**
+                        * Destructor.
+                        */
+                       virtual ~HTTPError(void) throw();
+
+                       /**
+                        * Constructor.
+                        */
+                       HTTPError(unsigned code, const std::string& desc) throw();
+
+       };
+
+}
+
+}
+
+#endif // PLAQUI_HTTPERROR_H 
index 1a9c5aaebf67a55f8253dbada1bb26df687b1621..86a2dd1b3d96a49430780c1356d397351ff63187 100644 (file)
@@ -28,6 +28,7 @@
 #ifndef PLAQUI_HTTPHEADERS_H
 #define PLAQUI_HTTPHEADERS_H
 
+#include "plaqui/server/httperror.h"
 #include <map>
 #include <string>
 #include <istream>
@@ -40,6 +41,8 @@ namespace Server {
        /// Cabeceras HTTP.
        class HTTPHeaders: public std::map<std::string, std::string> {
 
+               // Métodos.
+
                public:
 
                        /**
@@ -50,7 +53,8 @@ namespace Server {
                        /**
                         * Obtiene los datos de las cabeceras HTTP desde un texto.
                         */
-                       friend std::istream& operator>>(std::istream& is, HTTPHeaders& h);
+                       friend std::istream& operator>>(std::istream& is, HTTPHeaders& h)
+                               throw(HTTPError);
 
                        /**
                         * Convierte las cabeceras HTTP a texto.
index 938f9ad0e4aeeed50223749c906cff0232bd65d0..730bf0ac861d9a06d09d4a45f6fe6def6dd6a3df 100644 (file)
@@ -38,6 +38,18 @@ namespace Server {
        /// Pedido HTTP.
        class HTTPMessage {
 
+               // Constantes.
+
+               public:
+
+                       /// \todo TODO completar codigos.
+                       static const unsigned OK                         = 200;
+                       static const unsigned BAD_REQUEST                = 401;
+                       static const unsigned LENGTH_REQUIRED            = 411;
+                       static const unsigned INTERNAL_SERVER_ERROR      = 500;
+                       static const unsigned NOT_IMPLEMENTED            = 501;
+                       static const unsigned HTTP_VERSION_NOT_SUPPORTED = 505;
+
                // Atributos.
 
                private:
@@ -67,13 +79,13 @@ namespace Server {
                        /**
                         * Constructor.
                         */
-                       HTTPMessage(const std::string& http_version = "1.1");
+                       //HTTPMessage(const std::string& http_version = "1.1");
 
                        /**
                         * Constructor.
                         */
-                       //HTTPMessage(const std::string& body,
-                       //              const std::string& http_version = "1.1");
+                       HTTPMessage(const std::string& _body = "",
+                                       const std::string& _version = "1.1");
 
                        /**
                         * Obtiene el cuerpo del mensaje.
@@ -98,6 +110,13 @@ namespace Server {
                        friend std::ostream& operator<<(std::ostream& os,
                                        const HTTPMessage& m);
 
+                       /**
+                        * Obtiene la razón según un código.
+                        *
+                        * \param code Código de estado.
+                        */
+                       static std::string reason(unsigned code);
+
        };
 
 }
index ace04f077d8f1bb62d90b2b17f6033cf2e5099af..a5a3647f29a5f15c8b6f6e4ace553c37620f0dc7 100644 (file)
@@ -28,7 +28,8 @@
 #ifndef PLAQUI_HTTPREQUEST_H
 #define PLAQUI_HTTPREQUEST_H
 
-#include "httpmessage.h"
+#include "plaqui/server/httperror.h"
+#include "plaqui/server/httpmessage.h"
 #include <string>
 #include <istream>
 #include <ostream>
@@ -114,7 +115,8 @@ namespace Server {
                        /**
                         * Obtiene los datos del pedido HTTP desde un texto.
                         */
-                       friend std::istream& operator>>(std::istream& is, HTTPRequest& req);
+                       friend std::istream& operator>>(std::istream& is, HTTPRequest& req)
+                               throw(HTTPError, std::ios::failure);
 
                        /**
                         * Convierte el pedido HTTP en texto.
index f5c0afd81744a4053426b67a6780626cdab1241c..bc8f900a14bda0a2c240fa4a69ae6313e7bc80db 100644 (file)
@@ -28,7 +28,8 @@
 #ifndef PLAQUI_HTTPRESPONSE_H
 #define PLAQUI_HTTPRESPONSE_H
 
-#include "httpmessage.h"
+#include "plaqui/server/httperror.h"
+#include "plaqui/server/httpmessage.h"
 #include <string>
 
 namespace PlaQui {
@@ -38,6 +39,17 @@ namespace Server {
        /// Respuesta HTTP.
        class HTTPResponse: public HTTPMessage {
 
+               // Tipos.
+
+               public:
+
+                       typedef enum {
+                               INVALID_HTTP_RESPONSE,
+                               INVALID_HTTP_VERSION,
+                               INVALID_HTTP_RESPONSE_CODE,
+                               MISSING_HTTP_RESPONSE_CODE
+                       } Error;
+
                // Atributos.
 
                protected:
@@ -65,14 +77,12 @@ namespace Server {
                        /**
                         * Constructor.
                         */
-                       //HTTPResponse(const std::string& body,
-                       //              const std::string& version = "1.1");
+                       HTTPResponse(const HTTPError& error);
 
                        /**
                         * Constructor.
                         */
-                       //HTTPResponse(unsigned status_code, const std::string& reason,
-                       //              const std::string& version = "1.1");
+                       HTTPResponse(unsigned status_code, const std::string& body = "");
 
                        /**
                         * Constructor.
@@ -85,7 +95,7 @@ namespace Server {
                         * Obtiene los datos de la respuesta HTTP desde un texto.
                         */
                        friend std::istream& operator>>(std::istream& is,
-                                       HTTPResponse& resp);
+                                       HTTPResponse& resp) throw(Error, std::ios::failure);
 
                        /**
                         * Convierte la respuesta HTTP en texto.
index e66be38c1ee985eaeec8211b3d50c03a2df1ed82..8c92ca806942011126082d0607507ecdf67c6cb3 100644 (file)
@@ -125,7 +125,8 @@ namespace Server {
                         *
                         * \todo Hacer un tipo Command abstracto o algo así.
                         */
-                       void on_control_command_received(const Command& command);
+                       void on_control_command_received(const Command& command,
+                                       ControlServer* server);
 
        };
 
index 74c27cd96c175742f8c856ccc107cd9ae6ca7697..ecd253a8bc53e251aadcb34ab35fbee9112dbe4c 100644 (file)
@@ -48,6 +48,11 @@ namespace Server {
                         */
                        virtual ~String(void);
 
+                       /**
+                        * Constructor.
+                        */
+                       String(void);
+
                        /**
                         * Constructor.
                         *
index 393f4cc4040f4e82ebb80bac2e6aa6e842e10432..7465faa7a2d0cb9563a29285ade035b3aa3ba3da 100644 (file)
@@ -43,12 +43,16 @@ namespace Server {
         */
        class TCPServer: public Runnable {
 
-               // Tipos.
+               // Constantes.
 
                private:
 
                        /// Cantidad máxima de conexiones pendientes.
-                       static const unsigned MAX_PENDING_CONNECTIONS;
+                       static const unsigned MAX_PENDING_CONNECTIONS = 10;
+
+               // Tipos.
+
+               private:
 
                        /// Lista de conexiones de control.
                        typedef std::list<Connection*> ConnectionList;
index 0403d202f29b01d97b47805830f1c4a326419260..2337cb442dfa3967ea55c5cd537b386e71930b4e 100644 (file)
@@ -46,6 +46,10 @@ string_h=$(INCLUDE_DIR)/string.h
 objects+=string.o
 string.o: $(string_h) string.cpp
 
+httperror_h=$(INCLUDE_DIR)/httperror.h
+objects+=httperror.o
+httperror.o: $(httperror_h) httperror.cpp
+
 httpheaders_h=$(string_h) $(INCLUDE_DIR)/httpheaders.h
 objects+=httpheaders.o
 httpheaders.o: $(httpheaders_h) httpheaders.cpp
@@ -62,7 +66,7 @@ command_h=$(string_h) $(httprequest_h) $(INCLUDE_DIR)/command.h
 objects+=command.o
 command.o: $(command_h) command.cpp
 
-httpresponse_h=$(string_h) $(httpmessage_h) $(INCLUDE_DIR)/httprequest.h
+httpresponse_h=$(string_h) $(httperror_h) $(httpmessage_h) $(INCLUDE_DIR)/httprequest.h
 objects+=httpresponse.o
 httpresponse.o: $(httpresponse_h) httpresponse.cpp
 
index c5e163fe44e8d71044c563ed876a2e6071ce94b9..f5c6c730ca017c8b0610d860e7045e8c6d52fef0 100644 (file)
 
 #include "plaqui/server/controlserver.h"
 #include "plaqui/server/command.h"
-#include "plaqui/server/string.h"
-#include <cstring>
-#include <sstream>
+#include "plaqui/server/httperror.h"
+#include "plaqui/server/httpresponse.h"
+//#include <cstring>
+//#include <sstream>
 #ifdef DEBUG
+#      include "plaqui/server/string.h"
 #      include <iostream>
 #endif // DEBUG
 
@@ -61,21 +63,26 @@ void ControlServer::real_run(void) {
        while (!stop) {
                Command command;
                try {
+                       Glib::Mutex::Lock lock(socket_mutex);
                        socket >> command;
-               } catch (const char* e) {
-                       cerr << "    (" << __LINE__ << ") Error: " << e << endl;
+               // Si se cerró el socket.
+               } catch (const ios::failure& e) {
                        stop = true;
                        continue;
-               } catch (string e) {
-                       cerr << "    (" << __LINE__ << ") Error: " << e << endl;
-                       stop = true;
-                       continue;
-               } catch (...) {
-                       cerr << "    (" << __LINE__ << ") Error desconocido!" << endl;
-                       stop = true;
+               // Si hay un error al parsear el comando, se envia una respuesta con el
+               // error.
+               } catch (const HTTPError& e) {
+#ifdef DEBUG
+                       cerr << __FILE__ << " : real_run() ERROR: status_code = "
+                               << e.code << " | reason = " << HTTPMessage::reason(e.code)
+                               << " | desc = " << e.what() << endl;
+#endif // DEBUG
+                       socket << HTTPResponse(e) << flush;
                        continue;
                }
                // TODO agregar las verificaciones de abajo a HTTPRequest y padres.
+               // Actualizacion: Estoy usando trim() en casi todos lados, no debería
+               // ser necesario.
 /*
                // Primera línea no vacía (que debe ser el request).
                bool is_first = true;
@@ -110,26 +117,27 @@ void ControlServer::real_run(void) {
                        }
                }
 */
-               // Manda el comando.
-               command_received.emit(command);
 #ifdef DEBUG
-               cerr << "Comando: target = " << command.get_target()
-                       << " | command = " << command.get_command()
+               cerr << __FILE__ << " : real_run() Despachando comando: target = "
+                       << command.get_target() << " | command = " << command.get_command()
                        << " | args = [" << String::join(command.get_args(), ", ") << "]"
                        << endl;
 #endif // DEBUG
+               // Manda el comando.
+               command_received(command);
                // FIXME - hacer respuesta XML.
                // La respuesta hay que mandarla asincrónicamente porque no puedo
                // responder hasta que la planta no se termine de actualizar, por
                // ejemplo.
-               stringstream response_xml;
-               socket << "HTTP/1.0 200 OK" << endl;
+               //stringstream response_xml;
+               //socket << "HTTP/1.0 200 OK" << endl;
 /*
 Date: Sun, 19 Oct 2003 15:11:14 GMT
 Server: Apache/1.3.28 (Debian GNU/Linux)
 Last-Modified: Mon, 28 Apr 2003 07:50:08 GMT
 Accept-Ranges: bytes
 */
+/*
                socket << "Content-Type: text/html; charset=iso-8859-1" << endl;
                response_xml << "<html>" << endl;
                response_xml << "    <head>" << endl;
@@ -140,15 +148,6 @@ Accept-Ranges: bytes
                response_xml << "        <p>versión 0.4</p>" << endl;
                response_xml << "        <h2>Comando</h2>" << endl;
                response_xml << "        <ul>" << endl;
-/*             response_xml << "           <li><b>Versión:</b> " << request.version << endl;
-               response_xml << "           <li><b>Método:</b> " << (request.method ? "POST" : "GET") << endl;
-               response_xml << "           <li><b>URI:</b> " << request.uri << endl;
-               response_xml << "           <li><b>Query:</b> " << request.query << endl;
-               for (HTTPHeaders::const_iterator i = request.headers.begin();
-                               i != request.headers.end(); i++) {
-                       response_xml << "           <li><b>" << i->first << ":</b> "
-                               << i->second << endl;
-               }*/
                response_xml << "           <li><b>Target:</b> " << command.get_target() << endl;
                response_xml << "           <li><b>Command:</b> " << command.get_command() << endl;
                response_xml << "           <li><b>Argumentos:</b>" << endl;
@@ -174,9 +173,15 @@ Accept-Ranges: bytes
                socket << "Content-Length: " << response_xml.str().length() << endl;
                socket << endl;
                socket << response_xml.str() << flush;
+*/
        }
 }
 
+void ControlServer::send(const HTTPResponse& response) {
+       Glib::Mutex::Lock lock(socket_mutex);
+       socket << response << flush;
+}
+
 ControlServer::SignalCommandReceived& ControlServer::signal_command_received(void) {
        return command_received;
 }
diff --git a/Server/src/httperror.cpp b/Server/src/httperror.cpp
new file mode 100644 (file)
index 0000000..b00ded5
--- /dev/null
@@ -0,0 +1,55 @@
+// vim: set noexpandtab tabstop=4 shiftwidth=4:
+//----------------------------------------------------------------------------
+//                                  PlaQui
+//----------------------------------------------------------------------------
+// This file is part of PlaQui.
+//
+// PlaQui is free software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the Free Software
+// Foundation; either version 2 of the License, or (at your option) any later
+// version.
+//
+// PlaQui is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along
+// with PlaQui; if not, write to the Free Software Foundation, Inc., 59 Temple
+// Place, Suite 330, Boston, MA  02111-1307  USA
+//----------------------------------------------------------------------------
+// Creado:  mar nov 11 12:17:18 ART 2003
+// Autores: Leandro Lucarella <llucare@fi.uba.ar>
+//----------------------------------------------------------------------------
+//
+// $Id$
+//
+
+#include "plaqui/server/httperror.h"
+#ifdef DEBUG
+#      include <iostream>
+#endif // DEBUG
+
+using namespace std;
+
+namespace PlaQui {
+
+namespace Server {
+
+HTTPError::~HTTPError(void) throw() {
+#ifdef DEBUG
+       cerr << __FILE__ << ": destructor." << endl;
+#endif // DEBUG
+}
+
+HTTPError::HTTPError(unsigned code, const std::string& desc) throw():
+               runtime_error(desc), code(code) {
+#ifdef DEBUG
+       cerr << __FILE__ << ": code = " << code << " | desc = " << desc << endl;
+#endif // DEBUG
+}
+
+} // namespace Server
+
+} // namespace PlaQui
+
index 65d5adcc2c9466ccf17f1ea6e8dc929eda77bba1..0ec62e1e7301e87047a323e8786b61ffeea50f17 100644 (file)
@@ -26,6 +26,7 @@
 //
 
 #include "plaqui/server/httpheaders.h"
+#include "plaqui/server/httperror.h"
 #include "plaqui/server/string.h"
 //#include <cstdlib>
 #ifdef DEBUG
@@ -44,7 +45,7 @@ HTTPHeaders::~HTTPHeaders(void) {
 #endif // DEBUG
 }
 
-istream& operator>>(istream& is, HTTPHeaders& h) {
+istream& operator>>(istream& is, HTTPHeaders& h) throw(HTTPError) {
 #ifdef DEBUG
        cerr << __FILE__ << ": operator>>()" << endl;
 #endif // DEBUG
@@ -54,7 +55,7 @@ istream& operator>>(istream& is, HTTPHeaders& h) {
        string::size_type pos = sbuf.find(":");
        if (pos == string::npos) {
                // FIXME poner mejores excepciones.
-               throw string("Wrong header: ") + sbuf;
+               throw HTTPError(400, sbuf + ": No es una cabecera válida.");
        }
        h[sbuf.substr(0, pos)] = String(sbuf.substr(pos + 1)).trim();
 #ifdef DEBUG
index cfdd89404fab55f58f07ed292250a912e0accee2..af2875ecfcb441e2c48202033be7db999c135189 100644 (file)
@@ -45,30 +45,21 @@ HTTPMessage::~HTTPMessage(void) {
 #endif // DEBUG
 }
 
-HTTPMessage::HTTPMessage(const string& version):
-               version(version) {
+HTTPMessage::HTTPMessage(const string& _body, const string& _version):
+               version(_version) {
 #ifdef DEBUG
-       cerr << __FILE__ << ": version = " << version << endl;
-#endif // DEBUG
-}
-
-/*
-HTTPMessage::HTTPMessage(const string& _body,
-               const string& http_version):
-               http_version(http_version) {
-#ifdef DEBUG
-       cerr << __FILE__ << ": http_version = " << http_version
-               << " | body = " << body << endl;
+       cerr << __FILE__ << ": version = " << version << " | body.length = "
+               << _body.length() << endl;
 #endif // DEBUG
        set_body(_body);
 }
-*/
 
 void HTTPMessage::set_body(const string& _body) {
        body = _body;
        if (body.length()) {
                stringstream ss; // TODO ver forma mas linda de convertir
-               ss << body.length();
+               ss << (body.length());
+               headers["Accept-Ranges"] = "bytes";
                headers["Content-Length"] = ss.str();
        }
 }
@@ -124,6 +115,26 @@ ostream& operator<<(ostream& os, const HTTPMessage& m) {
                << m.body;
 }
 
+string HTTPMessage::reason(unsigned code) {
+       switch (code) {
+               // TODO completar los códigos.
+               case OK:
+                       return "OK";
+               case BAD_REQUEST:
+                       return "Bad Request";
+               case LENGTH_REQUIRED:
+                       return "Length Required";
+               case INTERNAL_SERVER_ERROR:
+                       return "Internal Server Error";
+               case NOT_IMPLEMENTED:
+                       return "Not Implemented";
+               case HTTP_VERSION_NOT_SUPPORTED:
+                       return "HTTP Version Not Supported";
+               default:
+                       return "";
+       }
+}
+
 } // namespace Server
 
 } // namespace PlaQui
index aa5d9cc8079a7f8efa4d75e43ca9e534abf3f9bd..f1119fd8d5a0b5b22dba540016bbccc471586800 100644 (file)
@@ -75,62 +75,70 @@ HTTPRequest::HTTPRequest(const string& uri,
 }
 */
 
-istream& operator>>(istream& is, HTTPRequest& req) {
+istream& operator>>(istream& is, HTTPRequest& req)
+               throw(HTTPError, ios::failure) {
 #ifdef DEBUG
        cerr << __FILE__ << ": operator>>()" << endl;
 #endif // DEBUG
        char buf[BUFSIZ];
        // Obtengo primera línea (request)
-       is.getline(buf, BUFSIZ);
+       if (!is.getline(buf, BUFSIZ)) {
+               // No hay más líneas.
+               throw ios::failure("socket closed");
+       }
 #ifdef DEBUG
-       cerr << "Recibiendo linea: " << buf << endl;
+       cerr << __FILE__ << ":\tRecibiendo linea: " << buf << endl;
 #endif // DEBUG
        String line(buf);
        // Si es la primera línea, es el request.
        if (line.length() < 3) {
-               // FIXME - poner excepciones lindas.
-               throw "HTTP/1.1 501 Method Not Implemented";
+               throw HTTPError(HTTPMessage::BAD_REQUEST, line
+                               + ": No tiene un método conocido.");
        }
        // Averiguo método.
        string::size_type pos = line.find_first_of(String::SPACE_CHARS);
        String met = line.substr(0, pos); 
-       if (met.to_upper() == "GET") {
+       met.to_upper();
+       if (met == "GET") {
                req.method = HTTPRequest::GET;
-       } else if (met.to_upper() == "POST") {
+       } else if (met == "POST") {
                req.method = HTTPRequest::POST;
        } else {
-               // FIXME - poner excepciones lindas.
-               throw "HTTP/1.1 501 Method Not Implemented";
+               throw HTTPError(HTTPMessage::NOT_IMPLEMENTED, met
+                               + ": No es un método soportado.");
        }
        // Si tiene sólo el método, no es válido.
        line = line.substr(pos + 1);
        line.trim();
        if (!line.length()) {
-               // FIXME - poner excepciones lindas.
-               throw "HTTP/1.1 400 Bad Request";
+               throw HTTPError(HTTPMessage::BAD_REQUEST, "Falta URI.");
        }
        // Si tiene más espacios, tengo la URI y el protocolo (o un error).
        pos = line.find_first_of(String::SPACE_CHARS);
        if (pos != string::npos) {
                // Si el resto es un protocolo válido, agrego más variables.
                String protocol = line.substr(pos + 1);
-               protocol = protocol.trim();
-               if (protocol.to_upper() == "HTTP/1.0") {
+               protocol = protocol.trim().to_upper();
+               if (protocol.substr(0, 5) != "HTTP/") {
+                       throw HTTPError(HTTPMessage::BAD_REQUEST,
+                                       protocol + ": Protocolo desconocido");
+               }
+               if (protocol.substr(5) == "1.0") {
                        req.version = "1.0";
-               } else if (protocol.to_upper() == "HTTP/1.1") {
+               } else if (protocol.substr(5) == "1.1") {
                        req.version = "1.1";
                // Si no es un error.
                } else {
-                       // FIXME - poner excepciones lindas.
-                       throw "HTTP/1.1 400 Bad Request";
+                       throw HTTPError(HTTPMessage::HTTP_VERSION_NOT_SUPPORTED,
+                                       protocol.substr(5) + ": Versión HTTP no soportada.");
                }
                line = line.substr(0, pos);
        }
        // Agrego la URI y sus derivados.
        if (!line.length() || (line[0] != '/')) {
                        // FIXME || request.find_first_not_of(";/?:@&=+$,")) {
-               // FIXME - poner excepciones lindas.
-               throw "HTTP/1.1 400 Bad Request";
+               throw HTTPError(HTTPMessage::BAD_REQUEST,
+                               line + ": La URI no comienza con /.");
        }
        // Si tiene un query string.
        pos = line.find("?");
@@ -154,7 +162,7 @@ ostream& operator<<(ostream& os, const HTTPRequest& req) {
        if (req.query.length()) {
                os << "?" << req.query;
        }
-       // TODO ver que este bien el \r\l
+       // TODO ver que este bien el \n/r
        os << " HTTP/" << req.version << "\n\r" << static_cast<const HTTPMessage&>(req);
        return os;
 }
index ab26bd3aff5c6a7198ac11cda624ca52a87609a8..562dbf9881f200291da337745bab5ad400ecd610 100644 (file)
@@ -51,42 +51,42 @@ HTTPResponse::HTTPResponse(const string& version):
 #endif // DEBUG
 }
 
-/*
-HTTPResponse::HTTPResponse(const Serializable& body,
-               const string& version):
-               HTTPMessage(body, version) {
+HTTPResponse::HTTPResponse(const HTTPError& error):
+               status_code(error.code) {
 #ifdef DEBUG
-       cerr << __FILE__ << ": http_version = " << http_version
-               << " | body = " << body.serialize() << endl;
+       cerr << __FILE__ << ": HTTPError(status_code = " << error.code
+               << ", reason = " << HTTPMessage::reason(error.code) << ", desc = " << error.what()
+               << ")" << endl;
 #endif // DEBUG
+       set_body(string("<plaqui><error desc=\"") + error.what() + "\" /></plaqui>");
 }
 
-HTTPResponse::HTTPResponse(const string& uri,
-               const HTTPResponse::HTTPMethod& method,
-               string& query, string& version):
-               HTTPMessage(body, version) {
+HTTPResponse::HTTPResponse(unsigned status_code, const string& body):
+               HTTPMessage(body), status_code(status_code) {
 #ifdef DEBUG
-       cerr << __FILE__ << ": http_version = " << http_version
-               << " | body = " << body.serialize() << endl;
+       cerr << __FILE__ << ": status_code = " << status_code
+               << " | body.length = " << body.length() << endl;
 #endif // DEBUG
 }
-*/
 
-istream& operator>>(istream& is, HTTPResponse& resp) {
+istream& operator>>(istream& is, HTTPResponse& resp)
+               throw (HTTPResponse::Error, ios::failure) {
 #ifdef DEBUG
        cerr << __FILE__ << ": operator>>()" << endl;
 #endif // DEBUG
        char buf[BUFSIZ];
        // Obtengo primera línea (request)
-       is.getline(buf, BUFSIZ);
+       if (!is.getline(buf, BUFSIZ)) {
+               // No hay mas líneas.
+               throw ios::failure("socket closed");
+       }
 #ifdef DEBUG
-       cerr << "Recibiendo linea: " << buf << endl;
+       cerr << __FILE__ << ":\tRecibiendo linea: " << buf << endl;
 #endif // DEBUG
        String line(buf);
        // Si es la primera línea, es el request.
-       if (line.to_upper().substr(0, 4) != "HTTP/") {
-               // FIXME - poner excepciones lindas.
-               throw "Not a HTTP response";
+       if (String(line.substr(0, 5)).to_upper() != "HTTP/") {
+               throw HTTPResponse::INVALID_HTTP_RESPONSE;
        }
        // Averiguo la versión.
        string::size_type pos = line.find_first_of(String::SPACE_CHARS, 5);
@@ -94,28 +94,26 @@ istream& operator>>(istream& is, HTTPResponse& resp) {
        if ((ver == "1.1") || (ver == "1.0")) {
                resp.version = ver;
        } else {
-               // FIXME - poner excepciones lindas.
-               throw "Invalid HTTP version";
+               throw HTTPResponse::INVALID_HTTP_VERSION;
        }
        // Si tiene sólo la versión HTTP, no es válido.
        line = line.substr(pos + 1);
        line.trim();
        if (!line.length()) {
-               // FIXME - poner excepciones lindas.
-               throw "Invalid HTTP response";
+               throw HTTPResponse::MISSING_HTTP_RESPONSE_CODE;
        }
        // Si tiene más espacios, tengo la razón (reason).
        pos = line.find_first_of(String::SPACE_CHARS);
        if (pos != string::npos) {
-               String r = line.substr(pos + 1);
-               resp.reason = r.trim();
+               //FIXME String r = line.substr(pos + 1);
+               //resp.reason = r.trim();
                line = line.substr(0, pos);
        }
        line = line.trim();
        // Seteo el código.
+       // TODO - chequear el codigo a ver si pertenece a uno definido en la RFC.
        if (line.length() != 3) {
-               // FIXME - poner excepciones lindas.
-               throw "Invalid response code";
+               throw HTTPResponse::INVALID_HTTP_RESPONSE_CODE;
        }
        stringstream ss;
        ss << line; // TODO ver forma mas linda de convertir
@@ -128,7 +126,8 @@ ostream& operator<<(ostream& os, const HTTPResponse& resp) {
 #ifdef DEBUG
        cerr << __FILE__ << ": operator<<()" << endl;
 #endif // DEBUG
-       os << "HTTP/" << resp.version << " " << resp.status_code << " " << resp.reason << "\n\r";
+       os << "HTTP/" << resp.version << " " << resp.status_code << " "
+               << HTTPMessage::reason(resp.status_code) << "\n\r";
        // TODO ver que este bien el \r\l
        os << static_cast<const HTTPMessage&>(resp);
        return os;
index 0439ca0d0e3f655011e90c9531d8e9eee485e1ff..49d0abb1bdf1de50129c778545fe8b438caa7196 100644 (file)
@@ -57,7 +57,7 @@ void Runnable::static_run(Runnable* runner) {
                << endl;
 #endif // DEBUG
        runner->real_run();
-       runner->signal_finished().emit();
+       runner->finished();
        delete runner;
 }
 
index a05285a60b8c8a5140b1a7a569df17df355333bd..73963babf8597e797f4a99d451992a1f9c114e85 100644 (file)
@@ -29,6 +29,8 @@
 #include "plaqui/server/connection.h"
 #include "plaqui/server/controlserver.h"
 #include <sigc++/class_slot.h>
+// FIXME - sacar sstream (a menos que se necesite)
+#include <sstream>
 #ifdef DEBUG
 #      include "plaqui/server/string.h"
 #      include <iostream>
@@ -72,7 +74,9 @@ Connection* Server::new_connection(
        ControlServer* connection = new ControlServer(sd);
        // TODO verificar si el new se hace bien? no creo.
        connection->signal_command_received().connect(
-                       SigC::slot_class(*this, &Server::on_control_command_received));
+                       SigC::bind<ControlServer*>(
+                               SigC::slot_class(*this, &Server::on_control_command_received),
+                               connection));
        // TODO: 
        return connection;
 }
@@ -88,14 +92,52 @@ bool Server::stop_transmission(string host, int port) {
 }
 
 /// \todo Implementar.
-void Server::on_control_command_received(const Command& command) {
+void Server::on_control_command_received(const Command& command,
+               ControlServer* server) {
 #ifdef DEBUG
        cerr << __FILE__ <<  ": on_control_command_received(target = "
                << command.get_target() << ", command = " << command.get_command()
                << ", args = [" << String::join(command.get_args(), ", ") << "])"
                << endl;
 #endif // DEBUG
-}
+       // TODO, seguir aca!
+       stringstream response_xml;
+       response_xml << "<html>" << endl;
+       response_xml << "    <head>" << endl;
+       response_xml << "        <title>PlaQui v0.4</title>" << endl;
+       response_xml << "    </head>" << endl;
+       response_xml << "    <body>" << endl;
+       response_xml << "        <h1>PlaQui</h1>" << endl;
+       response_xml << "        <p>versión 0.4</p>" << endl;
+       response_xml << "        <h2>Comando</h2>" << endl;
+       response_xml << "        <ul>" << endl;
+       response_xml << "           <li><b>Target:</b> " << command.get_target() << endl;
+       response_xml << "           <li><b>Command:</b> " << command.get_command() << endl;
+       response_xml << "           <li><b>Argumentos:</b>" << endl;
+       response_xml << "               <ol>" << endl;
+       for (Command::Arguments::const_iterator i = command.get_args().begin();
+                       i != command.get_args().end(); i++) {
+               response_xml << "                   <li>" << *i << "</li>" << endl;
+       }
+       response_xml << "               </ol>" << endl;
+       response_xml << "        </ul>" << endl;
+       response_xml << "        <h2>Desarrollado por</h2>" << endl;
+       response_xml << "        <ul>" << endl;
+       response_xml << "            <li>Nicolás Dimov.</li>" << endl;
+       response_xml << "            <li>Leandro Lucarella.</li>" << endl;
+       response_xml << "            <li>Ricardo Markiewicz.</li>" << endl;
+       response_xml << "        </ul>" << endl;
+       response_xml << "        <address>" << endl;
+       response_xml << "             Copyleft 2003 - bajo los " << endl;
+       response_xml << "             términos de la licencia GPL" << endl;
+       response_xml << "        </address>" << endl;
+       response_xml << "    </body>" << endl;
+       response_xml << "</html>" << endl;
+       HTTPResponse response(HTTPMessage::OK, response_xml.str());
+       response.headers["Content-Type"] = "text/html; charset=iso-8859-1";
+       //response.headers["Connection"] = "close";
+               server->send(response);
+       }
 
 } // namespace Server
 
index b38c7c2835e223eced26bc6fc2ea58533fa1ee23..97dd19f5123eee3d9de4fd23ed59ef1ca38c983c 100644 (file)
@@ -45,6 +45,9 @@ const string String::SPACE_CHARS = " \t\n\r";
 String::~String(void) {
 }
 
+String::String(void) {
+}
+
 String::String(const string& str):
                string(str.c_str()) {
 }
index 9d83135a2f48e1e3aca16604d489bf039e0192c8..8569c7ab9b292073e725b2cb539c3eeb24e0a646 100644 (file)
@@ -37,8 +37,6 @@ namespace PlaQui {
 
 namespace Server {
 
-const unsigned TCPServer::MAX_PENDING_CONNECTIONS = 10;
-
 TCPServer::~TCPServer(void) {
 #ifdef DEBUG
        cerr << __FILE__ <<  ": destructor." << endl;
@@ -61,8 +59,7 @@ TCPServer::TCPServer(int port):       socket(sockbuf::sock_stream) {
 #endif // DEBUG
 }
 
-void TCPServer::on_connection_finished(
-               Connection* connection) {
+void TCPServer::on_connection_finished(Connection* connection) {
 #ifdef DEBUG
        cerr << __FILE__ <<  ": on_connection_finished(connection = "
                << connection << ")" << endl;
index 8370f5423bbec67100aae21d485c413afb690c85..526d9228d060f832d6d4d483d5c888953b17bd69 100644 (file)
@@ -50,7 +50,7 @@ $(LIB_FILES)/server.a:
        cd $(LIB_FILES) && $(MAKE)
 
 # Tests
-server_test: $(LIB_FILES)/server.a server_test.cpp
+server_test: $(LIB_FILES)/server.a server_test.o
 
 clean:
        rm -f $(TARGETS) *.o