# include <iostream>
#endif // DEBUG
-PlaQui::Server::HTTPRequest::~HTTPRequest(void) {
-#ifdef DEBUG
- std::cerr << __FILE__ << ": destructor." << std::endl;
-#endif // DEBUG
-}
+using namespace std;
-PlaQui::Server::HTTPRequest::HTTPRequest(const std::string& version):
- PlaQui::Server::HTTPMessage(version) {
-#ifdef DEBUG
- std::cerr << __FILE__ << ": http_version = " << http_version << std::endl;
-#endif // DEBUG
-}
+namespace PlaQui {
-PlaQui::Server::HTTPRequest::HTTPRequest(const Serializable& body,
- const std::string& version):
- PlaQui::Server::HTTPMessage(body, version) {
+namespace Server {
+
+HTTPRequest::~HTTPRequest(void) {
#ifdef DEBUG
- std::cerr << __FILE__ << ": http_version = " << http_version
- << " | body = " << body.serialize() << std::endl;
+ cerr << __FILE__ << ": destructor." << endl;
#endif // DEBUG
}
-PlaQui::Server::HTTPRequest::HTTPRequest(const std::string& uri,
- const PlaQui::Server::HTTPRequest::HTTPMethod& method,
- std::string& query, std::string& version):
- PlaQui::Server::HTTPMessage(body, version) {
+HTTPRequest::HTTPRequest(const string& uri, const HTTPMethod& method,
+ const string& query, const string& body, const string& version):
+ HTTPMessage(body, version), method(method), uri(uri), query(query) {
#ifdef DEBUG
- std::cerr << __FILE__ << ": http_version = " << http_version
- << " | body = " << body.serialize() << std::endl;
+ cerr << __FILE__ << ": uri = " << uri << " | "
+ << "method = " << method_str() << " | "
+ << "query = " << query << " | "
+ << "body.length = " << body.length() << " | "
+ << "version = " << version << endl;
#endif // DEBUG
}
-void PlaQui::Server::HTTPRequest::serialize(std::ostream& os) {
-#ifdef DEBUG
- std::cerr << __FILE__ << ": serialize()" << std::endl;
-#endif // DEBUG
- os << method << " " << uri;
- if (query_string.length()) {
- os << "?" << query;
- }
- os << "HTTP/" << version << "\r\l" << std::flush; // TODO ver que este bien el \r\l
- HTTPMessage::serilize(os);
- if (headers.size()) {
- headers.serilize(os);
- }
- os << "\r\l" << std::flush;
- if (body.size()) {
- body.serilize(os);
+string HTTPRequest::method_str(void) const {
+ switch (method) {
+ case POST:
+ return "POST";
+ case GET:
+ default:
+ return "GET";
}
}
-void PlaQui::Server::HTTPRequest::unserialize(std::istream& is) {
- const unsigned BUFFER_SIZE = 4096;
- char buf[BUFFER_SIZE];
+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, BUFFER_SIZE);
+ if (!is.getline(buf, BUFSIZ)) {
+ // No hay más líneas.
+ throw ios::failure("socket closed");
+ }
#ifdef DEBUG
- std::cerr << "Recibiendo linea: " << buf << std::endl;
+ cerr << __FILE__ << ":\tRecibiendo linea: " << buf << endl;
#endif // DEBUG
- String line = buf;
+ 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.
- std::string::size_type pos = line.find_first_of(String::SPACE_CHARS);
+ string::size_type pos = line.find_first_of(String::SPACE_CHARS);
String met = line.substr(0, pos);
- if (met.to_upper() == "GET") {
- method = GET;
- } else if (met.to_upper() == "POST") {
- method = POST;
+ met.to_upper();
+ if (met == "GET") {
+ req.method = HTTPRequest::GET;
+ } 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);
- iine.trim();
+ 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 != std::string::npos) {
+ 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") {
- version = "1.0";
- } else if (protocol.to_upper() == "HTTP/1.1") {
- version = "1.1";
+ 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.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 = request.find("?");
- if (pos != std::string::npos) {
- query = line.substr(pos + 1);
+ pos = line.find("?");
+ if (pos != string::npos) {
+ req.query = line.substr(pos + 1);
} else {
- query = "";
+ req.query = "";
}
- uri = line.substr(0, pos);
- // Fin de request, obtengo cabeceras y cuerpo.
- HTTPMessage::unserialize(is);
+ req.uri = line.substr(0, pos);
+ // Fin de request, obtengo el mensaje.
+ is >> static_cast<HTTPMessage&>(req);
+ //PlaQui::Server::operator>>(is, static_cast<HTTPMessage>(req));
+ return is;
}
+ostream& operator<<(ostream& os, const HTTPRequest& req) {
+#ifdef DEBUG
+ cerr << __FILE__ << ": operator<<()" << endl;
+#endif // DEBUG
+ os << req.method_str() << " " << req.uri;
+ if (req.query.length()) {
+ os << "?" << req.query;
+ }
+ os << " HTTP/" << req.version << "\r\n"
+ << static_cast<const HTTPMessage&>(req);
+ return os;
+}
+
+} // namespace Server
+
+} // namespace PlaQui
+