A bit API Progress...

This commit is contained in:
Naim A 2013-03-21 02:44:10 +02:00
parent 876f2da5b7
commit 5c57728630
8 changed files with 279 additions and 44 deletions

View file

@ -128,7 +128,7 @@ doSrv:
stringstream stream; stringstream stream;
stream << "<html>"; stream << "<html>";
stream << "<head><title>Not Found</title></head>"; stream << "<head><title>Not Found</title></head>";
stream << "<body><h1>Not Found</h1><div>The server couldn't find the request resource.</div><br /><hr /><div style=\"font-size:small;text-align:center;\">&copy; 2013 Naim A. | ContactMe server</div></body>"; stream << "<body><h1>Not Found</h1><div>The server couldn't find the request resource.</div><br /><hr /><div style=\"font-size:small;text-align:center;\">&copy; 2013 Naim A. | <a href=\"http://udpt.googlecode.com/\">The UDPT Project</a></div></body>";
stream << "</html>"; stream << "</html>";
string str = stream.str(); string str = stream.str();
resp.write (str.c_str(), str.length()); resp.write (str.c_str(), str.length());
@ -139,9 +139,18 @@ doSrv:
cb (server, &req, &resp); cb (server, &req, &resp);
} catch (...) } catch (...)
{ {
// error 500 resp.setStatus(500, "Internal Server Error");
resp.addHeader ("Content-Type", "text/html; charset=US-ASCII");
stringstream stream;
stream << "<html>";
stream << "<head><title>Internal Server Error</title></head>";
stream << "<body><h1>Internal Server Error</h1><div>An Error Occurred while trying to process your request.</div><br /><hr /><div style=\"font-size:small;text-align:center;\">&copy; 2013 Naim A. | <a href=\"http://udpt.googlecode.com/\">The UDPT Project</a></div></body>";
stream << "</html>";
string str = stream.str();
resp.write (str.c_str(), str.length());
} }
} }
resp.finalize();
} catch (ServerException &e) } catch (ServerException &e)
{ {
// Error 400 Bad Request! // Error 400 Bad Request!
@ -192,6 +201,19 @@ doSrv:
return NULL; return NULL;
} }
void HTTPServer::setData(string k, void *d)
{
this->customData[k] = d;
}
void* HTTPServer::getData(string k)
{
map<string, void*>::iterator it = this->customData.find(k);
if (it == this->customData.end())
return NULL;
return it->second;
}
HTTPServer::~HTTPServer () HTTPServer::~HTTPServer ()
{ {
if (this->srv != INVALID_SOCKET) if (this->srv != INVALID_SOCKET)
@ -435,68 +457,47 @@ doSrv:
HTTPServer::Response::Response (SOCKET cli) HTTPServer::Response::Response (SOCKET cli)
{ {
this->conn = cli; this->conn = cli;
this->headerSent = false;
setStatus (200, "OK"); setStatus (200, "OK");
} }
void HTTPServer::Response::setStatus (int c, const string m) void HTTPServer::Response::setStatus (int c, const string m)
{ {
if (headerSent)
throw ServerException (2, "Can't set status.");
this->status_code = c; this->status_code = c;
this->status_msg = m; this->status_msg = m;
} }
void HTTPServer::Response::addHeader (string key, string value) void HTTPServer::Response::addHeader (string key, string value)
{ {
if (headerSent)
throw ServerException (1, "Headers already sent.");
this->headers.insert (pair<string, string>(key, value)); this->headers.insert (pair<string, string>(key, value));
} }
void HTTPServer::Response::write (const char *data, int len) void HTTPServer::Response::write (const char *data, int len)
{ {
if (!this->headerSent)
sendHeaders ();
if (len < 0) if (len < 0)
len = strlen (data); len = strlen (data);
writeRaw (data, len); msg.write(data, len);
} }
void HTTPServer::Response::sendHeaders ()
{
if (this->headerSent)
return;
this->headerSent = true;
addHeader ("Server", "ContactMe");
stringstream stream; void HTTPServer::Response::finalize ()
stream << "HTTP/1.1 " << this->status_code << " " << this->status_msg << "\r\n"; {
stream << "Connection: Close\r\n"; stringstream x;
x << "HTTP/1.1 " << this->status_code << " " << this->status_msg << "\r\n";
multimap<string, string>::iterator it; multimap<string, string>::iterator it, end;
for (it = this->headers.begin(); it != this->headers.end(); it++) end = this->headers.end();
for (it = this->headers.begin(); it != end;it++)
{ {
stream << it->first << ": " << it->second << "\r\n"; x << it->first << ": " << it->second << "\r\n";
} }
this->headers.clear(); x << "Connection: Close\r\n";
stream << "\r\n"; x << "Content-Length: " << this->msg.tellp() << "\r\n";
string str = stream.str(); x << "Server: udpt\r\n";
writeRaw (str.c_str(), str.length()); x << "\r\n";
} x << this->msg.str();
bool HTTPServer::Response::isHeadersSent () const // write to socket
{ send (this->conn, x.str().c_str(), x.str().length(), 0);
return this->headerSent;
} }
int HTTPServer::Response::writeRaw (const char *data, int len)
{
return send (this->conn, data, len, 0);
}
}; };
}; };

