From: Leandro Lucarella Date: Mon, 20 Oct 2003 07:22:31 +0000 (+0000) Subject: - Se agregan 2 nuevas clases para parsear los request HTTP: String y Request. X-Git-Tag: svn_import~395 X-Git-Url: https://git.llucax.com/z.facultad/75.42/plaqui.git/commitdiff_plain/6e0194f46ac77c18bfeabf84ef94a32f23e41073?ds=inline - Se agregan 2 nuevas clases para parsear los request HTTP: String y Request. String extiende std::string y agrega métodos útiles a la hora de parsear. Request extiende a std::map y guarda variables sobre el request HTTP al estilo variables de entorno en CGI. - Se mueven los includes a un directorio plaqui/server porque string.h me pisaba el string.h de la libc. - Se usan las nuevas clases para obtener información básica sobre el request como para empezar a traducir las URI en comandos para la planta (o el servidor). --- diff --git a/Server/include/connection.h b/Server/include/plaqui/server/connection.h similarity index 98% rename from Server/include/connection.h rename to Server/include/plaqui/server/connection.h index df4cf2c..ef1fa24 100644 --- a/Server/include/connection.h +++ b/Server/include/plaqui/server/connection.h @@ -28,7 +28,7 @@ #ifndef PLAQUI_CONNECTION_H #define PLAQUI_CONNECTION_H -#include "runnable.h" +#include "plaqui/server/runnable.h" #include namespace Plaqui { diff --git a/Server/include/controlclient.h b/Server/include/plaqui/server/controlclient.h similarity index 98% rename from Server/include/controlclient.h rename to Server/include/plaqui/server/controlclient.h index adbfb5b..3b61edc 100644 --- a/Server/include/controlclient.h +++ b/Server/include/plaqui/server/controlclient.h @@ -28,7 +28,7 @@ #ifndef PLAQUI_CONTROLCLIENT_H #define PLAQUI_CONTROLCLIENT_H -#include "connection.h" +#include "plaqui/server/connection.h" #include namespace Plaqui { diff --git a/Server/include/controlserver.h b/Server/include/plaqui/server/controlserver.h similarity index 97% rename from Server/include/controlserver.h rename to Server/include/plaqui/server/controlserver.h index 28cd032..99f8dea 100644 --- a/Server/include/controlserver.h +++ b/Server/include/plaqui/server/controlserver.h @@ -28,7 +28,7 @@ #ifndef PLAQUI_CONTROLSERVER_H #define PLAQUI_CONTROLSERVER_H -#include "connection.h" +#include "plaqui/server/connection.h" #include namespace Plaqui { diff --git a/Server/include/receiver.h b/Server/include/plaqui/server/receiver.h similarity index 98% rename from Server/include/receiver.h rename to Server/include/plaqui/server/receiver.h index 6de8634..91c3014 100644 --- a/Server/include/receiver.h +++ b/Server/include/plaqui/server/receiver.h @@ -28,7 +28,7 @@ #ifndef PLAQUI_RECEIVER_H #define PLAQUI_RECEIVER_H -#include "connection.h" +#include "plaqui/server/connection.h" #include #include diff --git a/Server/include/plaqui/server/request.h b/Server/include/plaqui/server/request.h new file mode 100644 index 0000000..acc5091 --- /dev/null +++ b/Server/include/plaqui/server/request.h @@ -0,0 +1,96 @@ +// 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: dom oct 19 16:46:00 ART 2003 +// Autores: Leandro Lucarella +//---------------------------------------------------------------------------- +// +// $Id$ +// + +#ifndef PLAQUI_REQUEST_H +#define PLAQUI_REQUEST_H + +#include +#include + +namespace Plaqui { + + /// Conexión. + class Request: public std::map { + + protected: + + /// Caracteres dígitos para URIs (RFC 2396). + static const std::string CHARS_DIGIT; + + /// Caracteres alfabéticos en minúsculas para URIs (RFC 2396). + static const std::string CHARS_LOWALPHA; + + /// Caracteres alfabéticos en mayúsculas para URIs (RFC 2396). + static const std::string CHARS_UPALPHA; + + /// Caracteres alfabéticos para URIs (RFC 2396). + static const std::string CHARS_ALPHA; + + /// Caracteres alfabnuméricos para URIs (RFC 2396). + static const std::string CHARS_ALPHANUM; + + /// Caracteres reservados para URIs (RFC 2396). + static const std::string CHARS_RESERVED; + + /// Caracteres de marca para URIs (RFC 2396). + static const std::string CHARS_MARK; + + /// Caracteres no reservados para URIs (RFC 2396). + static const std::string CHARS_UNRESERVED; + + /// Caracteres no hexa para URIs (RFC 2396). + static const std::string CHARS_HEX; + + public: + + /** + * Destructor. + */ + virtual ~Request(void) {} + + /** + * Agrega variables con un request HTTP. + * + * \param req Petición HTTP (POST o GET). + * \param host Host remoto. + * \param port Puerto remoto. + */ + void set_request(const std::string& req, const std::string& host, + unsigned port); + + /** + * Procesa una cabecera para obtener nuevas "variables". + * + * \param header Cabecera HTTP. + */ + void parse_header(const std::string& header); + + }; + +} + +#endif // PLAQUI_REQUEST_H diff --git a/Server/include/runnable.h b/Server/include/plaqui/server/runnable.h similarity index 100% rename from Server/include/runnable.h rename to Server/include/plaqui/server/runnable.h diff --git a/Server/include/server.h b/Server/include/plaqui/server/server.h similarity index 97% rename from Server/include/server.h rename to Server/include/plaqui/server/server.h index eccbd9a..2364273 100644 --- a/Server/include/server.h +++ b/Server/include/plaqui/server/server.h @@ -28,8 +28,8 @@ #ifndef PLAQUI_SERVER_H #define PLAQUI_SERVER_H -#include "controlserver.h" -#include "transmitter.h" +#include "plaqui/server/controlserver.h" +#include "plaqui/server/transmitter.h" #include #include #include diff --git a/Server/include/plaqui/server/string.h b/Server/include/plaqui/server/string.h new file mode 100644 index 0000000..292055f --- /dev/null +++ b/Server/include/plaqui/server/string.h @@ -0,0 +1,76 @@ +// 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: dom oct 19 16:46:00 ART 2003 +// Autores: Leandro Lucarella +//---------------------------------------------------------------------------- +// +// $Id$ +// + +#ifndef PLAQUI_STRING_H +#define PLAQUI_STRING_H + +#include + +namespace Plaqui { + + /// Conexión. + class String: public std::string { + + public: + + /// Caracteres que son considerados espacios a la hora de parsear. + static const std::string SPACE_CHARS; + + /** + * Destructor. + */ + virtual ~String(void) {} + + /** + * Constructor. + * + * \param str String a copiar. + */ + String(const std::string& str); + + /** + * Elmina caracteres al inicio y fin de un string. + * + * \param c Lista de caracteres a eliminar. + */ + String& trim(const String& clist = SPACE_CHARS); + + /** + * Convierte a mayúsculas. + */ + String& to_upper(void); + + /** + * Convierte a mayúsculas. + */ + String& to_lower(void); + + }; + +} + +#endif // PLAQUI_STRING_H diff --git a/Server/include/transmitter.h b/Server/include/plaqui/server/transmitter.h similarity index 97% rename from Server/include/transmitter.h rename to Server/include/plaqui/server/transmitter.h index 2b622b8..faff2ef 100644 --- a/Server/include/transmitter.h +++ b/Server/include/plaqui/server/transmitter.h @@ -28,7 +28,7 @@ #ifndef PLAQUI_TRANSMITTER_H #define PLAQUI_TRANSMITTER_H -#include "connection.h" +#include "plaqui/server/connection.h" #include namespace Plaqui { diff --git a/Server/src/Makefile b/Server/src/Makefile index 07f6901..f1a4b83 100644 --- a/Server/src/Makefile +++ b/Server/src/Makefile @@ -26,10 +26,11 @@ # # Directorio con los .h -INCLUDE_DIR=../include +INCLUDE_BASE_DIR=../include +INCLUDE_DIR=$(INCLUDE_BASE_DIR)/plaqui/server # Opciones para el compilador. -CXXFLAGS=-ansi -pedantic -Wall -I$(INCLUDE_DIR) \ +CXXFLAGS=-ansi -pedantic -Wall -I$(INCLUDE_BASE_DIR) \ `pkg-config --cflags glibmm-2.0` `pkg-config --cflags gthread-2.0` CXXFLAGS+=-g -DDEBUG #CXXFLAGS+=-g @@ -42,6 +43,14 @@ TARGETS=server.a # Regla por defecto. all: $(TARGETS) +string_h=$(INCLUDE_DIR)/string.h +objects+=string.o +string.o: $(string_h) string.cpp + +request_h=$(string_h) $(INCLUDE_DIR)/request.h +objects+=request.o +request.o: $(request_h) request.cpp + runnable_h=$(INCLUDE_DIR)/runnable.h objects+=runnable.o runnable.o: $(runnable_h) runnable.cpp @@ -54,7 +63,7 @@ controlclient_h=$(connection_h) $(INCLUDE_DIR)/controlclient.h objects+=controlclient.o controlclient.o: $(controlclient_h) controlclient.cpp -controlserver_h=$(connection_h) $(INCLUDE_DIR)/controlserver.h +controlserver_h=$(connection_h) $(request_h) $(INCLUDE_DIR)/controlserver.h objects+=controlserver.o controlserver.o: $(controlserver_h) controlserver.cpp diff --git a/Server/src/connection.cpp b/Server/src/connection.cpp index 6d48727..44d74df 100644 --- a/Server/src/connection.cpp +++ b/Server/src/connection.cpp @@ -25,7 +25,7 @@ // $Id$ // -#include "connection.h" +#include "plaqui/server/connection.h" #include using namespace Plaqui; diff --git a/Server/src/controlclient.cpp b/Server/src/controlclient.cpp index 3ad70b6..62e693e 100644 --- a/Server/src/controlclient.cpp +++ b/Server/src/controlclient.cpp @@ -25,7 +25,7 @@ // $Id$ // -#include "controlclient.h" +#include "plaqui/server/controlclient.h" // XXX #include diff --git a/Server/src/controlserver.cpp b/Server/src/controlserver.cpp index 6ac3a77..69de3a7 100644 --- a/Server/src/controlserver.cpp +++ b/Server/src/controlserver.cpp @@ -25,7 +25,8 @@ // $Id$ // -#include "controlserver.h" +#include "plaqui/server/controlserver.h" +#include "plaqui/server/request.h" #include #include @@ -44,7 +45,9 @@ void ControlServer::real_run(void) { bool stop = false; char buf[BUFFER_SIZE]; while (!stop) { - stringstream sstr; + Request request; + // Primera línea no vacía (que debe ser el request). + bool is_first = true; while (!stop && socket.getline(buf, BUFFER_SIZE)) { #ifdef DEBUG std::cerr << "Reciviendo (crudo): " << buf << std::endl; @@ -61,18 +64,35 @@ void ControlServer::real_run(void) { std::cerr << std::hex << "Caracter: " << *buf << std::endl; } #endif // DEBUG - // Si tiene contenido, lo almaceno en el buffer de comandos. + // Si tiene contenido, lo agrego a la información del request. if (len) { - sstr << buf << endl; - // Si viene la línea vacía, terminan las cabeceras HTTP. + // Si es la primera línea, es el request. + if (is_first) { + request.set_request(buf, socket->peerhost(), + socket->peerport()); + is_first = false; + } else { + // TODO request.parse_header(buf); + } + // Si viene la línea vacía } else { - stop = true; + // Si no es la primera, terminan las cabeceras HTTP. + if (!is_first) { + // Podría ir un break. + stop = true; + continue; + } + // Si es la primera, no pasa nada, sigue esperando un request. } } // Manda mensaje a la planta. //dispatch_command(parse_command(sstr.str())); #ifdef DEBUG - std::cerr << "Recivido:" << std::endl << sstr.str() << std::endl; + std::cerr << "Request: " << std::endl; + for (Request::const_iterator i = request.begin(); i != request.end(); + i++) { + std::cerr << " " << i->first << ": " << i->second << std::endl; + } #endif // DEBUG // FIXME - hacer respuesta XML. stringstream response_xml; @@ -91,8 +111,16 @@ Accept-Ranges: bytes response_xml << " " << std::endl; response_xml << " " << std::endl; response_xml << "

PlaQui

" << std::endl; - response_xml << "

versión 0.1

" << std::endl; - response_xml << "

Desarrollado por

" << std::endl; + response_xml << "

versión 0.2

" << std::endl; + response_xml << "

Pedido HTTP

" << std::endl; + response_xml << "
    " << std::endl; + for (Request::const_iterator i = request.begin(); i != request.end(); + i++) { + response_xml << "
  • " << i->first << ": " + << i->second << std::endl; + } + response_xml << "
" << std::endl; + response_xml << "

Desarrollado por

" << std::endl; response_xml << "
    " << std::endl; response_xml << "
  • Nicolás Dimov.
  • " << std::endl; response_xml << "
  • Leandro Lucarella.
  • " << std::endl; @@ -104,7 +132,7 @@ Accept-Ranges: bytes response_xml << " " << std::endl; response_xml << " " << std::endl; response_xml << "" << std::endl; - //socket << "Content-Length: " << response_xml.str().length() << std::endl; + socket << "Content-Length: " << response_xml.str().length() << std::endl; socket << std::endl; socket << response_xml.str() << std::flush; } diff --git a/Server/src/receiver.cpp b/Server/src/receiver.cpp index 0f9f32c..4f720f4 100644 --- a/Server/src/receiver.cpp +++ b/Server/src/receiver.cpp @@ -25,7 +25,7 @@ // $Id$ // -#include "receiver.h" +#include "plaqui/server/receiver.h" using namespace Plaqui; diff --git a/Server/src/request.cpp b/Server/src/request.cpp new file mode 100644 index 0000000..1eb8b0b --- /dev/null +++ b/Server/src/request.cpp @@ -0,0 +1,129 @@ +// 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: dom oct 19 16:41:15 ART 2003 +// Autores: Leandro Lucarella +//---------------------------------------------------------------------------- +// +// $Id$ +// + +#include "plaqui/server/request.h" +#include "plaqui/server/string.h" +#include +#include +#include +#ifdef DEBUG +# include +#endif // DEBUG + +using namespace Plaqui; + +const std::string Request::CHARS_DIGIT = "0123456789"; + +const std::string Request::CHARS_LOWALPHA = "abcdefghijklmnopqrstuvwxyz"; + +const std::string Request::CHARS_UPALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +const std::string Request::CHARS_ALPHA = CHARS_LOWALPHA + CHARS_UPALPHA; + +const std::string Request::CHARS_ALPHANUM = CHARS_DIGIT + CHARS_ALPHA; + +const std::string Request::CHARS_RESERVED = ";/?:@&=+$,"; + +const std::string Request::CHARS_MARK = "-_.!~*'()"; + +const std::string Request::CHARS_UNRESERVED = CHARS_ALPHANUM + CHARS_MARK; + +const std::string Request::CHARS_HEX = CHARS_DIGIT + std::string("abcdefABCDEF"); + +void Request::set_request(const std::string& req, const std::string& host, + unsigned port) { +#ifdef DEBUG + std::cerr << __FILE__ << ": req = " << req << " | host = " << host + << " | port = " << port << std::endl; +#endif // DEBUG + String request(req); + (*this)["REMOTE_HOST"] = host; + std::stringstream ss; + ss << port; + (*this)["REMOTE_PORT"] = ss.str(); + // Parseo el GET de forma rudimentaria. + if (request.length() < 3) { + // FIXME - poner excepciones lindas. + throw "HTTP/1.1 501 Method Not Implemented"; + } + // Averiguo método. + std::string::size_type pos = request.find_first_of(String::SPACE_CHARS); + String method = request.substr(0, pos); + if ((method.to_upper() == "GET") || (method.to_upper() == "POST")) { + (*this)["REQUEST_METHOD"] = method; + } else { + // FIXME - poner excepciones lindas. + throw "HTTP/1.1 501 Method Not Implemented"; + } + // Si tiene sólo el método, no es válido. + request = request.substr(pos + 1); + request.trim(); + if (!request.length()) { + // FIXME - poner excepciones lindas. + throw "HTTP/1.1 400 Bad Request"; + } + // Si tiene más espacios, tengo la URI y el protocolo (o un error). + pos = request.find_first_of(String::SPACE_CHARS); + if (pos != std::string::npos) { + // Si el resto es un protocolo válido, agrego más variables. + String protocol = request.substr(pos + 1); + protocol = protocol.trim(); + if ((String(protocol).to_upper() == "HTTP/1.0") + || (String(protocol).to_upper() == "HTTP/1.1")) { + (*this)["SERVER_PROTOCOL"] = protocol; + // Si no es un error. + } else { + // FIXME - poner excepciones lindas. + throw "HTTP/1.1 400 Bad Request"; + } + request = request.substr(0, pos); + } + // Agrego la URI y sus derivados. + if (!request.length() || (request[0] != '/')) { + // FIXME || request.find_first_not_of(";/?:@&=+$,")) { + // FIXME - poner excepciones lindas. + throw "HTTP/1.1 400 Bad Request"; + } + (*this)["REQUEST_URI"] = request; + // Si tiene un query string. + pos = request.find("?"); + if (pos != std::string::npos) { + (*this)["QUERY_STRING"] = request.substr(pos + 1); + // No tiene query string. + } else { + (*this)["QUERY_STRING"] = ""; + } + (*this)["SCRIPT_NAME"] = request.substr(0, pos); +} + +void Request::parse_header(const std::string& header) { +#ifdef DEBUG + std::cerr << __FILE__ << ": header = " << header << std::endl; +#endif // DEBUG + +} + diff --git a/Server/src/runnable.cpp b/Server/src/runnable.cpp index d962980..0e8b4bd 100644 --- a/Server/src/runnable.cpp +++ b/Server/src/runnable.cpp @@ -25,7 +25,7 @@ // $Id$ // -#include "runnable.h" +#include "plaqui/server/runnable.h" #include #include #ifdef DEBUG diff --git a/Server/src/server.cpp b/Server/src/server.cpp index c0d0341..6507d6d 100644 --- a/Server/src/server.cpp +++ b/Server/src/server.cpp @@ -25,7 +25,7 @@ // $Id$ // -#include "server.h" +#include "plaqui/server/server.h" #ifdef DEBUG # include #endif // DEBUG diff --git a/Server/src/string.cpp b/Server/src/string.cpp new file mode 100644 index 0000000..caa657b --- /dev/null +++ b/Server/src/string.cpp @@ -0,0 +1,57 @@ +// 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: dom oct 19 16:41:15 ART 2003 +// Autores: Leandro Lucarella +//---------------------------------------------------------------------------- +// +// $Id$ +// + +#include "plaqui/server/string.h" +#include +#include +#ifdef DEBUG +# include +#endif // DEBUG + +using namespace Plaqui; + +const std::string String::SPACE_CHARS = " \t\n\r"; + +String::String(const std::string& str): std::string(str.c_str()) { +} + +String& String::trim(const String& clist) { + erase(0, find_first_not_of(clist)); + erase(find_last_not_of(clist) + 1); + return *this; +} + +String& String::to_lower(void) { + std::transform(begin(), end(), begin(), tolower); + return *this; +} + +String& String::to_upper(void) { + std::transform(begin(), end(), begin(), toupper); + return *this; +} + diff --git a/Server/src/transmitter.cpp b/Server/src/transmitter.cpp index bd6d06b..d4306e3 100644 --- a/Server/src/transmitter.cpp +++ b/Server/src/transmitter.cpp @@ -25,7 +25,7 @@ // $Id$ // -#include "transmitter.h" +#include "plaqui/server/transmitter.h" #include #include diff --git a/Server/tests/Makefile b/Server/tests/Makefile index 8933af6..c3acd4d 100644 --- a/Server/tests/Makefile +++ b/Server/tests/Makefile @@ -26,13 +26,14 @@ # # Ubicación de archivos .h -INCLUDE_FILES=../include +INCLUDE_BASE_DIR=../include +INCLUDE_DIR=$(INCLUDE_BASE_DIR) # Ubicación de archivos .a LIB_FILES=../src # Opciones para el compilador. -CXXFLAGS=-ansi -pedantic -Wall -I$(INCLUDE_FILES) \ +CXXFLAGS=-ansi -pedantic -Wall -I$(INCLUDE_DIR) \ `pkg-config --cflags glibmm-2.0` `pkg-config --cflags gthread-2.0` CXXFLAGS+=-g -DDEBUG #CXXFLAGS+=-g diff --git a/Server/tests/server_test.cpp b/Server/tests/server_test.cpp index e0753b9..2e16935 100644 --- a/Server/tests/server_test.cpp +++ b/Server/tests/server_test.cpp @@ -25,7 +25,7 @@ // $Id$ // -#include "server.h" +#include "plaqui/server/server.h" #include #include #include