A bit API Progress...
This commit is contained in:
parent
876f2da5b7
commit
5c57728630
|
@ -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;\">© 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;\">© 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;\">© 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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
158
src/http/webapp.cpp
Normal 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
55
src/http/webapp.hpp
Normal 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);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue