Rene Nyffenegger

First compilation

*.swp
*.o
WebServer.exe
[submodule "socket"]
path = socket
url = https://github.com/ReneNyffenegger/Socket.cpp
[submodule "base64"]
path = base64
url = https://github.com/ReneNyffenegger/cpp-base64
/*
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.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#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:
TraceFunc_(std::string const&);
TraceFunc_(std::string const&, std::string const&);
~TraceFunc_();
static void StartTrace_(std::string const& file_name);
template <typename 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) {
DWORD d;
std::string indent_s;
std::stringstream s;
s << t;
s << u;
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);
}
static int indent;
static HANDLE trace_file_;
};
#else
#define StartTrace(x)
#define Trace(x)
#define Trace2(x,y)
#define TraceFunc(x)
#define TraceFunc2(x,y)
#endif // DO_TRACE
#endif // __TRACER_H__
/*
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
*/
#include "UrlHelper.h"
#include "Tracer.h"
#include "stdHelpers.h"
#include <windows.h>
#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;
}
}
/*
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
*/
#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
base64 @ 26a73f38
Subproject commit 26a73f38176434075d1f056bf5d207ee20918c26
rem set INC_DIR_SOCKET=socket\src
rem set GCC_FLAGS=-I %INC_DIR_SOCKET%
g++ -I socket\src -I base64 -c webserver.cpp
g++ -I socket\src -c main.cpp
g++ -c stdHelpers.cpp
g++ -c UrlHelper.cpp
g++ -I socket\src -c socket\src\Socket.cpp -o Socket.o
g++ -c base64\base64.cpp -o base64.o
g++ webserver.o base64.o main.o stdHelpers.o UrlHelper.o Socket.o -lwsock32 -o WebServer.exe
#include "webserver.h"
#include "Socket.h"
void Request_Handler(webserver::http_request* r) {
Socket s = *(r->s_);
std::string title;
std::string body;
std::string bgcolor="#ffffff";
std::string links =
"<p><a href='/red'>red</a> "
"<br><a href='/blue'>blue</a> "
"<br><a href='/form'>form</a> "
"<br><a href='/auth'>authentication example</a> [use <b>rene</b> as username and <b>secretGarden</b> as password"
"<br><a href='/header'>show some HTTP header details</a> "
;
if(r->path_ == "/") {
title = "Web Server Example";
body = "<h1>Welcome to Rene's Web Server</h1>"
"I wonder what you're going to click" + links;
}
else if (r->path_ == "/red") {
bgcolor = "#ff4444";
title = "You chose red";
body = "<h1>Red</h1>" + links;
}
else if (r->path_ == "/blue") {
bgcolor = "#4444ff";
title = "You chose blue";
body = "<h1>Blue</h1>" + links;
}
else if (r->path_ == "/form") {
title = "Fill a form";
body = "<h1>Fill a form</h1>";
body += "<form action='/form'>"
"<table>"
"<tr><td>Field 1</td><td><input name=field_1></td></tr>"
"<tr><td>Field 2</td><td><input name=field_2></td></tr>"
"<tr><td>Field 3</td><td><input name=field_3></td></tr>"
"</table>"
"<input type=submit></form>";
for (std::map<std::string, std::string>::const_iterator i = r->params_.begin();
i != r->params_.end();
i++) {
body += "<br>" + i->first + " = " + i->second;
}
body += "<hr>" + links;
}
else if (r->path_ == "/auth") {
if (r->authentication_given_) {
if (r->username_ == "rene" && r->password_ == "secretGarden") {
body = "<h1>Successfully authenticated</h1>" + links;
}
else {
body = "<h1>Wrong username or password</h1>" + links;
r->auth_realm_ = "Private Stuff";
}
}
else {
r->auth_realm_ = "Private Stuff";
}
}
else if (r->path_ == "/header") {
title = "some HTTP header details";
body = std::string ("<table>") +
"<tr><td>Accept:</td><td>" + r->accept_ + "</td></tr>" +
"<tr><td>Accept-Encoding:</td><td>" + r->accept_encoding_ + "</td></tr>" +
"<tr><td>Accept-Language:</td><td>" + r->accept_language_ + "</td></tr>" +
"<tr><td>User-Agent:</td><td>" + r->user_agent_ + "</td></tr>" +
"</table>" +
links;
}
else {
r->status_ = "404 Not Found";
title = "Wrong URL";
body = "<h1>Wrong URL</h1>";
body += "Path is : &gt;" + r->path_ + "&lt;";
}
r->answer_ = "<html><head><title>";
r->answer_ += title;
r->answer_ += "</title></head><body bgcolor='" + bgcolor + "'>";
r->answer_ += body;
r->answer_ += "</body></html>";
}
int main() {
webserver(8080, Request_Handler);
}
socket @ 713768b9
Subproject commit 713768b97514363aede0b77a96fa8af59e952b5f
/*
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
*/
#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_);
}
/*
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
*/
#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
/*
WebServer.cpp
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
Thanks to Tom Lynn who pointed out an error in this source code.
*/
#include <ctime>
#include <process.h>
#include <iostream>
#include <string>
#include <map>
#include <sstream>
//<process.h>
#include "webserver.h"
#include "socket.h"
#include "UrlHelper.h"
#include "base64.h"
webserver::request_func webserver::request_func_=0;
unsigned webserver::Request(void* ptr_s) {
Socket s = *(reinterpret_cast<Socket*>(ptr_s));
std::string line = s.ReceiveLine();
if (line.empty()) {
return 1;
}
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(&ltime);
tm* gmt= gmtime(&ltime);
static std::string const serverName = "RenesWebserver (Windows)";
char* asctime_remove_nl = 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();
return 0;
}
webserver::webserver(unsigned int port_to_listen, request_func r) {
SocketServer in(port_to_listen,5);
request_func_ = r;
while (1) {
Socket* ptr_s=in.Accept();
unsigned ret;
_beginthreadex(0,0,Request,(void*) ptr_s,0,&ret);
}
}
/*
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
*/
#include <string>
#include <map>
class Socket;
class webserver {
public:
struct http_request {
http_request() : 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);
private:
static unsigned __stdcall Request(void*);
static request_func request_func_;
};