|
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
|