String extiende std::string y agrega métodos útiles a la hora de parsear.
Request extiende a std::map<std::string, std::string> 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).
#ifndef PLAQUI_CONNECTION_H
#define PLAQUI_CONNECTION_H
-#include "runnable.h"
+#include "plaqui/server/runnable.h"
#include <socket++/sockinet.h>
namespace Plaqui {
#ifndef PLAQUI_CONTROLCLIENT_H
#define PLAQUI_CONTROLCLIENT_H
-#include "connection.h"
+#include "plaqui/server/connection.h"
#include <string>
namespace Plaqui {
#ifndef PLAQUI_CONTROLSERVER_H
#define PLAQUI_CONTROLSERVER_H
-#include "connection.h"
+#include "plaqui/server/connection.h"
#include <socket++/sockinet.h>
namespace Plaqui {
#ifndef PLAQUI_RECEIVER_H
#define PLAQUI_RECEIVER_H
-#include "connection.h"
+#include "plaqui/server/connection.h"
#include <socket++/sockinet.h>
#include <string>
--- /dev/null
+// 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 <llucare@fi.uba.ar>
+//----------------------------------------------------------------------------
+//
+// $Id$
+//
+
+#ifndef PLAQUI_REQUEST_H
+#define PLAQUI_REQUEST_H
+
+#include <map>
+#include <string>
+
+namespace Plaqui {
+
+ /// Conexión.
+ class Request: public std::map<std::string, std::string> {
+
+ 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
#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 <socket++/sockinet.h>
#include <string>
#include <list>
--- /dev/null
+// 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 <llucare@fi.uba.ar>
+//----------------------------------------------------------------------------
+//
+// $Id$
+//
+
+#ifndef PLAQUI_STRING_H
+#define PLAQUI_STRING_H
+
+#include <string>
+
+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
#ifndef PLAQUI_TRANSMITTER_H
#define PLAQUI_TRANSMITTER_H
-#include "connection.h"
+#include "plaqui/server/connection.h"
#include <string>
namespace Plaqui {
#
# 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
# 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
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
// $Id$
//
-#include "connection.h"
+#include "plaqui/server/connection.h"
#include <socket++/sockinet.h>
using namespace Plaqui;
// $Id$
//
-#include "controlclient.h"
+#include "plaqui/server/controlclient.h"
// XXX
#include <iostream>
// $Id$
//
-#include "controlserver.h"
+#include "plaqui/server/controlserver.h"
+#include "plaqui/server/request.h"
#include <cstring>
#include <sstream>
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;
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;
response_xml << " </head>" << std::endl;
response_xml << " <body>" << std::endl;
response_xml << " <h1>PlaQui</h1>" << std::endl;
- response_xml << " <p>versión 0.1</p>" << std::endl;
- response_xml << " <h3>Desarrollado por</h3>" << std::endl;
+ response_xml << " <p>versión 0.2</p>" << std::endl;
+ response_xml << " <h2>Pedido HTTP</h2>" << std::endl;
+ response_xml << " <ul>" << std::endl;
+ for (Request::const_iterator i = request.begin(); i != request.end();
+ i++) {
+ response_xml << " <li><b>" << i->first << ":</b> "
+ << i->second << std::endl;
+ }
+ response_xml << " </ul>" << std::endl;
+ response_xml << " <h2>Desarrollado por</h2>" << std::endl;
response_xml << " <ul>" << std::endl;
response_xml << " <li>Nicolás Dimov.</li>" << std::endl;
response_xml << " <li>Leandro Lucarella.</li>" << std::endl;
response_xml << " </address>" << std::endl;
response_xml << " </body>" << std::endl;
response_xml << "</html>" << 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;
}
// $Id$
//
-#include "receiver.h"
+#include "plaqui/server/receiver.h"
using namespace Plaqui;
--- /dev/null
+// 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 <llucare@fi.uba.ar>
+//----------------------------------------------------------------------------
+//
+// $Id$
+//
+
+#include "plaqui/server/request.h"
+#include "plaqui/server/string.h"
+#include <sstream>
+#include <cctype>
+#include <algorithm>
+#ifdef DEBUG
+# include <iostream>
+#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
+
+}
+
// $Id$
//
-#include "runnable.h"
+#include "plaqui/server/runnable.h"
#include <sigc++/class_slot.h>
#include <glibmm/thread.h>
#ifdef DEBUG
// $Id$
//
-#include "server.h"
+#include "plaqui/server/server.h"
#ifdef DEBUG
# include <iostream>
#endif // DEBUG
--- /dev/null
+// 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 <llucare@fi.uba.ar>
+//----------------------------------------------------------------------------
+//
+// $Id$
+//
+
+#include "plaqui/server/string.h"
+#include <cctype>
+#include <algorithm>
+#ifdef DEBUG
+# include <iostream>
+#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;
+}
+
// $Id$
//
-#include "transmitter.h"
+#include "plaqui/server/transmitter.h"
#include <socket++/sockinet.h>
#include <string>
#
# 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
// $Id$
//
-#include "server.h"
+#include "plaqui/server/server.h"
#include <socket++/sockinet.h>
#include <iostream>
#include <sstream>