diff --git a/src/http/httpserver.cpp b/src/http/httpserver.cpp index d3fa533..c32a2b9 100644 --- a/src/http/httpserver.cpp +++ b/src/http/httpserver.cpp @@ -128,7 +128,7 @@ doSrv: stringstream stream; stream << ""; stream << "Not Found"; - stream << "

Not Found

The server couldn't find the request resource.


© 2013 Naim A. | ContactMe server
"; + stream << "

Not Found

The server couldn't find the request resource.


© 2013 Naim A. | The UDPT Project
"; stream << ""; string str = stream.str(); resp.write (str.c_str(), str.length()); @@ -139,9 +139,18 @@ doSrv: cb (server, &req, &resp); } catch (...) { - // error 500 + resp.setStatus(500, "Internal Server Error"); + resp.addHeader ("Content-Type", "text/html; charset=US-ASCII"); + stringstream stream; + stream << ""; + stream << "Internal Server Error"; + stream << "

Internal Server Error

An Error Occurred while trying to process your request.


© 2013 Naim A. | The UDPT Project
"; + stream << ""; + string str = stream.str(); + resp.write (str.c_str(), str.length()); } } + resp.finalize(); } catch (ServerException &e) { // Error 400 Bad Request! @@ -192,6 +201,19 @@ doSrv: return NULL; } + void HTTPServer::setData(string k, void *d) + { + this->customData[k] = d; + } + + void* HTTPServer::getData(string k) + { + map::iterator it = this->customData.find(k); + if (it == this->customData.end()) + return NULL; + return it->second; + } + HTTPServer::~HTTPServer () { if (this->srv != INVALID_SOCKET) @@ -435,68 +457,47 @@ doSrv: HTTPServer::Response::Response (SOCKET cli) { this->conn = cli; - this->headerSent = false; setStatus (200, "OK"); } void HTTPServer::Response::setStatus (int c, const string m) { - if (headerSent) - throw ServerException (2, "Can't set status."); - this->status_code = c; this->status_msg = m; } void HTTPServer::Response::addHeader (string key, string value) { - if (headerSent) - throw ServerException (1, "Headers already sent."); this->headers.insert (pair(key, value)); } void HTTPServer::Response::write (const char *data, int len) { - if (!this->headerSent) - sendHeaders (); if (len < 0) 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; - stream << "HTTP/1.1 " << this->status_code << " " << this->status_msg << "\r\n"; - stream << "Connection: Close\r\n"; - - multimap::iterator it; - for (it = this->headers.begin(); it != this->headers.end(); it++) + void HTTPServer::Response::finalize () + { + stringstream x; + x << "HTTP/1.1 " << this->status_code << " " << this->status_msg << "\r\n"; + multimap::iterator it, end; + 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(); - stream << "\r\n"; - string str = stream.str(); - writeRaw (str.c_str(), str.length()); - } - - bool HTTPServer::Response::isHeadersSent () const - { - return this->headerSent; + x << "Connection: Close\r\n"; + x << "Content-Length: " << this->msg.tellp() << "\r\n"; + x << "Server: udpt\r\n"; + x << "\r\n"; + x << this->msg.str(); + + // write to socket + send (this->conn, x.str().c_str(), x.str().length(), 0); } - int HTTPServer::Response::writeRaw (const char *data, int len) - { - return send (this->conn, data, len, 0); - } }; }; diff --git a/src/http/httpserver.hpp b/src/http/httpserver.hpp index 510d0db..4a32e0a 100644 --- a/src/http/httpserver.hpp +++ b/src/http/httpserver.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "../multiplatform.h" using namespace std; @@ -110,16 +111,20 @@ namespace UDPT void setStatus (int, const string); void addHeader (string key, string value); - void sendHeaders (); + int writeRaw (const char *data, int len); void write (const char *data, int len = -1); - bool isHeadersSent () const; + private: + friend class HTTPServer; + SOCKET conn; int status_code; string status_msg; multimap headers; - bool headerSent; + stringstream msg; + + void finalize (); }; typedef void (reqCallback)(HTTPServer*,Request*,Response*); @@ -128,6 +133,9 @@ namespace UDPT void addApp (list *path, reqCallback *); + void setData (string, void *); + void* getData (string); + virtual ~HTTPServer (); private: @@ -142,6 +150,7 @@ namespace UDPT HANDLE *threads; bool isRunning; appNode rootNode; + map customData; static void handleConnections (HTTPServer *); diff --git a/src/http/webapp.cpp b/src/http/webapp.cpp new file mode 100644 index 0000000..eca9188 --- /dev/null +++ b/src/http/webapp.cpp @@ -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 . + */ + +#include "webapp.hpp" +#include "../tools.h" +#include + +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* aK = apiKeys->getMap(); + map::iterator it, end; + end = aK->end(); + for (it = aK->begin();it != end;it++) + { + string key = it->first; + list 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::iterator it; +// int i = 0; +// for (it = ips.begin();it != ips.end();it++) +// { +// rList[i++] = m_hton32((*it)); +// } + this->ip_whitelist.insert(pair >(key, ips)); + } + + } + + srv->setData("webapp", this); + } + + WebApp::~WebApp() + { + } + + void WebApp::deploy() + { + list path; + path.push_back("api"); + this->instance->addApp(&path, &WebApp::handleAPI); // "/api" + } + + bool WebApp::isAllowedIP (WebApp *app, string key, uint32_t ip) + { + std::map >::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 *lst = &it->second; + list::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"); + } + }; +}; diff --git a/src/http/webapp.hpp b/src/http/webapp.hpp new file mode 100644 index 0000000..9b3b3e5 --- /dev/null +++ b/src/http/webapp.hpp @@ -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 . + */ + +#pragma once + +#include "httpserver.hpp" +#include "../db/database.hpp" +#include "../settings.hpp" +#include +#include +#include +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 > ip_whitelist; + + static void handleAPI (HTTPServer*,HTTPServer::Request*, HTTPServer::Response*); + static bool isAllowedIP (WebApp *, string, uint32_t); + }; + }; +}; diff --git a/src/main.cpp b/src/main.cpp index 48a2148..822fee0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "udpTracker.hpp" #include "settings.hpp" #include "http/httpserver.hpp" +#include "http/webapp.hpp" using namespace std; using namespace UDPT; @@ -81,6 +82,7 @@ int main(int argc, char *argv[]) usi = new UDPTracker (settings); HTTPServer *apiSrv = NULL; + WebApp *wa = NULL; r = usi->start(); if (r != UDPTracker::START_OK) @@ -101,8 +103,11 @@ int main(int argc, char *argv[]) goto cleanup; } + try{ apiSrv = new HTTPServer(6969, 8); + wa = new WebApp (apiSrv, usi->conn, settings); + wa->deploy(); } catch (ServerException &ex) { cerr << "ServerException #" << ex.getErrorCode() << ": " << ex.getErrorMsg() << endl; @@ -119,6 +124,7 @@ cleanup: delete usi; delete settings; delete apiSrv; + delete wa; #ifdef WIN32 WSACleanup(); diff --git a/src/settings.cpp b/src/settings.cpp index 4253678..5ef0d05 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -284,6 +284,11 @@ void _settings_clean_string (char **str) return this->entries[name]; } + map* Settings::SettingClass::getMap() + { + return &this->entries; + } + bool Settings::SettingClass::set (const string name, const string value) { pair::iterator, bool> r; diff --git a/src/settings.hpp b/src/settings.hpp index 8e9ec51..bda24d5 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -36,6 +36,7 @@ namespace UDPT SettingClass (const string className); bool set (const string key, const string value); string get (const string key); + map* getMap (); private: friend class Settings; string className; diff --git a/src/udpTracker.hpp b/src/udpTracker.hpp index f0bd18e..282020f 100644 --- a/src/udpTracker.hpp +++ b/src/udpTracker.hpp @@ -131,6 +131,7 @@ namespace UDPT */ virtual ~UDPTracker (); + Data::DatabaseDriver *conn; private: SOCKET sock; uint16_t port; @@ -142,7 +143,6 @@ namespace UDPT uint8_t settings; Settings *o_settings; - Data::DatabaseDriver *conn; #ifdef WIN32 static DWORD _thread_start (LPVOID arg);