From 92c59963f82f81aa3202657e7fdbb2592924ede3 Mon Sep 17 00:00:00 2001 From: "cedeel@gmail.com" Date: Thu, 14 Jun 2012 13:06:06 +0000 Subject: Attempt to bring sanity to newlines across systems. git-svn-id: http://mc-server.googlecode.com/svn/trunk@606 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- WebServer/Globals.cpp | 20 +- WebServer/Socket.cpp | 744 +++++++++++++++++------------------ WebServer/StdHelpers.cpp | 124 +++--- WebServer/UrlHelper.cpp | 330 ++++++++-------- WebServer/WebServer.cpp | 994 +++++++++++++++++++++++------------------------ WebServer/base64.cpp | 198 +++++----- WebServer/cEvents.cpp | 250 ++++++------ 7 files changed, 1330 insertions(+), 1330 deletions(-) (limited to 'WebServer') diff --git a/WebServer/Globals.cpp b/WebServer/Globals.cpp index 2c60fd698..13c6ae709 100644 --- a/WebServer/Globals.cpp +++ b/WebServer/Globals.cpp @@ -1,10 +1,10 @@ - -// Globals.cpp - -// This file is used for precompiled header generation in MSVC environments - -#include "Globals.h" - - - - + +// Globals.cpp + +// This file is used for precompiled header generation in MSVC environments + +#include "Globals.h" + + + + diff --git a/WebServer/Socket.cpp b/WebServer/Socket.cpp index 430461fe8..2dde93b22 100644 --- a/WebServer/Socket.cpp +++ b/WebServer/Socket.cpp @@ -1,372 +1,372 @@ -/* - Socket.cpp - - Copyright (C) 2002-2004 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch -*/ - -/* - Note on point 2: - THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 -*/ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Socket.h" -#include - -#ifndef _WIN32 - #include - #include - #include - #define SD_SEND 0x01 -#else - #define MSG_NOSIGNAL (0) -#endif - -#ifdef __MAC_NA - #define MSG_NOSIGNAL (0) -#endif - -#ifndef MSG_NOSIGNAL - #define MSG_NOSIGNAL 0 -#endif // MSG_NOSIGNAL - -using namespace std; - -int Socket::nofSockets_= 0; - - - - - -void Socket::Start() -{ - #ifdef _WIN32 - if (!nofSockets_) - { - WSADATA info; - if (WSAStartup(MAKEWORD(2,0), &info)) - { - throw "Could not start WSA"; - } - } - #endif - ++nofSockets_; -} - - - - - -void Socket::End() -{ -#ifdef _WIN32 - WSACleanup(); -#endif -} - - - - - -Socket::Socket() : - s_(INVALID_SOCKET) -{ - Start(); - // UDP: use SOCK_DGRAM instead of SOCK_STREAM - s_ = socket(AF_INET,SOCK_STREAM,0); - - if (!IsValid()) - { - throw "INVALID_SOCKET"; - } - - refCounter_ = new int(1); -} - - - - - -Socket::Socket(SOCKET s) : s_(s) -{ - Start(); - refCounter_ = new int(1); -}; - - - - - -Socket::~Socket() -{ - if (! --(*refCounter_)) - { - Close(); - delete refCounter_; - } - - --nofSockets_; - if (!nofSockets_) - { - End(); - } -} - - - - - -Socket::Socket(const Socket& o) -{ - refCounter_=o.refCounter_; - (*refCounter_)++; - s_ =o.s_; - - nofSockets_++; -} - - - - - -Socket& Socket::operator=(Socket& o) -{ - (*o.refCounter_)++; - - refCounter_ = o.refCounter_; - s_ = o.s_; - - nofSockets_++; - - return *this; -} - - - - - -bool Socket::IsValid(void) const -{ - #ifdef _WIN32 - return (s_ != INVALID_SOCKET); - #else - return (s_ >= 0); - #endif -} - - - - - -void Socket::Close( bool a_WaitSend /* = false */ ) -{ - if (IsValid()) - { - if (a_WaitSend) - { - assert( shutdown(s_, SD_SEND ) == 0 ); - char c; - while( recv(s_, &c, 1, 0 ) > 0 ) - {} - } - - #ifndef _WIN32 - // Linux needs to shut the socket down first, otherwise the socket keeps blocking accept() and select() calls! - // Ref.: http://forum.mc-server.org/showthread.php?tid=344 - if (shutdown(s_, SHUT_RDWR) != 0) - { - LOGWARN("Error on shutting down socket %d", s_); - } - #endif // _WIN32 - - closesocket(s_); - - s_ = INVALID_SOCKET; - } -} - - - - - -std::string Socket::ReceiveLine() -{ - std::string ret; - while (1) - { - char r; - - if (recv(s_, &r, 1, 0) <= 0 ) - { - return ""; - } - ret += r; - if (r == '\n') return ret; - } -} - - - - - -std::string Socket::ReceiveBytes( unsigned int a_Length ) -{ - std::string ret; - while( ret.size() < a_Length ) - { - char r; - - if (recv(s_, &r, 1, 0) <= 0 ) - { - return ""; - } - ret += r; - } - return ret; -} - - - - - -void Socket::SendLine(std::string s) -{ - s += '\n'; - if( send(s_,s.c_str(),s.length(),MSG_NOSIGNAL) <= 0 ) - { - //printf("SendLine Socket error!! \n" ); - Close(); - } -} - - - - - -void Socket::SendBytes(const std::string& s) -{ - if( send(s_,s.c_str(),s.length(), MSG_NOSIGNAL) <= 0 ) - { - //printf("SendBytes Socket error!! \n" ); - Close(); - } -} - - - - - -SocketServer::SocketServer(int port, int connections, TypeSocket type) -{ - sockaddr_in sa; - - memset(&sa, 0, sizeof(sa)); - - sa.sin_family = PF_INET; - sa.sin_port = htons(port); - s_ = socket(AF_INET, SOCK_STREAM, 0); - - if (!IsValid()) - { - LOG("WebServer: INVALID_SOCKET"); - } - - if(type==NonBlockingSocket) - { - return; - } - - #ifdef _WIN32 - char yes = 1; - #else - int yes = 1; - #endif - - if (setsockopt(s_,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) - { - LOG("WebServer: setsockopt == -1"); - return; - } - - /* bind the socket to the internet address */ - if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR) - { - closesocket(s_); - LOG("WebServer: INVALID_SOCKET"); - } - - listen(s_, connections); -} - - - - - -Socket* SocketServer::Accept() -{ - Socket * r = new Socket(accept(s_, 0, 0)); - if (!r->IsValid()) - { - delete r; - r = NULL; - } - - return r; -} - - - - - -SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) -{ - FD_ZERO(&fds_); - SOCKET Highest = s1->s_; - FD_SET(const_cast(s1)->s_,&fds_); - if(s2) - { - FD_SET(const_cast(s2)->s_,&fds_); - if (s2->s_ > Highest) - { - Highest = s2->s_; - } - } - if (select(Highest + 1, &fds_, NULL, NULL, NULL) == SOCKET_ERROR) - { - throw "Error in select"; - } -} - - - - - -bool SocketSelect::Readable(Socket const* const s) -{ - return (FD_ISSET(s->s_,&fds_) != 0); -} - - - - +/* + Socket.cpp + + Copyright (C) 2002-2004 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch +*/ + +/* + Note on point 2: + THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 +*/ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Socket.h" +#include + +#ifndef _WIN32 + #include + #include + #include + #define SD_SEND 0x01 +#else + #define MSG_NOSIGNAL (0) +#endif + +#ifdef __MAC_NA + #define MSG_NOSIGNAL (0) +#endif + +#ifndef MSG_NOSIGNAL + #define MSG_NOSIGNAL 0 +#endif // MSG_NOSIGNAL + +using namespace std; + +int Socket::nofSockets_= 0; + + + + + +void Socket::Start() +{ + #ifdef _WIN32 + if (!nofSockets_) + { + WSADATA info; + if (WSAStartup(MAKEWORD(2,0), &info)) + { + throw "Could not start WSA"; + } + } + #endif + ++nofSockets_; +} + + + + + +void Socket::End() +{ +#ifdef _WIN32 + WSACleanup(); +#endif +} + + + + + +Socket::Socket() : + s_(INVALID_SOCKET) +{ + Start(); + // UDP: use SOCK_DGRAM instead of SOCK_STREAM + s_ = socket(AF_INET,SOCK_STREAM,0); + + if (!IsValid()) + { + throw "INVALID_SOCKET"; + } + + refCounter_ = new int(1); +} + + + + + +Socket::Socket(SOCKET s) : s_(s) +{ + Start(); + refCounter_ = new int(1); +}; + + + + + +Socket::~Socket() +{ + if (! --(*refCounter_)) + { + Close(); + delete refCounter_; + } + + --nofSockets_; + if (!nofSockets_) + { + End(); + } +} + + + + + +Socket::Socket(const Socket& o) +{ + refCounter_=o.refCounter_; + (*refCounter_)++; + s_ =o.s_; + + nofSockets_++; +} + + + + + +Socket& Socket::operator=(Socket& o) +{ + (*o.refCounter_)++; + + refCounter_ = o.refCounter_; + s_ = o.s_; + + nofSockets_++; + + return *this; +} + + + + + +bool Socket::IsValid(void) const +{ + #ifdef _WIN32 + return (s_ != INVALID_SOCKET); + #else + return (s_ >= 0); + #endif +} + + + + + +void Socket::Close( bool a_WaitSend /* = false */ ) +{ + if (IsValid()) + { + if (a_WaitSend) + { + assert( shutdown(s_, SD_SEND ) == 0 ); + char c; + while( recv(s_, &c, 1, 0 ) > 0 ) + {} + } + + #ifndef _WIN32 + // Linux needs to shut the socket down first, otherwise the socket keeps blocking accept() and select() calls! + // Ref.: http://forum.mc-server.org/showthread.php?tid=344 + if (shutdown(s_, SHUT_RDWR) != 0) + { + LOGWARN("Error on shutting down socket %d", s_); + } + #endif // _WIN32 + + closesocket(s_); + + s_ = INVALID_SOCKET; + } +} + + + + + +std::string Socket::ReceiveLine() +{ + std::string ret; + while (1) + { + char r; + + if (recv(s_, &r, 1, 0) <= 0 ) + { + return ""; + } + ret += r; + if (r == '\n') return ret; + } +} + + + + + +std::string Socket::ReceiveBytes( unsigned int a_Length ) +{ + std::string ret; + while( ret.size() < a_Length ) + { + char r; + + if (recv(s_, &r, 1, 0) <= 0 ) + { + return ""; + } + ret += r; + } + return ret; +} + + + + + +void Socket::SendLine(std::string s) +{ + s += '\n'; + if( send(s_,s.c_str(),s.length(),MSG_NOSIGNAL) <= 0 ) + { + //printf("SendLine Socket error!! \n" ); + Close(); + } +} + + + + + +void Socket::SendBytes(const std::string& s) +{ + if( send(s_,s.c_str(),s.length(), MSG_NOSIGNAL) <= 0 ) + { + //printf("SendBytes Socket error!! \n" ); + Close(); + } +} + + + + + +SocketServer::SocketServer(int port, int connections, TypeSocket type) +{ + sockaddr_in sa; + + memset(&sa, 0, sizeof(sa)); + + sa.sin_family = PF_INET; + sa.sin_port = htons(port); + s_ = socket(AF_INET, SOCK_STREAM, 0); + + if (!IsValid()) + { + LOG("WebServer: INVALID_SOCKET"); + } + + if(type==NonBlockingSocket) + { + return; + } + + #ifdef _WIN32 + char yes = 1; + #else + int yes = 1; + #endif + + if (setsockopt(s_,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) + { + LOG("WebServer: setsockopt == -1"); + return; + } + + /* bind the socket to the internet address */ + if (bind(s_, (sockaddr *)&sa, sizeof(sockaddr_in)) == SOCKET_ERROR) + { + closesocket(s_); + LOG("WebServer: INVALID_SOCKET"); + } + + listen(s_, connections); +} + + + + + +Socket* SocketServer::Accept() +{ + Socket * r = new Socket(accept(s_, 0, 0)); + if (!r->IsValid()) + { + delete r; + r = NULL; + } + + return r; +} + + + + + +SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) +{ + FD_ZERO(&fds_); + SOCKET Highest = s1->s_; + FD_SET(const_cast(s1)->s_,&fds_); + if(s2) + { + FD_SET(const_cast(s2)->s_,&fds_); + if (s2->s_ > Highest) + { + Highest = s2->s_; + } + } + if (select(Highest + 1, &fds_, NULL, NULL, NULL) == SOCKET_ERROR) + { + throw "Error in select"; + } +} + + + + + +bool SocketSelect::Readable(Socket const* const s) +{ + return (FD_ISSET(s->s_,&fds_) != 0); +} + + + + diff --git a/WebServer/StdHelpers.cpp b/WebServer/StdHelpers.cpp index f858c0bc4..63e48a7d2 100644 --- a/WebServer/StdHelpers.cpp +++ b/WebServer/StdHelpers.cpp @@ -1,62 +1,62 @@ -/* - stdHelpers.cpp - - Copyright (C) 2002-2004 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch -*/ - -/* - Note on point 2: - THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 -*/ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "StdHelpers.h" -#include - -std::string ReplaceInStr(const std::string& in, const std::string& search_for, const std::string& replace_with) { - std::string ret = in; - - std::string::size_type pos = ret.find(search_for); - - while (pos != std::string::npos) { - ret = ret.replace(pos, search_for.size(), replace_with); - pos = pos - search_for.size() + replace_with.size() + 1; - pos = ret.find(search_for, pos); - } - - return ret; -} - -// std:toupper and std::tolower are overloaded. Well... -// http://gcc.gnu.org/ml/libstdc++/2002-11/msg00180.html -char toLower_ (char c) { return std::tolower(c); } -char toUpper_ (char c) { return std::toupper(c); } - -void ToUpper(std::string& s) { - std::transform(s.begin(), s.end(), s.begin(),toUpper_); -} - -void ToLower(std::string& s) { - std::transform(s.begin(), s.end(), s.begin(),toLower_); -} +/* + stdHelpers.cpp + + Copyright (C) 2002-2004 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch +*/ + +/* + Note on point 2: + THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 +*/ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "StdHelpers.h" +#include + +std::string ReplaceInStr(const std::string& in, const std::string& search_for, const std::string& replace_with) { + std::string ret = in; + + std::string::size_type pos = ret.find(search_for); + + while (pos != std::string::npos) { + ret = ret.replace(pos, search_for.size(), replace_with); + pos = pos - search_for.size() + replace_with.size() + 1; + pos = ret.find(search_for, pos); + } + + return ret; +} + +// std:toupper and std::tolower are overloaded. Well... +// http://gcc.gnu.org/ml/libstdc++/2002-11/msg00180.html +char toLower_ (char c) { return std::tolower(c); } +char toUpper_ (char c) { return std::toupper(c); } + +void ToUpper(std::string& s) { + std::transform(s.begin(), s.end(), s.begin(),toUpper_); +} + +void ToLower(std::string& s) { + std::transform(s.begin(), s.end(), s.begin(),toLower_); +} diff --git a/WebServer/UrlHelper.cpp b/WebServer/UrlHelper.cpp index 44f1166fd..e0a67687b 100644 --- a/WebServer/UrlHelper.cpp +++ b/WebServer/UrlHelper.cpp @@ -1,165 +1,165 @@ -/* - UrlHelper.cpp - - Copyright (C) 2002-2004 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch -*/ - -/* - Note on point 2: - THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 -*/ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "UrlHelper.h" -#include "Tracer.h" -#include "StdHelpers.h" - -#include -#include - -bool RemoveProtocolFromUrl(std::string const& url, std::string& protocol, std::string& rest) { - TraceFunc("RemoveProtocolFromUrl"); - Trace(std::string("url='")+url+"'"); - std::string::size_type pos_colon = url.find(":"); - - if (pos_colon == std::string::npos) { - rest = url; - return false; - } - - if (url.size() < pos_colon + 2) { - rest = url; - return false; - } - - if (url[pos_colon+1] != '/' || - url[pos_colon+2] != '/') { - rest = url; - return false; - } - - protocol = url.substr(0,pos_colon); - rest = url.substr(3+pos_colon); // Skipping three characters ( '://' ) - - return true; -} - -void SplitGetReq(std::string get_req, std::string& path, std::map& params) { - TraceFunc("SplitGetReq"); - - // Remove trailing newlines - if (get_req[get_req.size()-1] == '\x0d' || - get_req[get_req.size()-1] == '\x0a') - get_req=get_req.substr(0, get_req.size()-1); - - if (get_req[get_req.size()-1] == '\x0d' || - get_req[get_req.size()-1] == '\x0a') - get_req=get_req.substr(0, get_req.size()-1); - - // Remove potential Trailing HTTP/1.x - if (get_req.size() > 7) { - if (get_req.substr(get_req.size()-8, 7) == "HTTP/1.") { - get_req=get_req.substr(0, get_req.size()-9); - } - } - - std::string::size_type qm = get_req.find("?"); - if (qm != std::string::npos) { - std::string url_params = get_req.substr(qm+1); - - path = get_req.substr(0, qm); - - // Appending a '&' so that there are as many '&' as name-value pairs. - // It makes it easier to split the url for name value pairs, he he he - url_params += "&"; - - std::string::size_type next_amp = url_params.find("&"); - - while (next_amp != std::string::npos) { - std::string name_value = url_params.substr(0,next_amp); - url_params = url_params.substr(next_amp+1); - next_amp = url_params.find("&"); - - std::string::size_type pos_equal = name_value.find("="); - - std::string nam = name_value.substr(0,pos_equal); - std::string val = name_value.substr(pos_equal+1); - - std::string::size_type pos_plus; - while ( (pos_plus = val.find("+")) != std::string::npos ) { - val.replace(pos_plus, 1, " "); - } - - // Replacing %xy notation - std::string::size_type pos_hex = 0; - while ( (pos_hex = val.find("%", pos_hex)) != std::string::npos ) { - std::stringstream h; - h << val.substr(pos_hex+1, 2); - h << std::hex; - - int i; - h>>i; - - std::stringstream f; - f << static_cast(i); - std::string s; - f >> s; - - val.replace(pos_hex, 3, s); - pos_hex ++; - } - - params.insert(std::map::value_type(nam, val)); - } - } - else { - path = get_req; - } -} - -void SplitUrl(std::string const& url, std::string& protocol, std::string& server, std::string& path) { - TraceFunc("SplitUrl"); - RemoveProtocolFromUrl(url, protocol, server); - - if (protocol == "http") { - std::string::size_type pos_slash = server.find("/"); - - if (pos_slash != std::string::npos) { - Trace("slash found"); - path = server.substr(pos_slash); - server = server.substr(0, pos_slash); - } - else { - Trace("slash not found"); - path = "/"; - } - } - else if (protocol == "file") { - path = ReplaceInStr(server, "\\", "/"); - server = ""; - } - else { - std::cerr << "unknown protocol in SplitUrl: '" << protocol << "'" << std::endl; - } -} +/* + UrlHelper.cpp + + Copyright (C) 2002-2004 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch +*/ + +/* + Note on point 2: + THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 +*/ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "UrlHelper.h" +#include "Tracer.h" +#include "StdHelpers.h" + +#include +#include + +bool RemoveProtocolFromUrl(std::string const& url, std::string& protocol, std::string& rest) { + TraceFunc("RemoveProtocolFromUrl"); + Trace(std::string("url='")+url+"'"); + std::string::size_type pos_colon = url.find(":"); + + if (pos_colon == std::string::npos) { + rest = url; + return false; + } + + if (url.size() < pos_colon + 2) { + rest = url; + return false; + } + + if (url[pos_colon+1] != '/' || + url[pos_colon+2] != '/') { + rest = url; + return false; + } + + protocol = url.substr(0,pos_colon); + rest = url.substr(3+pos_colon); // Skipping three characters ( '://' ) + + return true; +} + +void SplitGetReq(std::string get_req, std::string& path, std::map& params) { + TraceFunc("SplitGetReq"); + + // Remove trailing newlines + if (get_req[get_req.size()-1] == '\x0d' || + get_req[get_req.size()-1] == '\x0a') + get_req=get_req.substr(0, get_req.size()-1); + + if (get_req[get_req.size()-1] == '\x0d' || + get_req[get_req.size()-1] == '\x0a') + get_req=get_req.substr(0, get_req.size()-1); + + // Remove potential Trailing HTTP/1.x + if (get_req.size() > 7) { + if (get_req.substr(get_req.size()-8, 7) == "HTTP/1.") { + get_req=get_req.substr(0, get_req.size()-9); + } + } + + std::string::size_type qm = get_req.find("?"); + if (qm != std::string::npos) { + std::string url_params = get_req.substr(qm+1); + + path = get_req.substr(0, qm); + + // Appending a '&' so that there are as many '&' as name-value pairs. + // It makes it easier to split the url for name value pairs, he he he + url_params += "&"; + + std::string::size_type next_amp = url_params.find("&"); + + while (next_amp != std::string::npos) { + std::string name_value = url_params.substr(0,next_amp); + url_params = url_params.substr(next_amp+1); + next_amp = url_params.find("&"); + + std::string::size_type pos_equal = name_value.find("="); + + std::string nam = name_value.substr(0,pos_equal); + std::string val = name_value.substr(pos_equal+1); + + std::string::size_type pos_plus; + while ( (pos_plus = val.find("+")) != std::string::npos ) { + val.replace(pos_plus, 1, " "); + } + + // Replacing %xy notation + std::string::size_type pos_hex = 0; + while ( (pos_hex = val.find("%", pos_hex)) != std::string::npos ) { + std::stringstream h; + h << val.substr(pos_hex+1, 2); + h << std::hex; + + int i; + h>>i; + + std::stringstream f; + f << static_cast(i); + std::string s; + f >> s; + + val.replace(pos_hex, 3, s); + pos_hex ++; + } + + params.insert(std::map::value_type(nam, val)); + } + } + else { + path = get_req; + } +} + +void SplitUrl(std::string const& url, std::string& protocol, std::string& server, std::string& path) { + TraceFunc("SplitUrl"); + RemoveProtocolFromUrl(url, protocol, server); + + if (protocol == "http") { + std::string::size_type pos_slash = server.find("/"); + + if (pos_slash != std::string::npos) { + Trace("slash found"); + path = server.substr(pos_slash); + server = server.substr(0, pos_slash); + } + else { + Trace("slash not found"); + path = "/"; + } + } + else if (protocol == "file") { + path = ReplaceInStr(server, "\\", "/"); + server = ""; + } + else { + std::cerr << "unknown protocol in SplitUrl: '" << protocol << "'" << std::endl; + } +} diff --git a/WebServer/WebServer.cpp b/WebServer/WebServer.cpp index 8be690bd1..089be4352 100644 --- a/WebServer/WebServer.cpp +++ b/WebServer/WebServer.cpp @@ -1,497 +1,497 @@ -/* - WebServer.cpp - - Copyright (C) 2003-2007 René Nyffenegger - - This source code is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this source code must not be misrepresented; you must not - claim that you wrote the original source code. If you use this source code - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original source code. - - 3. This notice may not be removed or altered from any source distribution. - - René Nyffenegger rene.nyffenegger@adp-gmbh.ch - - Thanks to Tom Lynn who pointed out an error in this source code. -*/ - -/* - Note on point 2: - THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 -*/ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include -#ifdef _WIN32 - #include -#endif -#include -#include - - -#include "WebServer.h" -#include "cEvents.h" -#include "Socket.h" -#include "UrlHelper.h" -#include "base64.h" - - - - - -webserver::request_func webserver::request_func_ = NULL; - - - - - -static std::string EatLine( std::string& a_String ) -{ - std::string RetVal = ""; - unsigned int StringSize = a_String.size(); - const char* c = a_String.c_str(); - - for( unsigned int i = 0; i < StringSize; ++i, ++c) - { - if( *c == '\n' ) - { - RetVal += *c; -// ++i; ++c; -// if( i < StringSize ) -// { -// if( *c == '\r' ) -// { -// RetVal += *c; -// } -// } - break; - } - RetVal += *c; - } - a_String = a_String.substr( RetVal.size() ); - return RetVal; -} - - - - - -// Turns -// "blabla my string with \"quotes\"!" -// into -// blabla my string with "quotes"! -static std::string GetQuotedString( const std::string& a_String ) -{ - std::string RetVal; - - bool bGotFirstQuote = false; - bool bIgnoreNext = false; - unsigned int StrLen = a_String.size(); - for( unsigned int i = 0; i < StrLen; ++i ) - { - if( bIgnoreNext == false ) - { - if( a_String[i] == '\"' ) - { - if( bGotFirstQuote == false ) - { - bGotFirstQuote = true; - } - else - { - break; - } - continue; - } - else if( a_String[i] == '\\' ) // Escape character - { - bIgnoreNext = true; - continue; - } - } - RetVal.push_back( a_String[i] ); - bIgnoreNext = false; - } - - return RetVal; -} - - - - - -void ParseMultipartFormData( webserver::http_request& req, Socket* s) -{ - static const std::string multipart_form_data = "multipart/form-data"; - if(req.content_type_.substr(0, multipart_form_data.size()) == multipart_form_data) // Difficult data... :( - { - AStringVector ContentTypeData = StringSplit( req.content_type_, "; " ); - - std::string boundary; - // Find boundary - for( unsigned int i = 0; i < ContentTypeData.size(); ++i ) - { - static const std::string boundary_ = "boundary="; - if( ContentTypeData[i].substr(0, boundary_.size()) == boundary_ ) // Found boundary - { - boundary = ContentTypeData[i].substr( boundary_.size() ); - } - } - - //LOGINFO("Boundary: %s", boundary.c_str() ); - std::string boundary_start = "--" + boundary; - std::string boundary_end = boundary_start + "--"; - - std::string Content = s->ReceiveBytes( req.content_length_ ); - - //printf("Total content: \n%s\n", Content.c_str() ); - - // Should start with boundary! - std::string line = EatLine( Content ); - if( line.substr(0, boundary_start.size() ) != boundary_start ) - { - // Something was wrong! :( - Content.clear(); - } - - while( !Content.empty() ) - { - webserver::formdata FormData; - - static const std::string content_disposition = "Content-Disposition: "; - static const std::string content_type = "Content-Type: "; - - std::string f_disposition; - - while( 1 ) - { - std::string line = EatLine( Content ); - if( line.empty() ) - break; - - unsigned int pos_cr_lf = line.find_first_of("\x0a\x0d"); - if (pos_cr_lf == 0) break; // Empty line, indicates end of mime thingy - - if( line.substr(0, content_disposition.size() ) == content_disposition ) - { - f_disposition = line.substr(content_disposition.size()); - LOGINFO("Disposition: %s", f_disposition.c_str() ); - } - else if( line.substr(0, content_type.size() ) == content_type ) - { - FormData.content_type_ = line.substr(content_type.size()); - } - - //LOGINFO("Got line: '%s'", line.c_str() ); - } - - // Check if we got the proper headers - if( !f_disposition.empty() ) - { - static const std::string disp_name = "name="; - static const std::string disp_filename = "filename="; - - // Parse the disposition - AStringVector DispositionData = StringSplit( f_disposition, "; " ); - for( unsigned int i = 0; i < DispositionData.size(); ++i ) - { - if( DispositionData[i].substr(0, disp_name.size()) == disp_name ) - { - FormData.name_ = GetQuotedString( DispositionData[i].substr(disp_name.size()) ); - } - else if( DispositionData[i].substr(0, disp_filename.size()) == disp_filename ) - { - FormData.filename_ = GetQuotedString( DispositionData[i].substr(disp_filename.size()) ); - } - } - - std::string ContentValue; - // Parse until boundary_end is found - while( 1 ) - { - std::string line = EatLine( Content ); - if( line.empty() ) - break; - - if( line.substr(0, boundary_end.size() ) == boundary_end ) - { - break; - } - else if( line.substr(0, boundary_start.size() ) == boundary_start ) - { - break; - } - ContentValue.append( line.c_str(), line.size() ); - } - - - FormData.value_ = ContentValue; - } - - req.multipart_formdata_.push_back( FormData ); - } - } -} - - - - - -#ifdef _WIN32 -unsigned webserver::Request(void* ptr_s) -#else -void* webserver::Request(void* ptr_s) -#endif -{ - Socket* s = (reinterpret_cast(ptr_s)); - - std::string line = s->ReceiveLine(); - if (line.empty()) - { - s->Close(); - delete s; - return 0; - } - - http_request req; - std::string path; - std::map params; - size_t posStartPath = 0; - - if (line.find("GET") == 0) - { - req.method_="GET"; - posStartPath = line.find_first_not_of(" ",3); - } - else if (line.find("POST") == 0) - { - req.method_="POST"; - posStartPath = line.find_first_not_of(" ",4); - } - - SplitGetReq(line.substr(posStartPath), path, params); - - req.status_ = "202 OK"; - req.s_ = s; - req.path_ = path; - req.params_ = params; - - static const std::string authorization = "Authorization: Basic "; - static const std::string accept = "Accept: " ; - static const std::string accept_language = "Accept-Language: " ; - static const std::string accept_encoding = "Accept-Encoding: " ; - static const std::string user_agent = "User-Agent: " ; - static const std::string content_length = "Content-Length: " ; - static const std::string content_type = "Content-Type: " ; - - while(1) - { - line=s->ReceiveLine(); - if (line.empty()) - { - break; - } - - unsigned int pos_cr_lf = line.find_first_of("\x0a\x0d"); - if (pos_cr_lf == 0) break; - - line = line.substr(0,pos_cr_lf); - - if (line.substr(0, authorization.size()) == authorization) - { - req.authentication_given_ = true; - std::string encoded = line.substr(authorization.size()); - std::string decoded = base64_decode(encoded); - - unsigned int pos_colon = decoded.find(":"); - - req.username_ = decoded.substr(0, pos_colon); - req.password_ = decoded.substr(pos_colon+1 ); - } - else if (line.substr(0, accept.size()) == accept) - { - req.accept_ = line.substr(accept.size()); - } - else if (line.substr(0, accept_language.size()) == accept_language) - { - req.accept_language_ = line.substr(accept_language.size()); - } - else if (line.substr(0, accept_encoding.size()) == accept_encoding) - { - req.accept_encoding_ = line.substr(accept_encoding.size()); - } - else if (line.substr(0, user_agent.size()) == user_agent) - { - req.user_agent_ = line.substr(user_agent.size()); - } - else if (line.substr(0, content_length.size()) == content_length) - { - req.content_length_ = atoi( line.substr(content_length.size()).c_str() ); - } - else if (line.substr(0, content_type.size()) == content_type) - { - req.content_type_ = line.substr(content_type.size()); - } - } - - if( (req.method_.compare("POST") == 0) && (req.content_length_ > 0) ) - { - // The only content type we can parse at the moment, the default HTML post data - if( req.content_type_.compare( "application/x-www-form-urlencoded" ) == 0 ) - { - std::string Content = s->ReceiveBytes( req.content_length_ ); - Content.insert( 0, "/ ?" ); // Little hack, inserts dummy URL so that SplitGetReq() can work with this content - - std::string dummy; - std::map post_params; - SplitGetReq(Content, dummy, post_params); - - req.params_post_ = post_params; - } - else - { - ParseMultipartFormData( req, s ); - } - } - - request_func_(&req); - - std::stringstream str_str; - str_str << req.answer_.size(); - - time_t ltime; - time(<ime); - tm* gmt= gmtime(<ime); - -#ifdef _WIN32 - static std::string const serverName = "MCServerWebAdmin (Windows)"; -#elif __APPLE__ - static std::string const serverName = "MCServerWebAdmin (MacOSX)"; -#else - static std::string const serverName = "MCServerWebAdmin (Linux)"; -#endif - - - char* asctime_remove_nl = std::asctime(gmt); - asctime_remove_nl[24] = 0; - - s->SendBytes("HTTP/1.1 "); - - if (! req.auth_realm_.empty() ) - { - s->SendLine("401 Unauthorized"); - s->SendBytes("WWW-Authenticate: Basic Realm=\""); - s->SendBytes(req.auth_realm_); - s->SendLine("\""); - } - else - { - s->SendLine(req.status_); - } - s->SendLine(std::string("Date: ") + asctime_remove_nl + " GMT"); - s->SendLine(std::string("Server: ") +serverName); - s->SendLine("Connection: close"); - s->SendLine("Content-Type: text/html; charset=ISO-8859-1"); - s->SendLine("Content-Length: " + str_str.str()); - s->SendLine(""); - s->SendLine(req.answer_); - - s->Close( true ); // true = wait for all data to be sent before closing - delete s; - - - return 0; -} - - - - - -void webserver::Stop() -{ - m_bStop = true; - m_Socket->Close(); - m_Events->Wait(); -} - - - - - -bool webserver::Begin() -{ - if (!m_Socket->IsValid()) - { - LOGINFO("WebAdmin: The server socket is invalid. Terminating WebAdmin."); - return false; - } - m_bStop = false; - while ( !m_bStop ) - { - Socket * ptr_s = m_Socket->Accept(); - if (m_bStop) - { - if (ptr_s != 0) - { - ptr_s->Close(); - delete ptr_s; - } - break; - } - if (ptr_s == NULL) - { - LOGINFO("WebAdmin: Accepted socket is NULL. Terminating WebAdmin to avoid busywait."); - return false; - } - - #ifdef _WIN32 - unsigned ret; - HANDLE hHandle = reinterpret_cast(_beginthreadex(NULL, 0, Request, (void *)ptr_s, 0, &ret)); - CloseHandle(hHandle); - #else - // Mattes: TODO: this handle probably leaks! - pthread_t * hHandle = new pthread_t; - pthread_create( hHandle, NULL, Request, ptr_s); - #endif - } - m_Events->Set(); - return true; -} - - - - - -webserver::webserver(unsigned int port_to_listen, request_func r) -{ - m_Socket = new SocketServer(port_to_listen, 1); - - request_func_ = r; - m_Events = new cEvents(); -} - - - - - -webserver::~webserver() -{ - delete m_Socket; - delete m_Events; -} - - - - +/* + WebServer.cpp + + Copyright (C) 2003-2007 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + + Thanks to Tom Lynn who pointed out an error in this source code. +*/ + +/* + Note on point 2: + THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 +*/ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include +#ifdef _WIN32 + #include +#endif +#include +#include + + +#include "WebServer.h" +#include "cEvents.h" +#include "Socket.h" +#include "UrlHelper.h" +#include "base64.h" + + + + + +webserver::request_func webserver::request_func_ = NULL; + + + + + +static std::string EatLine( std::string& a_String ) +{ + std::string RetVal = ""; + unsigned int StringSize = a_String.size(); + const char* c = a_String.c_str(); + + for( unsigned int i = 0; i < StringSize; ++i, ++c) + { + if( *c == '\n' ) + { + RetVal += *c; +// ++i; ++c; +// if( i < StringSize ) +// { +// if( *c == '\r' ) +// { +// RetVal += *c; +// } +// } + break; + } + RetVal += *c; + } + a_String = a_String.substr( RetVal.size() ); + return RetVal; +} + + + + + +// Turns +// "blabla my string with \"quotes\"!" +// into +// blabla my string with "quotes"! +static std::string GetQuotedString( const std::string& a_String ) +{ + std::string RetVal; + + bool bGotFirstQuote = false; + bool bIgnoreNext = false; + unsigned int StrLen = a_String.size(); + for( unsigned int i = 0; i < StrLen; ++i ) + { + if( bIgnoreNext == false ) + { + if( a_String[i] == '\"' ) + { + if( bGotFirstQuote == false ) + { + bGotFirstQuote = true; + } + else + { + break; + } + continue; + } + else if( a_String[i] == '\\' ) // Escape character + { + bIgnoreNext = true; + continue; + } + } + RetVal.push_back( a_String[i] ); + bIgnoreNext = false; + } + + return RetVal; +} + + + + + +void ParseMultipartFormData( webserver::http_request& req, Socket* s) +{ + static const std::string multipart_form_data = "multipart/form-data"; + if(req.content_type_.substr(0, multipart_form_data.size()) == multipart_form_data) // Difficult data... :( + { + AStringVector ContentTypeData = StringSplit( req.content_type_, "; " ); + + std::string boundary; + // Find boundary + for( unsigned int i = 0; i < ContentTypeData.size(); ++i ) + { + static const std::string boundary_ = "boundary="; + if( ContentTypeData[i].substr(0, boundary_.size()) == boundary_ ) // Found boundary + { + boundary = ContentTypeData[i].substr( boundary_.size() ); + } + } + + //LOGINFO("Boundary: %s", boundary.c_str() ); + std::string boundary_start = "--" + boundary; + std::string boundary_end = boundary_start + "--"; + + std::string Content = s->ReceiveBytes( req.content_length_ ); + + //printf("Total content: \n%s\n", Content.c_str() ); + + // Should start with boundary! + std::string line = EatLine( Content ); + if( line.substr(0, boundary_start.size() ) != boundary_start ) + { + // Something was wrong! :( + Content.clear(); + } + + while( !Content.empty() ) + { + webserver::formdata FormData; + + static const std::string content_disposition = "Content-Disposition: "; + static const std::string content_type = "Content-Type: "; + + std::string f_disposition; + + while( 1 ) + { + std::string line = EatLine( Content ); + if( line.empty() ) + break; + + unsigned int pos_cr_lf = line.find_first_of("\x0a\x0d"); + if (pos_cr_lf == 0) break; // Empty line, indicates end of mime thingy + + if( line.substr(0, content_disposition.size() ) == content_disposition ) + { + f_disposition = line.substr(content_disposition.size()); + LOGINFO("Disposition: %s", f_disposition.c_str() ); + } + else if( line.substr(0, content_type.size() ) == content_type ) + { + FormData.content_type_ = line.substr(content_type.size()); + } + + //LOGINFO("Got line: '%s'", line.c_str() ); + } + + // Check if we got the proper headers + if( !f_disposition.empty() ) + { + static const std::string disp_name = "name="; + static const std::string disp_filename = "filename="; + + // Parse the disposition + AStringVector DispositionData = StringSplit( f_disposition, "; " ); + for( unsigned int i = 0; i < DispositionData.size(); ++i ) + { + if( DispositionData[i].substr(0, disp_name.size()) == disp_name ) + { + FormData.name_ = GetQuotedString( DispositionData[i].substr(disp_name.size()) ); + } + else if( DispositionData[i].substr(0, disp_filename.size()) == disp_filename ) + { + FormData.filename_ = GetQuotedString( DispositionData[i].substr(disp_filename.size()) ); + } + } + + std::string ContentValue; + // Parse until boundary_end is found + while( 1 ) + { + std::string line = EatLine( Content ); + if( line.empty() ) + break; + + if( line.substr(0, boundary_end.size() ) == boundary_end ) + { + break; + } + else if( line.substr(0, boundary_start.size() ) == boundary_start ) + { + break; + } + ContentValue.append( line.c_str(), line.size() ); + } + + + FormData.value_ = ContentValue; + } + + req.multipart_formdata_.push_back( FormData ); + } + } +} + + + + + +#ifdef _WIN32 +unsigned webserver::Request(void* ptr_s) +#else +void* webserver::Request(void* ptr_s) +#endif +{ + Socket* s = (reinterpret_cast(ptr_s)); + + std::string line = s->ReceiveLine(); + if (line.empty()) + { + s->Close(); + delete s; + return 0; + } + + http_request req; + std::string path; + std::map params; + size_t posStartPath = 0; + + if (line.find("GET") == 0) + { + req.method_="GET"; + posStartPath = line.find_first_not_of(" ",3); + } + else if (line.find("POST") == 0) + { + req.method_="POST"; + posStartPath = line.find_first_not_of(" ",4); + } + + SplitGetReq(line.substr(posStartPath), path, params); + + req.status_ = "202 OK"; + req.s_ = s; + req.path_ = path; + req.params_ = params; + + static const std::string authorization = "Authorization: Basic "; + static const std::string accept = "Accept: " ; + static const std::string accept_language = "Accept-Language: " ; + static const std::string accept_encoding = "Accept-Encoding: " ; + static const std::string user_agent = "User-Agent: " ; + static const std::string content_length = "Content-Length: " ; + static const std::string content_type = "Content-Type: " ; + + while(1) + { + line=s->ReceiveLine(); + if (line.empty()) + { + break; + } + + unsigned int pos_cr_lf = line.find_first_of("\x0a\x0d"); + if (pos_cr_lf == 0) break; + + line = line.substr(0,pos_cr_lf); + + if (line.substr(0, authorization.size()) == authorization) + { + req.authentication_given_ = true; + std::string encoded = line.substr(authorization.size()); + std::string decoded = base64_decode(encoded); + + unsigned int pos_colon = decoded.find(":"); + + req.username_ = decoded.substr(0, pos_colon); + req.password_ = decoded.substr(pos_colon+1 ); + } + else if (line.substr(0, accept.size()) == accept) + { + req.accept_ = line.substr(accept.size()); + } + else if (line.substr(0, accept_language.size()) == accept_language) + { + req.accept_language_ = line.substr(accept_language.size()); + } + else if (line.substr(0, accept_encoding.size()) == accept_encoding) + { + req.accept_encoding_ = line.substr(accept_encoding.size()); + } + else if (line.substr(0, user_agent.size()) == user_agent) + { + req.user_agent_ = line.substr(user_agent.size()); + } + else if (line.substr(0, content_length.size()) == content_length) + { + req.content_length_ = atoi( line.substr(content_length.size()).c_str() ); + } + else if (line.substr(0, content_type.size()) == content_type) + { + req.content_type_ = line.substr(content_type.size()); + } + } + + if( (req.method_.compare("POST") == 0) && (req.content_length_ > 0) ) + { + // The only content type we can parse at the moment, the default HTML post data + if( req.content_type_.compare( "application/x-www-form-urlencoded" ) == 0 ) + { + std::string Content = s->ReceiveBytes( req.content_length_ ); + Content.insert( 0, "/ ?" ); // Little hack, inserts dummy URL so that SplitGetReq() can work with this content + + std::string dummy; + std::map post_params; + SplitGetReq(Content, dummy, post_params); + + req.params_post_ = post_params; + } + else + { + ParseMultipartFormData( req, s ); + } + } + + request_func_(&req); + + std::stringstream str_str; + str_str << req.answer_.size(); + + time_t ltime; + time(<ime); + tm* gmt= gmtime(<ime); + +#ifdef _WIN32 + static std::string const serverName = "MCServerWebAdmin (Windows)"; +#elif __APPLE__ + static std::string const serverName = "MCServerWebAdmin (MacOSX)"; +#else + static std::string const serverName = "MCServerWebAdmin (Linux)"; +#endif + + + char* asctime_remove_nl = std::asctime(gmt); + asctime_remove_nl[24] = 0; + + s->SendBytes("HTTP/1.1 "); + + if (! req.auth_realm_.empty() ) + { + s->SendLine("401 Unauthorized"); + s->SendBytes("WWW-Authenticate: Basic Realm=\""); + s->SendBytes(req.auth_realm_); + s->SendLine("\""); + } + else + { + s->SendLine(req.status_); + } + s->SendLine(std::string("Date: ") + asctime_remove_nl + " GMT"); + s->SendLine(std::string("Server: ") +serverName); + s->SendLine("Connection: close"); + s->SendLine("Content-Type: text/html; charset=ISO-8859-1"); + s->SendLine("Content-Length: " + str_str.str()); + s->SendLine(""); + s->SendLine(req.answer_); + + s->Close( true ); // true = wait for all data to be sent before closing + delete s; + + + return 0; +} + + + + + +void webserver::Stop() +{ + m_bStop = true; + m_Socket->Close(); + m_Events->Wait(); +} + + + + + +bool webserver::Begin() +{ + if (!m_Socket->IsValid()) + { + LOGINFO("WebAdmin: The server socket is invalid. Terminating WebAdmin."); + return false; + } + m_bStop = false; + while ( !m_bStop ) + { + Socket * ptr_s = m_Socket->Accept(); + if (m_bStop) + { + if (ptr_s != 0) + { + ptr_s->Close(); + delete ptr_s; + } + break; + } + if (ptr_s == NULL) + { + LOGINFO("WebAdmin: Accepted socket is NULL. Terminating WebAdmin to avoid busywait."); + return false; + } + + #ifdef _WIN32 + unsigned ret; + HANDLE hHandle = reinterpret_cast(_beginthreadex(NULL, 0, Request, (void *)ptr_s, 0, &ret)); + CloseHandle(hHandle); + #else + // Mattes: TODO: this handle probably leaks! + pthread_t * hHandle = new pthread_t; + pthread_create( hHandle, NULL, Request, ptr_s); + #endif + } + m_Events->Set(); + return true; +} + + + + + +webserver::webserver(unsigned int port_to_listen, request_func r) +{ + m_Socket = new SocketServer(port_to_listen, 1); + + request_func_ = r; + m_Events = new cEvents(); +} + + + + + +webserver::~webserver() +{ + delete m_Socket; + delete m_Events; +} + + + + diff --git a/WebServer/base64.cpp b/WebServer/base64.cpp index 72cd7cd59..4c19b600b 100644 --- a/WebServer/base64.cpp +++ b/WebServer/base64.cpp @@ -1,99 +1,99 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "base64.h" -#include - -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - - -static inline bool is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; - - } - - return ret; - -} - -std::string base64_decode(std::string const& encoded_string) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::string ret; - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - ret += char_array_3[i]; - i = 0; - } - } - - if (i) { - for (j = i; j <4; j++) - char_array_4[j] = 0; - - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; - } - - return ret; -} + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "base64.h" +#include + +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} + +std::string base64_decode(std::string const& encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} diff --git a/WebServer/cEvents.cpp b/WebServer/cEvents.cpp index 4c9fa8775..a00a0e817 100644 --- a/WebServer/cEvents.cpp +++ b/WebServer/cEvents.cpp @@ -1,125 +1,125 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "cEvents.h" - - - - - -cEvents::cEvents( unsigned int a_NumEvents /* = 1 */ ) - : m_NumEvents( a_NumEvents ) -#ifndef _WIN32 - , m_bNamed( false ) -#endif -{ - if( m_NumEvents < 1 ) m_NumEvents = 1; - -#ifdef _WIN32 - m_Handle = new HANDLE[ m_NumEvents ]; - for( unsigned int i = 0; i < m_NumEvents; i++) - { - ((HANDLE*)m_Handle)[i] = CreateEvent( 0, FALSE, FALSE, 0 ); - } -#else - m_Handle = new sem_t*[ m_NumEvents ]; - for( unsigned int i = 0; i < m_NumEvents; i++) - { - - sem_t* & HandlePtr = ((sem_t**)m_Handle)[i]; - HandlePtr = new sem_t; - - if( sem_init( HandlePtr, 0, 0 ) ) - { - LOG("WARNING cEvents: Could not create unnamed semaphore, fallback to named."); - m_bNamed = true; - delete HandlePtr; // named semaphores return their own address - - char c_Str[32]; - sprintf( c_Str, "cEvents%p", &HandlePtr ); - HandlePtr = sem_open( c_Str, O_CREAT, 777, 0 ); - if( HandlePtr == SEM_FAILED ) - LOG("ERROR: Could not create Event. (%i)", errno); - else - if( sem_unlink( c_Str ) != 0 ) - LOG("ERROR: Could not unlink cEvents. (%i)", errno); - } - } -#endif -} - - - - - -cEvents::~cEvents() -{ -#ifdef _WIN32 - for( unsigned int i = 0; i < m_NumEvents; i++ ) - { - CloseHandle( ((HANDLE*)m_Handle)[i] ); - } - delete [] (HANDLE*)m_Handle; -#else - for( unsigned int i = 0; i < m_NumEvents; i++ ) - { - if( m_bNamed ) - { - sem_t* & HandlePtr = ((sem_t**)m_Handle)[i]; - char c_Str[32]; - sprintf( c_Str, "cEvents%p", &HandlePtr ); - // LOG("Closing event: %s", c_Str ); - // LOG("Sem ptr: %p", HandlePtr ); - if( sem_close( HandlePtr ) != 0 ) - { - LOG("ERROR: Could not close cEvents. (%i)", errno); - } - } - else - { - sem_destroy( ((sem_t**)m_Handle)[i] ); - delete ((sem_t**)m_Handle)[i]; - } - } - delete [] (sem_t**)m_Handle; m_Handle = 0; -#endif -} - - - - - -void cEvents::Wait() -{ -#ifdef _WIN32 - WaitForMultipleObjects( m_NumEvents, (HANDLE*)m_Handle, true, INFINITE ); -#else - for(unsigned int i = 0; i < m_NumEvents; i++) - { - if( sem_wait( ((sem_t**)m_Handle)[i] ) != 0 ) - { - LOG("ERROR: Could not wait for cEvents. (%i)", errno); - } - } -#endif -} - - - - - -void cEvents::Set(unsigned int a_EventNum /* = 0 */) -{ -#ifdef _WIN32 - SetEvent( ((HANDLE*)m_Handle)[a_EventNum] ); -#else - if( sem_post( ((sem_t**)m_Handle)[a_EventNum] ) != 0 ) - { - LOG("ERROR: Could not set cEvents. (%i)", errno); - } -#endif -} - - - - + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "cEvents.h" + + + + + +cEvents::cEvents( unsigned int a_NumEvents /* = 1 */ ) + : m_NumEvents( a_NumEvents ) +#ifndef _WIN32 + , m_bNamed( false ) +#endif +{ + if( m_NumEvents < 1 ) m_NumEvents = 1; + +#ifdef _WIN32 + m_Handle = new HANDLE[ m_NumEvents ]; + for( unsigned int i = 0; i < m_NumEvents; i++) + { + ((HANDLE*)m_Handle)[i] = CreateEvent( 0, FALSE, FALSE, 0 ); + } +#else + m_Handle = new sem_t*[ m_NumEvents ]; + for( unsigned int i = 0; i < m_NumEvents; i++) + { + + sem_t* & HandlePtr = ((sem_t**)m_Handle)[i]; + HandlePtr = new sem_t; + + if( sem_init( HandlePtr, 0, 0 ) ) + { + LOG("WARNING cEvents: Could not create unnamed semaphore, fallback to named."); + m_bNamed = true; + delete HandlePtr; // named semaphores return their own address + + char c_Str[32]; + sprintf( c_Str, "cEvents%p", &HandlePtr ); + HandlePtr = sem_open( c_Str, O_CREAT, 777, 0 ); + if( HandlePtr == SEM_FAILED ) + LOG("ERROR: Could not create Event. (%i)", errno); + else + if( sem_unlink( c_Str ) != 0 ) + LOG("ERROR: Could not unlink cEvents. (%i)", errno); + } + } +#endif +} + + + + + +cEvents::~cEvents() +{ +#ifdef _WIN32 + for( unsigned int i = 0; i < m_NumEvents; i++ ) + { + CloseHandle( ((HANDLE*)m_Handle)[i] ); + } + delete [] (HANDLE*)m_Handle; +#else + for( unsigned int i = 0; i < m_NumEvents; i++ ) + { + if( m_bNamed ) + { + sem_t* & HandlePtr = ((sem_t**)m_Handle)[i]; + char c_Str[32]; + sprintf( c_Str, "cEvents%p", &HandlePtr ); + // LOG("Closing event: %s", c_Str ); + // LOG("Sem ptr: %p", HandlePtr ); + if( sem_close( HandlePtr ) != 0 ) + { + LOG("ERROR: Could not close cEvents. (%i)", errno); + } + } + else + { + sem_destroy( ((sem_t**)m_Handle)[i] ); + delete ((sem_t**)m_Handle)[i]; + } + } + delete [] (sem_t**)m_Handle; m_Handle = 0; +#endif +} + + + + + +void cEvents::Wait() +{ +#ifdef _WIN32 + WaitForMultipleObjects( m_NumEvents, (HANDLE*)m_Handle, true, INFINITE ); +#else + for(unsigned int i = 0; i < m_NumEvents; i++) + { + if( sem_wait( ((sem_t**)m_Handle)[i] ) != 0 ) + { + LOG("ERROR: Could not wait for cEvents. (%i)", errno); + } + } +#endif +} + + + + + +void cEvents::Set(unsigned int a_EventNum /* = 0 */) +{ +#ifdef _WIN32 + SetEvent( ((HANDLE*)m_Handle)[a_EventNum] ); +#else + if( sem_post( ((sem_t**)m_Handle)[a_EventNum] ) != 0 ) + { + LOG("ERROR: Could not set cEvents. (%i)", errno); + } +#endif +} + + + + -- cgit v1.2.3