From f27c218d18ebf7198e07249aca1eed625da914fd Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 12 Nov 2003 03:36:58 +0000 Subject: [PATCH] =?utf8?q?Pocos=20cambios=20a=20la=20vista=20del=20"usuari?= =?utf8?q?o":=20-=20Ya=20se=20env=C3=ADan=20comandos=20con=20la=20se=C3=B1?= =?utf8?q?al=20command=5Freceived()=20apropiadamente.=20-=20Las=20respuest?= =?utf8?q?as=20son=20asincr=C3=B3nicas,=20ya=20que=20los=20comandos=20van?= =?utf8?q?=20a=20encolarse=20para=20=20=20esperar=20que=20el=20modelo=20se?= =?utf8?q?=20actulice.=20-=20Ya=20se=20pueden=20enviar=20respuestas=20via?= =?utf8?q?=20ControlServer::send().=20Muchos=20cambios=20internos=20entre?= =?utf8?q?=20los=20que=20se=20destacan=20el=20correcto=20funcionamiento=20?= =?utf8?q?de=20las=20excepciones=20(que=20ven=C3=ADa=20postergado).?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- Server/include/plaqui/server/controlclient.h | 9 +++ Server/include/plaqui/server/controlserver.h | 10 +++ Server/include/plaqui/server/httperror.h | 70 ++++++++++++++++++++ Server/include/plaqui/server/httpheaders.h | 6 +- Server/include/plaqui/server/httpmessage.h | 25 ++++++- Server/include/plaqui/server/httprequest.h | 6 +- Server/include/plaqui/server/httpresponse.h | 22 ++++-- Server/include/plaqui/server/server.h | 3 +- Server/include/plaqui/server/string.h | 5 ++ Server/include/plaqui/server/tcpserver.h | 8 ++- Server/src/Makefile | 6 +- Server/src/controlserver.cpp | 59 +++++++++-------- Server/src/httperror.cpp | 55 +++++++++++++++ Server/src/httpheaders.cpp | 5 +- Server/src/httpmessage.cpp | 41 +++++++----- Server/src/httprequest.cpp | 46 +++++++------ Server/src/httpresponse.cpp | 55 ++++++++------- Server/src/runnable.cpp | 2 +- Server/src/server.cpp | 48 +++++++++++++- Server/src/string.cpp | 3 + Server/src/tcpserver.cpp | 5 +- Server/tests/Makefile | 2 +- 22 files changed, 375 insertions(+), 116 deletions(-) create mode 100644 Server/include/plaqui/server/httperror.h create mode 100644 Server/src/httperror.cpp diff --git a/Server/include/plaqui/server/controlclient.h b/Server/include/plaqui/server/controlclient.h index 73acdcf..faf3a27 100644 --- a/Server/include/plaqui/server/controlclient.h +++ b/Server/include/plaqui/server/controlclient.h @@ -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: /** diff --git a/Server/include/plaqui/server/controlserver.h b/Server/include/plaqui/server/controlserver.h index 5b6eb23..7c5ea6e 100644 --- a/Server/include/plaqui/server/controlserver.h +++ b/Server/include/plaqui/server/controlserver.h @@ -30,7 +30,9 @@ #include "plaqui/server/connection.h" #include "plaqui/server/command.h" +#include "plaqui/server/httpresponse.h" #include +#include 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 index 0000000..1cc4ee8 --- /dev/null +++ b/Server/include/plaqui/server/httperror.h @@ -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 +//---------------------------------------------------------------------------- +// +// $Id$ +// + +#ifndef PLAQUI_HTTPERROR_H +#define PLAQUI_HTTPERROR_H + +#include +#include +#include +#include + +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 diff --git a/Server/include/plaqui/server/httpheaders.h b/Server/include/plaqui/server/httpheaders.h index 1a9c5aa..86a2dd1 100644 --- a/Server/include/plaqui/server/httpheaders.h +++ b/Server/include/plaqui/server/httpheaders.h @@ -28,6 +28,7 @@ #ifndef PLAQUI_HTTPHEADERS_H #define PLAQUI_HTTPHEADERS_H +#include "plaqui/server/httperror.h" #include #include #include @@ -40,6 +41,8 @@ namespace Server { /// Cabeceras HTTP. class HTTPHeaders: public std::map { + // 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. diff --git a/Server/include/plaqui/server/httpmessage.h b/Server/include/plaqui/server/httpmessage.h index 938f9ad..730bf0a 100644 --- a/Server/include/plaqui/server/httpmessage.h +++ b/Server/include/plaqui/server/httpmessage.h @@ -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); + }; } diff --git a/Server/include/plaqui/server/httprequest.h b/Server/include/plaqui/server/httprequest.h index ace04f0..a5a3647 100644 --- a/Server/include/plaqui/server/httprequest.h +++ b/Server/include/plaqui/server/httprequest.h @@ -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 #include #include @@ -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. diff --git a/Server/include/plaqui/server/httpresponse.h b/Server/include/plaqui/server/httpresponse.h index f5c0afd..bc8f900 100644 --- a/Server/include/plaqui/server/httpresponse.h +++ b/Server/include/plaqui/server/httpresponse.h @@ -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 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. diff --git a/Server/include/plaqui/server/server.h b/Server/include/plaqui/server/server.h index e66be38..8c92ca8 100644 --- a/Server/include/plaqui/server/server.h +++ b/Server/include/plaqui/server/server.h @@ -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); }; diff --git a/Server/include/plaqui/server/string.h b/Server/include/plaqui/server/string.h index 74c27cd..ecd253a 100644 --- a/Server/include/plaqui/server/string.h +++ b/Server/include/plaqui/server/string.h @@ -48,6 +48,11 @@ namespace Server { */ virtual ~String(void); + /** + * Constructor. + */ + String(void); + /** * Constructor. * diff --git a/Server/include/plaqui/server/tcpserver.h b/Server/include/plaqui/server/tcpserver.h index 393f4cc..7465faa 100644 --- a/Server/include/plaqui/server/tcpserver.h +++ b/Server/include/plaqui/server/tcpserver.h @@ -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 ConnectionList; diff --git a/Server/src/Makefile b/Server/src/Makefile index 0403d20..2337cb4 100644 --- a/Server/src/Makefile +++ b/Server/src/Makefile @@ -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 diff --git a/Server/src/controlserver.cpp b/Server/src/controlserver.cpp index c5e163f..f5c6c73 100644 --- a/Server/src/controlserver.cpp +++ b/Server/src/controlserver.cpp @@ -27,10 +27,12 @@ #include "plaqui/server/controlserver.h" #include "plaqui/server/command.h" -#include "plaqui/server/string.h" -#include -#include +#include "plaqui/server/httperror.h" +#include "plaqui/server/httpresponse.h" +//#include +//#include #ifdef DEBUG +# include "plaqui/server/string.h" # include #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 << "" << endl; response_xml << " " << endl; @@ -140,15 +148,6 @@ Accept-Ranges: bytes response_xml << "

versión 0.4

" << endl; response_xml << "

Comando

" << endl; response_xml << "
    " << endl; -/* response_xml << "
  • Versión: " << request.version << endl; - response_xml << "
  • Método: " << (request.method ? "POST" : "GET") << endl; - response_xml << "
  • URI: " << request.uri << endl; - response_xml << "
  • Query: " << request.query << endl; - for (HTTPHeaders::const_iterator i = request.headers.begin(); - i != request.headers.end(); i++) { - response_xml << "
  • " << i->first << ": " - << i->second << endl; - }*/ response_xml << "
  • Target: " << command.get_target() << endl; response_xml << "
  • Command: " << command.get_command() << endl; response_xml << "
  • Argumentos:" << 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 index 0000000..b00ded5 --- /dev/null +++ b/Server/src/httperror.cpp @@ -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 +//---------------------------------------------------------------------------- +// +// $Id$ +// + +#include "plaqui/server/httperror.h" +#ifdef DEBUG +# include +#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 + diff --git a/Server/src/httpheaders.cpp b/Server/src/httpheaders.cpp index 65d5adc..0ec62e1 100644 --- a/Server/src/httpheaders.cpp +++ b/Server/src/httpheaders.cpp @@ -26,6 +26,7 @@ // #include "plaqui/server/httpheaders.h" +#include "plaqui/server/httperror.h" #include "plaqui/server/string.h" //#include #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 diff --git a/Server/src/httpmessage.cpp b/Server/src/httpmessage.cpp index cfdd894..af2875e 100644 --- a/Server/src/httpmessage.cpp +++ b/Server/src/httpmessage.cpp @@ -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 diff --git a/Server/src/httprequest.cpp b/Server/src/httprequest.cpp index aa5d9cc..f1119fd 100644 --- a/Server/src/httprequest.cpp +++ b/Server/src/httprequest.cpp @@ -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(req); return os; } diff --git a/Server/src/httpresponse.cpp b/Server/src/httpresponse.cpp index ab26bd3..562dbf9 100644 --- a/Server/src/httpresponse.cpp +++ b/Server/src/httpresponse.cpp @@ -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(""); } -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(resp); return os; diff --git a/Server/src/runnable.cpp b/Server/src/runnable.cpp index 0439ca0..49d0abb 100644 --- a/Server/src/runnable.cpp +++ b/Server/src/runnable.cpp @@ -57,7 +57,7 @@ void Runnable::static_run(Runnable* runner) { << endl; #endif // DEBUG runner->real_run(); - runner->signal_finished().emit(); + runner->finished(); delete runner; } diff --git a/Server/src/server.cpp b/Server/src/server.cpp index a05285a..73963ba 100644 --- a/Server/src/server.cpp +++ b/Server/src/server.cpp @@ -29,6 +29,8 @@ #include "plaqui/server/connection.h" #include "plaqui/server/controlserver.h" #include +// FIXME - sacar sstream (a menos que se necesite) +#include #ifdef DEBUG # include "plaqui/server/string.h" # include @@ -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( + 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 << "" << endl; + response_xml << " " << endl; + response_xml << " PlaQui v0.4" << endl; + response_xml << " " << endl; + response_xml << " " << endl; + response_xml << "

    PlaQui

    " << endl; + response_xml << "

    versión 0.4

    " << endl; + response_xml << "

    Comando

    " << endl; + response_xml << "
      " << endl; + response_xml << "
    • Target: " << command.get_target() << endl; + response_xml << "
    • Command: " << command.get_command() << endl; + response_xml << "
    • Argumentos:" << endl; + response_xml << "
        " << endl; + for (Command::Arguments::const_iterator i = command.get_args().begin(); + i != command.get_args().end(); i++) { + response_xml << "
      1. " << *i << "
      2. " << endl; + } + response_xml << "
      " << endl; + response_xml << "
    " << endl; + response_xml << "

    Desarrollado por

    " << endl; + response_xml << "
      " << endl; + response_xml << "
    • Nicolás Dimov.
    • " << endl; + response_xml << "
    • Leandro Lucarella.
    • " << endl; + response_xml << "
    • Ricardo Markiewicz.
    • " << endl; + response_xml << "
    " << endl; + response_xml << "
    " << endl; + response_xml << " Copyleft 2003 - bajo los " << endl; + response_xml << " términos de la licencia GPL" << endl; + response_xml << "
    " << endl; + response_xml << " " << endl; + response_xml << "" << 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 diff --git a/Server/src/string.cpp b/Server/src/string.cpp index b38c7c2..97dd19f 100644 --- a/Server/src/string.cpp +++ b/Server/src/string.cpp @@ -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()) { } diff --git a/Server/src/tcpserver.cpp b/Server/src/tcpserver.cpp index 9d83135..8569c7a 100644 --- a/Server/src/tcpserver.cpp +++ b/Server/src/tcpserver.cpp @@ -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; diff --git a/Server/tests/Makefile b/Server/tests/Makefile index 8370f54..526d922 100644 --- a/Server/tests/Makefile +++ b/Server/tests/Makefile @@ -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 -- 2.43.0