From: <mik...@us...> - 2003-12-26 22:56:46
|
Update of /cvsroot/sharedaemon/sharedaemon-ui-web/src/server/http In directory sc8-pr-cvs1:/tmp/cvs-serv3848/src/server/http Added Files: HttpConstants.h HttpResponse.h TextWriter.cpp Writer.h HttpConstants.cpp TextWriter.h HttpServerSocket.cpp HttpResponse.cpp HttpRequest.cpp HttpSocket.h HttpSocket.cpp HttpRequest.h HttpServerSocket.h Log Message: 26/12/2003 Mikael Barbeaux * Added a test program for Http sockets. * Fixed a problem about accepting sockets which were an infinite process. * Implemented main http controls : HttpRequest, HttpResponse, HttpSocket, HttpServerSocket and Writers --- NEW FILE: HttpConstants.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _HTTP_CONSTANTS_H_ #define _HTTP_CONSTANTS_H_ #include <string> #include <sstream> #include <map> using namespace std; /** * Http Methods */ enum HttpMethod { GET, POST, HEAD, UNKNOWN }; /** * Http response codes */ enum HttpResponseCode { ACCEPTED = 200, // request accepted BAD_GATEWAY = 502, // bad gateway BAD_METHOD = 405, // method not allowed BAD_REQUEST = 400, // bad request CLIENT_TIMEOUT = 408, // request timeout CONFLIT = 409, // conflit CREATED = 201, // created ENTITY_TOO_LARGE = 413, // request entity too large FORBIDDEN = 403, // forbidden GATEWAY_TIMEOUT = 504, // gateway timeout GONE = 410, // gone INTERNAL_ERROR = 500, // internal error LENGTH_REQUIRED = 411, // length required MOVED_PERM = 301, // moved permanently MOVED_TEMP = 302, // moved temporary MULT_CHOICE = 300, // Multiple choice NO_CONTENT = 204, // no content NO_ACCEPTABLE = 406, // not acceptable NOT_AUTHORITATIVE = 203, // no authoritative information NOT_FOUND = 404, // not found NOT_IMPLEMENTED = 501, // not implemented NOT_MODIFIED = 304, // not modified OK = 200, // ok PARTIAL = 206, // partial content PAYMENT_REQUIRED = 402, // payment required PRECON_FAILED = 412, // precondiion failed PROXY_AUTH = 407, // proxy authentification required REQ_TOO_LARGE = 414, // request uri too large RESET = 405, // reset content SEE_OTHER = 303, // see other UNAUTHORIZED = 401, // unauthorized UNAVAILABLE = 503, // service unavailable UNSUPPORTED_TYPE = 415, // unsupported media type USE_PROXY = 305, // use proxy VERSION = 505 // http version not supported }; /** * Rules for parsing */ #define SP (char) 32 // space #define CR (char) 13 // carriage return #define LF (char) 10 // linefeed #define CRLF "\n" #define HT (char) 9 // horizontal tab /** * Defines a unique object for handling HttpConstants. * Implements the Singleton pattern. */ class HttpConstants { public: /** * Returns the unique instance of HttpConstants. * * @return HttpConstants* */ static HttpConstants* getInstance(); /** * Returns the description of a http status code. * * @return string */ string getDescription(HttpResponseCode code); /** * Returns the string representation of this code. * * @return string */ string codeToString(HttpResponseCode code); protected: /** * Creates a HttpConstants object. * This constructor is protected in order * to be sure only one instance will be created. */ HttpConstants(); /** * Copy constructor. * Also protected for same reasons as above. */ HttpConstants(const HttpConstants&); /** * Affectation of HttpConstants. * Also protected for same reasons as above. */ HttpConstants& operator= (const HttpConstants&); private: /** * The unique instance of HttpConstants. * To retrieve this instance, use the * getInstance() method. */ static HttpConstants* instance; map<int, string> descriptions; }; #endif --- NEW FILE: HttpResponse.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _HTTP_RESPONSE_H_ #define _HTTP_RESPONSE_H_ #include "HttpConstants.h" #include "Writer.h" #include <string> #include <map> using namespace std; /** * Defines a abstract http response class * to be handle by the webserver. * A HTTP response is composed by: * * 1) A HTTP protocol version * 2) A status code, indicating response's type. * 3) A description of this status code. * 4) A list of headers, identifying the response. * 5) Eventually a body, containing datas resolved * by the request processing. * * This class is abstract because a response's body * can be full text or bytes array, thus it needs * differenciation. * To use a http response object that handles plain text, * such as text or html, use the HttpTextResponse object. * To use a http response object with bytes array as body, * use the HttpBytesResponse object. */ class HttpResponse { protected: // HTTP version used in this response string version; // HTTP status code of this response HttpResponseCode code; // description of this status code string code_description; // header parameters map<string, string> headers; // writer associated to this response Writer *writer; public: /** * Creates an empty HttpResponse object with * the given writer. * * @param writer_res */ HttpResponse(Writer *writer_res); /** * HttpResponse destructor. */ ~HttpResponse(); /** * Sets the HTTP version used in this response. * * @param string - HTTP version */ void setVersion(string http_version); /** * Sets the HTTP status code of this response. * * @param HttpResponseCode */ void setResponseCode(HttpResponseCode resp_code); /** * Adds the given header name and value to the * response. * * @param name * @param value */ void addHeader(string name, string value); /** * Adds the given header name associated to a * int value. * * @param name * @param value */ void addHeaderInt(string name, int value); /** * Tests if the given header name exists. * * @param name * @return bool */ bool containsHeader(string name); /** * Returns or sets the character-encoding value. */ string getCharacterEncoding(); void setCharacterEncoding(string charset); /** * Returns or sets the content-type value. */ string getContentType(); void setContentType(string type); /** * Sets the content-length value. */ void setContentLength(unsigned long int length); /** * Returns the writer associated to this response. * * @return Writer* */ Writer *getWriter() { return writer; } /** * Returns the response's header to be sent to the client. * * @return string */ string getResponseHeader(); }; #endif --- NEW FILE: TextWriter.cpp --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "TextWriter.h" /** * Default constructor for TextWriter */ TextWriter::TextWriter() : Writer() { } /** * TextWriter destructor */ TextWriter::~TextWriter() { } /** * Adds data to the buffer * Throws a WriterException if the writer has * been closed. */ TextWriter& TextWriter::operator<< (const char text[]) throw (WriterException) { if(closed) throw WriterException(ClosedWriterExcp, "Writer is closed.", "TextWriter::<< char[]"); buffer << text; return *this; } /** * Adds data to the buffer * Throws a WriterException if the writer has been * closed. */ TextWriter& TextWriter::operator<< (const string& text) throw (WriterException) { if(closed) throw WriterException(ClosedWriterExcp, "Writer is closed.", "TextWriter::<< string"); buffer << text; return *this; } /** * Adds int to the buffer * Throws a WriterException if the writer has been * closed. */ TextWriter& TextWriter::operator<< (int& a) throw (WriterException) { if(closed) throw WriterException(ClosedWriterExcp, "Writer is closed.", "TextWriter::<< int"); buffer << a; return *this; } --- NEW FILE: Writer.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _WRITER_H_ #define _WRITER_H_ #include "../../exceptions/WriterException.h" /** * Defines a Writer for http response object. * If you want to handler text responses, such as * plain text, css or html, use the TextWriter object. * To handler bytes response, use the BytesWriter object. */ class Writer { protected: // closed state bool closed; public: /** * Default constructor * Set closed state */ Writer() { closed = false; } /** * Writer destructor * Does nothing */ virtual ~Writer() {} /** * Returns the data in this Writer. * Abstract method, need to be implemented * into subclasses. * * @return char* * @throw WriterException */ virtual char* getBytes() throw (WriterException) = 0; /** * Returns the size of the buffer * Must be implemented into subclasses * * @return unsigned long int * @throw WriterException */ virtual unsigned long int getSize() throw (WriterException) = 0; /** * Close the Writer */ void close() { closed = true; } /** * Tests if the Writer is closed. * * @return bool */ bool isClosed() { return closed; } }; #endif --- NEW FILE: HttpConstants.cpp --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "HttpConstants.h" // Init instance HttpConstants *HttpConstants::instance = 0; /** * Returns the unique instance of HttpConstants. * * @return HttpConstants* */ HttpConstants *HttpConstants::getInstance() { if(instance == 0) instance = new HttpConstants(); return instance; } /** * Creates a HttpConstants object. * This constructor is protected in order * to be sure only one instance will be created. */ HttpConstants::HttpConstants() { descriptions[100] = "Continue"; descriptions[101] = "Switching Protocols"; descriptions[200] = "OK"; descriptions[201] = "Created"; descriptions[202] = "Accepted"; descriptions[203] = "Non-Authoritative Information"; descriptions[204] = "No Content"; descriptions[205] = "Reset Content"; descriptions[206] = "Partial Content"; descriptions[300] = "Multiple Choices"; descriptions[301] = "Moved Permanently"; descriptions[302] = "Found"; descriptions[303] = "See Other"; descriptions[304] = "Not Modified"; descriptions[305] = "Use Proxy"; descriptions[307] = "Temporary Redirect"; descriptions[400] = "Bad Request"; descriptions[401] = "Unauthorized"; descriptions[402] = "Payment Required"; descriptions[403] = "Forbidden"; descriptions[404] = "Not Found"; descriptions[405] = "Method Not Allowed"; descriptions[406] = "Not Acceptable"; descriptions[407] = "Proxy Authentification Required"; descriptions[408] = "Request Time-Out"; descriptions[409] = "Conflict"; descriptions[410] = "Gone"; descriptions[411] = "Length Required"; descriptions[412] = "Precondition Failed"; descriptions[413] = "Request Entity Too Large"; descriptions[414] = "Request-URI Too Large"; descriptions[415] = "Unsupported Media Type"; descriptions[416] = "Requested ranfe not satisfiable"; descriptions[417] = "Expectation Failed"; descriptions[500] = "Internal Server Error"; descriptions[501] = "Not Implemented"; descriptions[502] = "Bad Gateway"; descriptions[503] = "Service unavailable"; descriptions[504] = "Gateway Time-out"; descriptions[505] = "HTTP Version not supported"; } /** * Returns the description of a http status code. */ string HttpConstants::getDescription(HttpResponseCode code) { map<int, string>::iterator it = descriptions.find(code); if(it != descriptions.end()) return (string) (*it).second; else return ""; } /** * Returns the string representation of this code. */ string HttpConstants::codeToString(HttpResponseCode code) { ostringstream s; s << code; return s.str(); } --- NEW FILE: TextWriter.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _TEXT_WRITER_H #define _TEXT_WRITER_H #include "Writer.h" #include "../../exceptions/WriterException.h" #include <string> #include <sstream> using namespace std; /** * Defines a Writer for handling text buffer only. * To handler bytes buffer, use the BytesWriter * object instead. */ class TextWriter : public Writer { private: // buffer for text data. ostringstream buffer; public: /** * Default constructor for TextWriter */ TextWriter(); /** * TextWriter destructor */ ~TextWriter(); /** * Adds data to the buffer * * @param const char[] * @return TextWriter * @throw WriterException */ TextWriter& operator<< (const char text[]) throw (WriterException); /** * Adds data to the buffer * * @param const string& * @return TextWriter * @throw WriterException */ TextWriter& operator<< (const string& text) throw (WriterException); /** * Adds int to the buffer * * @param int& * @return TextWriter * @throw WriterException */ TextWriter& operator<< (int& a) throw (WriterException); /** * Returns the buffer's content. * * @return char* */ virtual char* getBytes() throw (WriterException) { if(! closed) throw WriterException(NotClosedWriterExcp, "Writer isn't closed.", "TextWriter::getBytes"); return (char*) buffer.str().c_str(); } /** * Returns the size of the buffer * Must be implemented into subclasses * * @return unsigned long int */ virtual unsigned long int getSize() throw (WriterException) { if(! closed) throw WriterException(NotClosedWriterExcp, "Writer isn't closed.", "TextWriter::getBytes"); return (unsigned long int) buffer.str().size(); } }; #endif --- NEW FILE: HttpServerSocket.cpp --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "HttpServerSocket.h" #include "TextWriter.h" #include <iostream> using namespace std; /** * Constructor * Init server port. */ HttpServerSocket::HttpServerSocket(int port) : ServerSocket(), Thread() { server_port = port; } /** * HttpServerSocket destructor * Waits for thread to terminate. */ HttpServerSocket::~HttpServerSocket() throw (ThreadException) { // wait for the thread to terminate wait(); } /** * Starts the server. * Implements the thread execution code. */ void HttpServerSocket::run() { // Starts the server validate(); bind(server_port); listen(20); while(true) { // sets a cancel point setCancelPoint(); // we accept a connection HttpSocket *client = 0; try { try { client = (HttpSocket*) accept(); } catch(SocketException& se) { } if(client == 0) continue; // process the connection //theManager->addConnection(client); cout << "Socket accepted !" << endl; HttpRequest request; cout << "Receiving HTTP request..." << endl; client->receiveHttpRequest(request); cout << "Reveiced mesage : " << endl; cout << request.toString() << endl; cout << "Send response" << endl; TextWriter *writer = new TextWriter; *writer << "<html><body>Request received !</body></html>"; writer->close(); HttpResponse response(writer); response.setContentType("text/html"); cout << "ok" << endl; client->sendHttpResponse(response); cout << "Closing socket..." << endl; client->close(); delete client; } catch(Exception& e) { cout << e.getMessage() << endl; } } } /** * Starts the server. */ void HttpServerSocket::start() { Thread::start(); } /** * Stops the server. */ void HttpServerSocket::stop() throw (SocketException) { close(); cancel(); } --- NEW FILE: HttpResponse.cpp --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "HttpResponse.h" /** * Default constructor for HttpResponse * Does nothing... */ HttpResponse::HttpResponse(Writer *writer_res) { writer = writer_res; // we suppose at first that the response is '200 OK' code = OK; code_description = HttpConstants::getInstance()->getDescription(OK); version = "HTTP/1.1"; } /** * HttpResponse destructor */ HttpResponse::~HttpResponse() { delete writer; } /** * Sets the HTTP version used in this version. */ void HttpResponse::setVersion(string http_version) { version = http_version; } /** * Sets the HTTP status code of this response. * It will also set automatically the description * of this status code. */ void HttpResponse::setResponseCode(HttpResponseCode resp_code) { code = resp_code; code_description = HttpConstants::getInstance()->getDescription(resp_code); } /** * Adds the given header name and value to the * response. */ void HttpResponse::addHeader(string name, string value) { headers[name] = value; } /** * Adds the given header name associated to a * int value. */ void HttpResponse::addHeaderInt(string name, int value) { string s = ""+value; addHeader(name, s); } /** * Tests if the given header name exists. */ bool HttpResponse::containsHeader(string name) { map<string, string>::iterator it = headers.find(name); return (it != headers.end()); } /** * Returns or sets the character-encoding value. */ string HttpResponse::getCharacterEncoding() { map<string, string>::iterator it = headers.find("Content-Encoding"); if(it != headers.end()) return (*it).second; else return ""; } void HttpResponse::setCharacterEncoding(string charset) { headers["Content-Encoding"] = charset; } /** * Returns or sets the content-type value. */ string HttpResponse::getContentType() { map<string, string>::iterator it = headers.find("Content-Type"); if(it != headers.end()) return (*it).second; else return ""; } void HttpResponse::setContentType(string type) { headers["Content-Type"] = type; } /** * Sets the content-length value. */ void HttpResponse::setContentLength(unsigned long int length) { string s = "" + length; headers["Content-Length"] = s; } /** * Returns the response's header to be sent to the client. */ string HttpResponse::getResponseHeader() { string header = (version + " "); header += HttpConstants::getInstance()->codeToString(code); header += (" " + code_description + "\n"); map<string, string>::iterator it = headers.begin(); while(it != headers.end()) { header += ((string) ((*it).first) + ": " + (string) ((*it).second) + "\n"); it++; } header += "\n"; return header; } --- NEW FILE: HttpRequest.cpp --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "HttpRequest.h" #include <iostream> #include <string> using namespace std; /** * Function that counts the number of * occurrences of a string into another * string. * * @param s - The string * @param tok - Token to count into the string * @return int - number of occurrences of tok into s */ int nbOccurs(string s, string tok) { int nb = 0; unsigned int start = 0, pos; while((pos = s.find(tok, start)) != string::npos) { nb++; start = pos+1; } return nb++; } /** * Creates an empty HttpRequest. * Does nothing... */ HttpRequest::HttpRequest() { } /** * HttpRequest destructor * Does nothing... */ HttpRequest::~HttpRequest() { } /** * Parses data to build the HTTP request. * Throws a HttpException if the data isn't * Http compliant. * It returns true if it still needs some bytes to * be received ( typically, request's body is sent * in another packet ). * * METHOD SP URI SP VERSION CRLF * *( name ":" value CRLF) * CRLF * [body] * */ bool HttpRequest::parseData(char* data) throw(HttpException) { string req_str = data; unsigned int start = 0; unsigned int pos; // Method pos = req_str.find(SP, start); if(pos == string::npos) throw HttpException(NotHttpRequestExcp, "The received request isn't HTTP compliant", "HttpRequest::parseData"); string meth = req_str.substr(start, pos - start); if(meth == "GET") method = GET; else if(meth == "POST") method = POST; else if(meth == "HEAD") method = HEAD; else method = UNKNOWN; // URI start = pos+1; pos = req_str.find(SP, start); if(pos == string::npos) throw HttpException(NotHttpRequestExcp, "The received request isn't HTTP compliant", "HttpRequest::parseData"); string r_uri = req_str.substr(start, pos - start); // Retrieving parameters if any... unsigned int ind; if((ind = r_uri.find("?", 0)) != string::npos) { // parse query string for parameters parseQueryString(r_uri.substr(ind+1,r_uri.length())); } uri = r_uri; // HTTP version start = pos+1; pos = req_str.find(CRLF, start); if(pos == string::npos) throw HttpException(NotHttpRequestExcp, "The received request isn't HTTP compliant", "HttpRequest::parseData"); version = req_str.substr(start, pos - start - 1); // Headers start = pos+1; while((pos = req_str.find(CRLF, start)) != (start+1)) { // There still have some headers, retrieving it... string line = req_str.substr(start, pos - start - 1); unsigned int temp; if((temp = line.find(":",0)) == string::npos) throw HttpException(NotHttpRequestExcp, "The received request isn't HTTP compliant", "HttpRequest::parseData"); // parse header values headers[line.substr(0,temp)] = line.substr(temp+2, line.length()); start = pos+1; } // Body start = pos+1; // Size of body unsigned long bytes = getHeaderInt("Content-Length"); if(bytes == 0) { // no body... body = ""; return false; } // if body still needs to be received... else if(start >= req_str.length()) { body = ""; return true; } // body is received... else { body = req_str.substr(start, req_str.length()); // still needs some bytes... if(body.length() < bytes) return true; // everything is received ! else return false; } } /** * Parses the body data to build request's body. * Typically, browsers send request's header and request's * body in two differents packets. This method retrieves * the body that didn't come into request's header. * Returns true if body is still not complete. */ bool HttpRequest::parseBody(char* data) { // Size of body unsigned long bytes = getHeaderInt("Content-Length"); body += data; if(body.length() < bytes) return true; else { // Delete last CRLF if exists.. if(body.find("\n",body.length()-1)) body = body.substr(0,body.length()-1); // parse query string parseQueryString(body); return false; } } /** * Converts the request into a string. * For debugging purposes only. */ string HttpRequest::toString() { // building output string string out = ""; switch(method) { case GET: out += "GET "; break; case HEAD: out += "HEAD "; break; case POST: out += "POST "; break; default: out += "UNKNOWN "; break; } out += (uri + " "); out += (version + "\n"); map<string, string>::iterator it = headers.begin(); while(it != headers.end()) { out += (((string) (*it).first) + ": " + ((string) (*it).second) + "\n"); it++; } out += "\n"; out += body; return out; } /** * Parses uri for finding query parameters. * Throws a HttpException if query string isn't * http compliant. * * name "=" value *( "&" name "=" value ) */ void HttpRequest::parseQueryString(string query) throw (HttpException) { // parse string unsigned int start = 0; unsigned int pos; while((pos = query.find("&",start)) != string::npos) { unsigned int pos1; if(((pos1 = query.find("=",start)) == string::npos) || (pos1 >= pos)) throw HttpException(NotHttpRequestExcp, "The received request isn't HTTP compliant", "HttpRequest::parseData"); parameters[query.substr(start,pos1-start)] = query.substr(pos1+1,pos-pos1-1); start = pos+1; } unsigned int pos1; if(((pos1 = query.find("=",start)) == string::npos) || (pos1 >= query.length())) throw HttpException(NotHttpRequestExcp, "The received request isn't HTTP compliant", "HttpRequest::parseData"); parameters[query.substr(start,pos1-start)] = query.substr(pos1+1,query.length()); } /** * Returns value of this header name * If there are multiple values for this header * name, it will return the first value of it. * If there isn't such a header name, it will * return an empty string. */ string HttpRequest::getHeader(string name) { map<string, string>::iterator it = headers.find(name); if(it == headers.end()) return ""; string values = (string) (*it).second; unsigned int pos; if((pos = values.find(",", 0)) != string::npos) return values.substr(0, pos); else return values; } /** * Returns value of this header name as a int. * If there are multiple values for this header * name, it will return the first int value of it. * If there isn't such a header name, or if convertion * to int isn't possible, it will return 0. */ long HttpRequest::getHeaderInt(string name) { string v = getHeader(name); if(v == "") return 0; else return atol(v.c_str()); } /** * Returns all headers names. */ vector<string> HttpRequest::getHeaderNames() { map<string, string>::iterator it = headers.begin(); vector<string> names(headers.size()); int i=0; while(it != headers.end()) { names[i] = (*it).first; i++; it++; } return names; } /** * Returns all values of this header name. If no such * header name exists, it returns an empty vector. */ vector<string> HttpRequest::getHeaders(string name) { map<string, string>::iterator it = headers.find(name); if(it == headers.end()) { // returns a empty vector vector<string> values(0); return values; } string values_str = (string) (*it).second; unsigned int start = 0; unsigned int pos; int i=0; vector<string> values(nbOccurs(values_str, ",")+1); while((pos = values_str.find(",", start)) != string::npos) { values[i] = values_str.substr(start, pos-start); start = pos+1; i++; } values[i] = values_str.substr(start, values_str.length()); return values; } /** * Returns value of the given parameter name. * If this parameter doesn't exist, it will * return an empty string. */ string HttpRequest::getParameter(string name) { map<string, string>::iterator it = parameters.find(name); if(it == parameters.end()) return ""; else return (string) (*it).second; } /** * Returns all the parameters into a map. */ map<string, string> HttpRequest::getParameterMap() { return parameters; } /** * Returns all parameters' names * If there isn't any parameters, it will return * an empty vector. */ vector<string> HttpRequest::getParameterNames() { map<string, string>::iterator it = parameters.begin(); vector<string> names(parameters.size()); int i=0; while(it != parameters.end()) { names[i] = (*it).first; i++; it++; } return names; } /** * Returns the uri without any parameters if * exist. */ string HttpRequest::getURI() { unsigned int pos; if((pos = uri.find("?", 0)) != string::npos) return uri.substr(0, pos); else return uri; } --- NEW FILE: HttpSocket.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _HTTP_SOCKET_H_ #define _HTTP_SOCKET_H_ #include "../network/Socket.h" #include "../../exceptions/SocketException.h" #include "../../exceptions/WriterException.h" #include "HttpRequest.h" #include "HttpResponse.h" /** * Defines a socket for the Http protocol. * It extends the generic socket implementation. * Now, it handles HttpRequest and HttpResponse * for communicating with clients, instead * of simple bytes arrays. */ class HttpSocket : protected Socket { public: /** * Create a unconnected Http socket. */ HttpSocket(); /** * Creates a http socket with the given * socket's id and address. */ HttpSocket(int id, sockaddr_in& address); /** * Http socket destructor */ ~HttpSocket(); /** * The following methods from Socket stays public : * isClosed * isValid * getId * close */ Socket::isClosed; Socket::isValid; Socket::getId; Socket::close; /** * Build the HttpRequest of this socket. * * @param HttpRequest */ void receiveHttpRequest(HttpRequest& request) throw (SocketException); /** * Send the HttpResponse of this socket. * * @param HttpResponse */ void sendHttpResponse(HttpResponse& response) throw (SocketException, WriterException); }; #endif --- NEW FILE: HttpSocket.cpp --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "HttpSocket.h" /** * Default constructor for Http sockets. * Does nothing for an unconnected socket. */ HttpSocket::HttpSocket() : Socket() { } /** * Creates a Http socket using the given socket's id * and the given address. */ HttpSocket::HttpSocket(int id, sockaddr_in& address) : Socket(id, address) { } /** * Default destructor for Http socket. * Does nothing. */ HttpSocket::~HttpSocket() { } /** * Process the request associated to this http socket. * It receives all data from the client and then * parse the data to build the associated http request. */ void HttpSocket::receiveHttpRequest(HttpRequest& request) throw (SocketException) { // Get the data from the client char *data = new char; receive(&data); // create the request object bool not_complete = request.parseData(data); delete[] data; // while body still not completely received... while(not_complete) { char *body = new char; // receive bytes again receive(&body); not_complete = request.parseBody(data); delete[] body; } } /** * Send the http response to the client socket. * It converts the response to bytes arrays and * send it to the client. */ void HttpSocket::sendHttpResponse(HttpResponse& response) throw (SocketException, WriterException) { // Get header string h = response.getResponseHeader(); char *header = (char*)h.c_str(); unsigned long int header_size = h.size(); // Get body Writer *writer = response.getWriter(); char *body = writer->getBytes(); unsigned long int body_size = writer->getSize(); // Send response to the client send(header, header_size); send(body, body_size); } --- NEW FILE: HttpRequest.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _HTTP_REQUEST_H_ #define _HTTP_REQUEST_H_ #include "HttpConstants.h" #include "../../exceptions/HttpException.h" #include <string> #include <map> #include <vector> using namespace std; /** * Defines a http request to be handle by the webserver. * A HTTP request is composed by: * * 1) A method, typically GET, POST or HEAD. * 2) A URI to indicate the request target. * 3) A HTTP protocol version, typically HTTP/1.0 * 4) A list of headers, identifying the client. * 5) Eventually a body, containing datas from the POST * request. * */ class HttpRequest { private: // method of this http request HttpMethod method; // URI of the target. string uri; // request parameters map<string, string> parameters; // HTTP version used string version; // header parameters map<string, string> headers; // body string body; /** * Parses the query string to find parameters. * * @param query - the query string * @throw HttpException */ void parseQueryString(string query) throw (HttpException); public: /** * Creates a empty HttpRequest object. */ HttpRequest(); /** * HttpRequest destructor. */ ~HttpRequest(); /** * Parses data to build the http request. * * @param data - Data to parse * @return bool - if not yet complete * @throw HttpException */ bool parseData(char* data) throw (HttpException); /** * Parses body data to build the http request. * * @param data - Body data to parse * @return bool - if body not yet complete */ bool parseBody(char* data); /** * Converts this request into a string. * * @return string */ string toString(); /** * Returns value of this header name * * @param name - Name of this header * @return string - (first) value or empty string */ string getHeader(string name); /** * Returns value of this header name as a long * * @param name - Name of this header * @return long - (first) value or 0 */ long getHeaderInt(string name); /** * Returns all headers names. * * @return vector<string> - All headers names */ vector<string> getHeaderNames(); /** * Returns all values of this header name. * * @return vector<string> - All values of this * header name */ vector<string> getHeaders(string name); /** * Returns the method of this request. * * @return HttpMethod */ HttpMethod getMethod() { return method; } /** * Returns the complete uri of this request. * * @return string */ string getMethodURI() { return uri; } /** * Returns the uri without any parameters if * exist. * * @return string */ string getURI(); /** * Returns HTTP version used in this request. * * @return string */ string getHttpVersion() { return version; } /** * Returns value of the given parameter name. * * @param name - parameter's name * @return string - parameter's value */ string getParameter(string name); /** * Returns all the parameters into a map * * @return map<string, string> */ map<string, string> getParameterMap(); /** * Returns all parameters' names * * @return vector<string> */ vector<string> getParameterNames(); }; #endif --- NEW FILE: HttpServerSocket.h --- /* * This file is part of webInterface. * Copyright (C) 2003 Mikael Barbeaux <mik...@us...> * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _HTTP_SERVER_SOCKET_H_ #define _HTTP_SERVER_SOCKET_H_ #include "../network/ServerSocket.h" #include "HttpSocket.h" #include "../../exceptions/SocketException.h" #include "../../thread/Thread.h" #include "../../exceptions/ThreadException.h" /** * Defines a HttpServerSocket object. * A http server socket is a threaded ServerSocket * that accepts HttpSocket. */ class HttpServerSocket : protected ServerSocket, protected Thread { private: // server's port int server_port; protected: /** * Runs the server. * Implements the thread execution code. */ virtual void run(); public: /** * Creates a HttpServerSocket object on the * given port ( default is 80). */ HttpServerSocket(int port = 80); /** * HttpServerSocket destructor. */ ~HttpServerSocket() throw (ThreadException); /** * Starts the server. */ void start(); /** * Stops the server. */ void stop() throw (SocketException); }; #endif |