From aafef187ef856a36c3f8e599afea2dee44f08904 Mon Sep 17 00:00:00 2001 From: faketruth Date: Mon, 3 Oct 2011 19:25:04 +0000 Subject: Source for additional projects -jsoncpp -lua -tolua++ -WebServer -zlib -iniFile git-svn-id: http://mc-server.googlecode.com/svn/trunk@4 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- WebServer/Socket.cpp | 278 +++++++++++++++++++++++++++++++++++++++++++++++ WebServer/Socket.h | 106 ++++++++++++++++++ WebServer/StdHelpers.cpp | 61 +++++++++++ WebServer/StdHelpers.h | 65 +++++++++++ WebServer/Tracer.h | 113 +++++++++++++++++++ WebServer/UrlHelper.cpp | 167 ++++++++++++++++++++++++++++ WebServer/UrlHelper.h | 42 +++++++ WebServer/WebServer.cpp | 226 ++++++++++++++++++++++++++++++++++++++ WebServer/WebServer.h | 95 ++++++++++++++++ WebServer/base64.cpp | 96 ++++++++++++++++ WebServer/base64.h | 4 + WebServer/cEvent.cpp | 112 +++++++++++++++++++ WebServer/cEvent.h | 18 +++ 13 files changed, 1383 insertions(+) create mode 100644 WebServer/Socket.cpp create mode 100644 WebServer/Socket.h create mode 100644 WebServer/StdHelpers.cpp create mode 100644 WebServer/StdHelpers.h create mode 100644 WebServer/Tracer.h create mode 100644 WebServer/UrlHelper.cpp create mode 100644 WebServer/UrlHelper.h create mode 100644 WebServer/WebServer.cpp create mode 100644 WebServer/WebServer.h create mode 100644 WebServer/base64.cpp create mode 100644 WebServer/base64.h create mode 100644 WebServer/cEvent.cpp create mode 100644 WebServer/cEvent.h (limited to 'WebServer') diff --git a/WebServer/Socket.cpp b/WebServer/Socket.cpp new file mode 100644 index 000000000..1ae3c9f37 --- /dev/null +++ b/WebServer/Socket.cpp @@ -0,0 +1,278 @@ +/* + 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 "../source/cMCLogger.h" + +#include "Socket.h" +#include + +#ifndef _WIN32 +#include +#include +#else +#define MSG_NOSIGNAL (0) +#endif + +#ifdef __MAC_NA +#define MSG_NOSIGNAL (0) +#endif + +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_(0) { + Start(); + // UDP: use SOCK_DGRAM instead of SOCK_STREAM + s_ = socket(AF_INET,SOCK_STREAM,0); + +#ifdef _WIN32 + if(s_ ==INVALID_SOCKET) +#else + if(s_ < 0) +#endif + { + 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; +} + +void Socket::Close() { + if( s_ ) + { + closesocket(s_); + s_ = 0; + } +} + +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; + } +} + +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); + +#ifdef _WIN32 + if(s_ ==INVALID_SOCKET) +#else + if(s_ < 0) +#endif + { + 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 new_sock = accept(s_, 0, 0); +#ifdef _WIN32 + if(new_sock==INVALID_SOCKET || s_ == 0) +#else + if(new_sock < 0 || s_ == 0) +#endif + { + #ifdef _WIN32 + int rc = WSAGetLastError(); + if(rc==WSAEWOULDBLOCK) { + return 0; // non-blocking call, no request pending + } + else + #endif + { + //throw "Invalid Socket"; + return 0; + } + } + + Socket* r = new Socket(new_sock); + return r; +} + +SocketClient::SocketClient(const std::string& host, int port) : Socket() { + std::string error; + + hostent *he; + if ((he = gethostbyname(host.c_str())) == 0) { +#ifdef _WIN32 + error = strerror(errno); +#endif + throw error; + } + + sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr = *((in_addr *)he->h_addr); + memset(&(addr.sin_zero), 0, 8); + + if (::connect(s_, (sockaddr *) &addr, sizeof(sockaddr))) { +#ifdef _WIN32 + error = strerror(WSAGetLastError()); +#endif + throw error; + } +} + +#ifndef _WIN32 +struct timeval; +#endif + +SocketSelect::SocketSelect(Socket const * const s1, Socket const * const s2, TypeSocket type) { + FD_ZERO(&fds_); + FD_SET(const_cast(s1)->s_,&fds_); + if(s2) { + FD_SET(const_cast(s2)->s_,&fds_); + } + +#ifdef _WIN32 + TIMEVAL *ptval = 0; +#else + timeval *ptval = 0; +#endif + + if (select (0, &fds_, (fd_set*) 0, (fd_set*) 0, ptval) == SOCKET_ERROR) + throw "Error in select"; +} + +bool SocketSelect::Readable(Socket const* const s) { + if (FD_ISSET(s->s_,&fds_)) return true; + return false; +} diff --git a/WebServer/Socket.h b/WebServer/Socket.h new file mode 100644 index 000000000..777f696ce --- /dev/null +++ b/WebServer/Socket.h @@ -0,0 +1,106 @@ +/* + Socket.h + + 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 +*/ + +#ifndef SOCKET_H +#define SOCKET_H + +#include "../source/MCSocket.h" +#ifdef _WIN32 +#include +#endif + +#include + +enum TypeSocket {BlockingSocket, NonBlockingSocket}; + +class Socket { +public: + + virtual ~Socket(); + Socket(const Socket&); + Socket& operator=(Socket&); + + std::string ReceiveLine(); + std::string ReceiveBytes(); + + void Close(); + + // The parameter of SendLine is not a const reference + // because SendLine modifes the std::string passed. + void SendLine (std::string); + + // The parameter of SendBytes is a const reference + // because SendBytes does not modify the std::string passed + // (in contrast to SendLine). + void SendBytes(const std::string&); + +protected: + friend class SocketServer; + friend class SocketSelect; + + Socket(SOCKET s); + Socket(); + + + SOCKET s_; + + int* refCounter_; + +private: + static void Start(); + static void End(); + static int nofSockets_; +}; + +class SocketClient : public Socket { +public: + SocketClient(const std::string& host, int port); +}; + +class SocketServer : public Socket { +public: + SocketServer(int port, int connections, TypeSocket type=BlockingSocket); + + Socket* Accept(); +}; + +// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/wsapiref_2tiq.asp +class SocketSelect { + public: + SocketSelect(Socket const * const s1, Socket const * const s2=NULL, TypeSocket type=BlockingSocket); + + bool Readable(Socket const * const s); + + private: + fd_set fds_; +}; + +#endif diff --git a/WebServer/StdHelpers.cpp b/WebServer/StdHelpers.cpp new file mode 100644 index 000000000..6bb05f421 --- /dev/null +++ b/WebServer/StdHelpers.cpp @@ -0,0 +1,61 @@ +/* + 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 "StdHelpers.h" +#include +#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/StdHelpers.h b/WebServer/StdHelpers.h new file mode 100644 index 000000000..e9efa3dc2 --- /dev/null +++ b/WebServer/StdHelpers.h @@ -0,0 +1,65 @@ +/* + stdHelpers.h + + Copyright (C) 2002-2005 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 +*/ + +#ifndef STDHELPERS_H__ +#define STDHELPERS_H__ + +#include +#include + +std::string ReplaceInStr(const std::string& in, const std::string& search_for, const std::string& replace_with); + +void ToUpper(std::string& s); +void ToLower(std::string& s); + +template +T To(std::string const& s) { + T ret; + + std::stringstream stream; + stream << s; + stream >> ret; + + return ret; +} + +template +std::string StringFrom(T const& t) { + std::string ret; + + std::stringstream stream; + stream << t; + stream >> ret; + + return ret; +} + +#endif \ No newline at end of file diff --git a/WebServer/Tracer.h b/WebServer/Tracer.h new file mode 100644 index 000000000..bce350219 --- /dev/null +++ b/WebServer/Tracer.h @@ -0,0 +1,113 @@ +/* + Tracer.h + + 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. + + The most current version of Tracer.h can be found at + http://www.adp-gmbh.ch/cpp/common/Tracer.html + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch +*/ + +/* + Note on point 2: + THIS IS NOT THE ORIGINAL SOURCE1!!1!!!~!!~`1ONE!!`1 +*/ + +#ifndef TRACER_H__ +#define TRACER_H__ + +#ifdef DO_TRACE + +#include +#include + +#include + +#define StartTrace(x) TraceFunc_::StartTrace_(x) +#define Trace(x) dummy_____for_trace_func______.Trace_(x) +#define Trace2(x,y) dummy_____for_trace_func______.Trace_(x,y) +#define TraceFunc(x) TraceFunc_ dummy_____for_trace_func______(x) +#define TraceFunc2(x,y) TraceFunc_ dummy_____for_trace_func______(x,y) + +class TraceFunc_ { + std::string func_name_; + public: + /* + Calling TraceFunc_ indents the output until the enclosing scope ( {...} ) + is left. + */ + TraceFunc_(std::string const&); + TraceFunc_(std::string const&, std::string const& something); + ~TraceFunc_(); + + /* + Creates the trace output file named by filename. + Must be called before any other tracing function. + Use the StartTrace macro for it. + */ + static void StartTrace_(std::string const& filename); + + template + void Trace_(T const& t) { + DWORD d; + std::string indent_s; + std::stringstream s; + + s << t; + + for (int i=0; i< indent; i++) indent_s += " "; + + ::WriteFile(trace_file_,indent_s.c_str(), indent_s.size(), &d, 0); + ::WriteFile(trace_file_, s.str().c_str(), s.str().size() ,&d, 0); + ::WriteFile(trace_file_,"\x0a",1,&d,0); + } + + template + void Trace_(T const& t, U const& u) { + std::string indent_s; + std::stringstream s; + + s << t; + s << u; + Trace_(s.str()); + } + + static int indent; + /* trace_file_ is a HANDLE for the file in which the traced output goes. + The file is opened (that is, created) by calling StartTrace_. + Better yet, use the StartTrace macro + to create the file. + */ + static HANDLE trace_file_; +}; + +#else + +#define StartTrace(x) +#define Trace(x) +#define Trace2(x,y) +#define TraceFunc(x) +#define TraceFunc2(x,y) + +#endif + +#endif // TRACER_H__ diff --git a/WebServer/UrlHelper.cpp b/WebServer/UrlHelper.cpp new file mode 100644 index 000000000..3cdb0fc60 --- /dev/null +++ b/WebServer/UrlHelper.cpp @@ -0,0 +1,167 @@ +/* + 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 "UrlHelper.h" +#include "Tracer.h" +#include "StdHelpers.h" + +#ifdef _WIN32 +#include +#endif + +#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/UrlHelper.h b/WebServer/UrlHelper.h new file mode 100644 index 000000000..06ab00446 --- /dev/null +++ b/WebServer/UrlHelper.h @@ -0,0 +1,42 @@ +/* + UrlHelper.h + + 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 +*/ +#ifndef __URL_HELPER_H__ +#define __URL_HELPER_H__ + +#include +#include + +void SplitUrl (std::string const& url, std::string& protocol, std::string& server, std::string& path); +bool RemoveProtocolFromUrl(std::string const& url, std::string& protocol, std::string& rest); + +void SplitGetReq (std::string et_req, std::string& path, std::map& params); + +#endif diff --git a/WebServer/WebServer.cpp b/WebServer/WebServer.cpp new file mode 100644 index 000000000..954791663 --- /dev/null +++ b/WebServer/WebServer.cpp @@ -0,0 +1,226 @@ +/* + 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 +#ifdef _WIN32 +#include +#endif +#include +#include +#include +#include + + +#include "WebServer.h" +#include "Socket.h" +#include "UrlHelper.h" +#include "base64.h" + +#include "cEvent.h" + + +webserver::request_func webserver::request_func_=0; + +#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; + + if (line.find("GET") == 0) { + req.method_="GET"; + } + else if (line.find("POST") == 0) { + req.method_="POST"; + } + + std::string path; + std::map params; + + size_t posStartPath = line.find_first_not_of(" ",3); + + 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: " ; + + 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()); + } + } + + 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(); + delete s; + + + return 0; +} + +void webserver::Stop() +{ + m_bStop = true; + m_Socket->Close(); + m_Event->Wait(); +} + +void webserver::Begin() +{ + 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; + } + + // unused variable 'ret' + //_beginthreadex(0,0,Request,(void*) ptr_s,0,&ret); + // Thanks to Frank M. Hoffmann for fixing a HANDLE leak + #ifdef _WIN32 + unsigned ret; + HANDLE hHandle = reinterpret_cast(_beginthreadex(0,0,Request,(void*) ptr_s,0,&ret)); + CloseHandle(hHandle); + #else + pthread_t* hHandle = new pthread_t; + pthread_create( hHandle, NULL, Request, ptr_s); + #endif + } + m_Event->Set(); +} + +webserver::webserver(unsigned int port_to_listen, request_func r) { + m_Socket = new SocketServer(port_to_listen,1); + + request_func_ = r; + m_Event = new cEvent(); +} + +webserver::~webserver() +{ + delete m_Socket; + delete m_Event; +} diff --git a/WebServer/WebServer.h b/WebServer/WebServer.h new file mode 100644 index 000000000..06c6359e6 --- /dev/null +++ b/WebServer/WebServer.h @@ -0,0 +1,95 @@ +/* + WebServer.h + + Copyright (C) 2003-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 +#include + +class cEvent; +class Socket; +class SocketServer; +class webserver { + public: + struct http_request { + + http_request() + : s_( 0 ) + , authentication_given_(false) + {} + + Socket* s_; + std::string method_; + std::string path_; + std::map params_; + + std::string accept_; + std::string accept_language_; + std::string accept_encoding_; + std::string user_agent_; + + /* status_: used to transmit server's error status, such as + o 202 OK + o 404 Not Found + and so on */ + std::string status_; + + /* auth_realm_: allows to set the basic realm for an authentication, + no need to additionally set status_ if set */ + std::string auth_realm_; + + std::string answer_; + + /* authentication_given_ is true when the user has entered a username and password. + These can then be read from username_ and password_ */ + bool authentication_given_; + std::string username_; + std::string password_; + }; + + typedef void (*request_func) (http_request*); + webserver(unsigned int port_to_listen, request_func); + ~webserver(); + + void Begin(); + void Stop(); + + private: + bool m_bStop; + #ifdef _WIN32 + static unsigned __stdcall Request(void*); + #else + static void* Request(void*); + #endif + static request_func request_func_; + + cEvent* m_Event; + SocketServer* m_Socket; +}; diff --git a/WebServer/base64.cpp b/WebServer/base64.cpp new file mode 100644 index 000000000..8a6f33147 --- /dev/null +++ b/WebServer/base64.cpp @@ -0,0 +1,96 @@ +#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/base64.h b/WebServer/base64.h new file mode 100644 index 000000000..91b731417 --- /dev/null +++ b/WebServer/base64.h @@ -0,0 +1,4 @@ +#include + +std::string base64_encode(unsigned char const* , unsigned int len); +std::string base64_decode(std::string const& s); diff --git a/WebServer/cEvent.cpp b/WebServer/cEvent.cpp new file mode 100644 index 000000000..289131568 --- /dev/null +++ b/WebServer/cEvent.cpp @@ -0,0 +1,112 @@ +#include "cEvent.h" +#include "../source/cMCLogger.h" + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include // sprintf() +#endif + +cEvent::cEvent( 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 cEvent: 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, "cEvent%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 cEvent. (%i)", errno); + } + } +#endif +} + +cEvent::~cEvent() +{ +#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, "cEvent%p", &HandlePtr ); + // LOG("Closing event: %s", c_Str ); + // LOG("Sem ptr: %p", HandlePtr ); + if( sem_close( HandlePtr ) != 0 ) + { + LOG("ERROR: Could not close cEvent. (%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 cEvent::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 cEvent. (%i)", errno); + } + } +#endif +} + +void cEvent::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 cEvent. (%i)", errno); + } +#endif +} diff --git a/WebServer/cEvent.h b/WebServer/cEvent.h new file mode 100644 index 000000000..e5b77be50 --- /dev/null +++ b/WebServer/cEvent.h @@ -0,0 +1,18 @@ +#pragma once + +class cEvent +{ +public: + cEvent( unsigned int a_NumEvents = 1 ); + ~cEvent(); + + void Wait(); + void Set(unsigned int a_EventNum = 0); +private: + unsigned int m_NumEvents; + void* m_Handle; // HANDLE[] pointer + +#ifndef _WIN32 + bool m_bNamed; +#endif +}; -- cgit v1.2.3