diff options
Diffstat (limited to '')
-rw-r--r-- | WebServer/Socket.cpp | 278 | ||||
-rw-r--r-- | WebServer/Socket.h | 106 | ||||
-rw-r--r-- | WebServer/StdHelpers.cpp | 61 | ||||
-rw-r--r-- | WebServer/StdHelpers.h | 65 | ||||
-rw-r--r-- | WebServer/Tracer.h | 113 | ||||
-rw-r--r-- | WebServer/UrlHelper.cpp | 167 | ||||
-rw-r--r-- | WebServer/UrlHelper.h | 42 | ||||
-rw-r--r-- | WebServer/WebServer.cpp | 226 | ||||
-rw-r--r-- | WebServer/WebServer.h | 95 | ||||
-rw-r--r-- | WebServer/base64.cpp | 96 | ||||
-rw-r--r-- | WebServer/base64.h | 4 | ||||
-rw-r--r-- | WebServer/cEvent.cpp | 112 | ||||
-rw-r--r-- | WebServer/cEvent.h | 18 |
13 files changed, 1383 insertions, 0 deletions
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 <iostream>
+
+#ifndef _WIN32
+#include <cstring>
+#include <sys/time.h>
+#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<Socket*>(s1)->s_,&fds_);
+ if(s2) {
+ FD_SET(const_cast<Socket*>(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 <winsock2.h>
+#endif
+
+#include <string>
+
+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 <algorithm>
+#include <cctype>
+
+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 <string>
+#include <sstream>
+
+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 <class T>
+T To(std::string const& s) {
+ T ret;
+
+ std::stringstream stream;
+ stream << s;
+ stream >> ret;
+
+ return ret;
+}
+
+template<class T>
+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 <string>
+#include <sstream>
+
+#include <windows.h>
+
+#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 <class T>
+ 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 <class T, class U>
+ 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 <windows.h>
+#endif
+
+#include <sstream>
+#include <iostream>
+
+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<std::string, std::string>& 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<char>(i);
+ std::string s;
+ f >> s;
+
+ val.replace(pos_hex, 3, s);
+ pos_hex ++;
+ }
+
+ params.insert(std::map<std::string,std::string>::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 <string>
+#include <map>
+
+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<std::string, std::string>& 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 <ctime>
+#ifdef _WIN32
+#include <process.h>
+#endif
+#include <iostream>
+#include <string>
+#include <map>
+#include <sstream>
+
+
+#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<Socket*>(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<std::string, std::string> 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<HANDLE>(_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 <string>
+#include <map>
+
+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<std::string, std::string> 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 <iostream>
+
+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 <string>
+
+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 <Windows.h>
+#else
+#include <semaphore.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h> // 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
+}; |