View file

@ -22,6 +22,7 @@
#include <stdint.h> #include <stdint.h>
#include <map> #include <map>
#include <string> #include <string>
#include <sstream>
#include <list> #include <list>
#include "../multiplatform.h" #include "../multiplatform.h"
using namespace std; using namespace std;
@ -110,16 +111,20 @@ namespace UDPT
void setStatus (int, const string); void setStatus (int, const string);
void addHeader (string key, string value); void addHeader (string key, string value);
void sendHeaders ();
int writeRaw (const char *data, int len); int writeRaw (const char *data, int len);
void write (const char *data, int len = -1); void write (const char *data, int len = -1);
bool isHeadersSent () const;
private: private:
friend class HTTPServer;
SOCKET conn; SOCKET conn;
int status_code; int status_code;
string status_msg; string status_msg;
multimap<string, string> headers; multimap<string, string> headers;
bool headerSent; stringstream msg;
void finalize ();
}; };
typedef void (reqCallback)(HTTPServer*,Request*,Response*); typedef void (reqCallback)(HTTPServer*,Request*,Response*);
@ -128,6 +133,9 @@ namespace UDPT
void addApp (list<string> *path, reqCallback *); void addApp (list<string> *path, reqCallback *);
void setData (string, void *);
void* getData (string);
virtual ~HTTPServer (); virtual ~HTTPServer ();
private: private:
@ -142,6 +150,7 @@ namespace UDPT
HANDLE *threads; HANDLE *threads;
bool isRunning; bool isRunning;
appNode rootNode; appNode rootNode;
map<string, void*> customData;
static void handleConnections (HTTPServer *); static void handleConnections (HTTPServer *);

158
src/http/webapp.cpp Normal file
View file

@ -0,0 +1,158 @@
/*
* Copyright © 2013 Naim A.
*
* This file is part of UDPT.
*
* UDPT 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 3 of the License, or
* (at your option) any later version.
*
* UDPT 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 UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#include "webapp.hpp"
#include "../tools.h"
#include <iostream>
using namespace std;
namespace UDPT
{
namespace Server
{
static uint32_t _getNextIPv4 (string::size_type &i, string &line)
{
string::size_type len = line.length();
char c;
while (i < len)
{
c = line.at(i);
if (c >= '0' && c <= '9')
break;
i++;
}
uint32_t ip = 0;
for (int n = 0;n < 4;n++)
{
int cn = 0;
while (i < len)
{
c = line.at (i++);
if (c == '.' || ((c == ' ' || c == ',' || c == ';') && n == 3))
break;
else if (!(c >= '0' && c <= '9'))
return 0;
cn *= 10;
cn += (c - '0');
}
ip *= 256;
ip += cn;
}
return ip;
}
WebApp::WebApp(HTTPServer *srv, DatabaseDriver *db, Settings *settings)
{
this->instance = srv;
this->db = db;
this->sc_api = settings->getClass("api");
Settings::SettingClass *apiKeys = settings->getClass("api.keys");
if (apiKeys != NULL)
{
map<string, string>* aK = apiKeys->getMap();
map<string, string>::iterator it, end;
end = aK->end();
for (it = aK->begin();it != end;it++)
{
string key = it->first;
list<uint32_t> ips;
string::size_type strp = 0;
uint32_t ip;
while ((ip = _getNextIPv4(strp, it->second)) != 0)
{
ips.push_back( m_hton32(ip) );
}
// ips.push_back(0); // end of list
// uint32_t *rList = new uint32_t [ips.size()];
// list<uint32_t>::iterator it;
// int i = 0;
// for (it = ips.begin();it != ips.end();it++)
// {
// rList[i++] = m_hton32((*it));
// }
this->ip_whitelist.insert(pair<string, list<uint32_t> >(key, ips));
}
}
srv->setData("webapp", this);
}
WebApp::~WebApp()
{
}
void WebApp::deploy()
{
list<string> path;
path.push_back("api");
this->instance->addApp(&path, &WebApp::handleAPI); // "/api"
}
bool WebApp::isAllowedIP (WebApp *app, string key, uint32_t ip)
{
std::map<std::string, list<uint32_t> >::iterator it, end;
end = app->ip_whitelist.end ();
it = app->ip_whitelist.find (key);
if (it == app->ip_whitelist.end())
return false; // no such key
list<uint32_t> *lst = &it->second;
list<uint32_t>::iterator ipit;
for (ipit = lst->begin();ipit != lst->end();ipit++)
{
if (*ipit == ip)
return true;
}
return false;
}
void WebApp::handleAPI(HTTPServer *srv, HTTPServer::Request *req, HTTPServer::Response *resp)
{
if (req->getAddress()->sin_family != AF_INET)
{
throw ServerException (0, "IPv4 supported Only.");
}
string key = req->getParam("auth");
if (key.length() <= 0)
throw ServerException (0, "Bad Authentication Key");
WebApp *app = (WebApp*)srv->getData("webapp");
if (app == NULL)
throw ServerException(0, "WebApp object wasn't found");
if (!isAllowedIP(app, key, req->getAddress()->sin_addr.s_addr))
{
resp->setStatus(403, "Forbidden");
resp->write("IP not whitelisted. Access Denied.");
return;
}
string action = req->getParam("action");
}
};
};

55
src/http/webapp.hpp Normal file
View file

@ -0,0 +1,55 @@
/*
* Copyright © 2013 Naim A.
*
* This file is part of UDPT.
*
* UDPT 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 3 of the License, or
* (at your option) any later version.
*
* UDPT 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 UDPT. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "httpserver.hpp"
#include "../db/database.hpp"
#include "../settings.hpp"
#include <stdint.h>
#include <map>
#include <string>
using namespace std;
using namespace UDPT;
using namespace UDPT::Data;
namespace UDPT
{
namespace Server
{
class WebApp
{
public:
WebApp (HTTPServer *, DatabaseDriver *, Settings *);
~WebApp ();
void deploy ();
private:
HTTPServer *instance;
UDPT::Data::DatabaseDriver *db;
Settings::SettingClass *sc_api;
std::map<std::string, list<uint32_t> > ip_whitelist;
static void handleAPI (HTTPServer*,HTTPServer::Request*, HTTPServer::Response*);
static bool isAllowedIP (WebApp *, string, uint32_t);
};
};
};

View file

@ -23,6 +23,7 @@
#include "udpTracker.hpp" #include "udpTracker.hpp"
#include "settings.hpp" #include "settings.hpp"
#include "http/httpserver.hpp" #include "http/httpserver.hpp"
#include "http/webapp.hpp"
using namespace std; using namespace std;
using namespace UDPT; using namespace UDPT;
@ -81,6 +82,7 @@ int main(int argc, char *argv[])
usi = new UDPTracker (settings); usi = new UDPTracker (settings);
HTTPServer *apiSrv = NULL; HTTPServer *apiSrv = NULL;
WebApp *wa = NULL;
r = usi->start(); r = usi->start();
if (r != UDPTracker::START_OK) if (r != UDPTracker::START_OK)
@ -101,8 +103,11 @@ int main(int argc, char *argv[])
goto cleanup; goto cleanup;
} }
try{ try{
apiSrv = new HTTPServer(6969, 8); apiSrv = new HTTPServer(6969, 8);
wa = new WebApp (apiSrv, usi->conn, settings);
wa->deploy();
} catch (ServerException &ex) } catch (ServerException &ex)
{ {
cerr << "ServerException #" << ex.getErrorCode() << ": " << ex.getErrorMsg() << endl; cerr << "ServerException #" << ex.getErrorCode() << ": " << ex.getErrorMsg() << endl;
@ -119,6 +124,7 @@ cleanup:
delete usi; delete usi;
delete settings; delete settings;
delete apiSrv; delete apiSrv;
delete wa;
#ifdef WIN32 #ifdef WIN32
WSACleanup(); WSACleanup();

View file

@ -284,6 +284,11 @@ void _settings_clean_string (char **str)
return this->entries[name]; return this->entries[name];
} }
map<string, string>* Settings::SettingClass::getMap()
{
return &this->entries;
}
bool Settings::SettingClass::set (const string name, const string value) bool Settings::SettingClass::set (const string name, const string value)
{ {
pair<map<string, string>::iterator, bool> r; pair<map<string, string>::iterator, bool> r;

View file

@ -36,6 +36,7 @@ namespace UDPT
SettingClass (const string className); SettingClass (const string className);
bool set (const string key, const string value); bool set (const string key, const string value);
string get (const string key); string get (const string key);
map<string, string>* getMap ();
private: private:
friend class Settings; friend class Settings;
string className; string className;

View file

@ -131,6 +131,7 @@ namespace UDPT
*/ */
virtual ~UDPTracker (); virtual ~UDPTracker ();
Data::DatabaseDriver *conn;
private: private:
SOCKET sock; SOCKET sock;
uint16_t port; uint16_t port;
@ -142,7 +143,6 @@ namespace UDPT
uint8_t settings; uint8_t settings;
Settings *o_settings; Settings *o_settings;
Data::DatabaseDriver *conn;
#ifdef WIN32 #ifdef WIN32
static DWORD _thread_start (LPVOID arg); static DWORD _thread_start (LPVOID arg);