Initial commit
This commit is contained in:
82
.gitignore
vendored
Normal file
82
.gitignore
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
# Snippets taken from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
|
||||
[Dd]ebug/x64/
|
||||
[Dd]ebugPublic/x64/
|
||||
[Rr]elease/x64/
|
||||
[Rr]eleases/x64/
|
||||
bin/x64/
|
||||
obj/x64/
|
||||
|
||||
[Dd]ebug/x86/
|
||||
[Dd]ebugPublic/x86/
|
||||
[Rr]elease/x86/
|
||||
[Rr]eleases/x86/
|
||||
bin/x86/
|
||||
obj/x86/
|
||||
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
[Aa][Rr][Mm]64[Ee][Cc]/
|
||||
bld/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.idb
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
# but not Directory.Build.rsp, as it configures directory-level build defaults
|
||||
!Directory.Build.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
48
Main.cpp
Normal file
48
Main.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "Windows.h"
|
||||
|
||||
#include "Router.h"
|
||||
#include "Terminal.h"
|
||||
#include "Resource.h"
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
SetConsoleMode((HANDLE)(size_t)STD_OUTPUT_HANDLE, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
|
||||
|
||||
std::string req_raw =
|
||||
"GET /url/path HTTP/1.1\r\n"
|
||||
"Host: example.com\r\n"
|
||||
"Host: www.example.com\r\n"
|
||||
"User - Agent : Mozilla / 5.0\r\n"
|
||||
"Accept : text / html, application / xhtml + xml, application / xml; q = 0.9, image / avif, image / webp, */*;q=0.8\r\n"
|
||||
"Accept-Language: en-GB,en;q=0.5\r\n"
|
||||
"Accept-Encoding: gzip, deflate, br\r\n"
|
||||
"Connection: keep-alive\r\n"
|
||||
"\r\n";
|
||||
std::stringstream req(req_raw);
|
||||
|
||||
|
||||
Router router;
|
||||
|
||||
router.on_get("/", [&](Request& req, Response& res, Next next) {
|
||||
Resource src(INDEX, HTML_FILE);
|
||||
res.header("Content-Type", "text/html");
|
||||
res.send(src.data(), src.size());
|
||||
});
|
||||
|
||||
router.on_get("/url/path", [&](Request& req, Response& res, Next next) {
|
||||
res.send("Hello, World!");
|
||||
});
|
||||
|
||||
std::stringstream res;
|
||||
router.handle(req, res);
|
||||
|
||||
std::cout << CYAN << res.str() << RESET << std::endl;
|
||||
|
||||
router.listen(8080);
|
||||
}
|
||||
17
RC.h
Normal file
17
RC.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
class RC
|
||||
{
|
||||
public:
|
||||
RC() : _rc(new int[1]) { *_rc = 1; };
|
||||
RC(const RC &r) noexcept : _rc(r._rc) { *_rc += 1; }
|
||||
RC(RC &&r) noexcept : _rc(r._rc) { }
|
||||
~RC() { if (!--*_rc) delete[] _rc; };
|
||||
|
||||
int rc() { return *_rc; }
|
||||
bool last() { return *_rc == 1; }
|
||||
|
||||
private:
|
||||
int* _rc;
|
||||
};
|
||||
106
Resource.cpp
Normal file
106
Resource.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include "Resource.h"
|
||||
|
||||
#include <streambuf>
|
||||
#include <istream>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
|
||||
static HMODULE GetCurrentModule()
|
||||
{
|
||||
HMODULE hModule = NULL;
|
||||
GetModuleHandleEx(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
(LPCTSTR)GetCurrentModule,
|
||||
&hModule
|
||||
);
|
||||
|
||||
return hModule;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class ResBuf : public std::streambuf
|
||||
{
|
||||
public:
|
||||
ResBuf(int id, int type)
|
||||
{
|
||||
HMODULE hMod = GetCurrentModule();
|
||||
|
||||
HRSRC hRes = FindResource(hMod, MAKEINTRESOURCE(id), MAKEINTRESOURCE(type));
|
||||
if (!hRes)
|
||||
{
|
||||
throw std::exception("Could not find resource");
|
||||
}
|
||||
|
||||
HGLOBAL hResLoad = LoadResource(hMod, hRes);
|
||||
if (!hResLoad)
|
||||
{
|
||||
throw std::exception("Could not load resource");
|
||||
}
|
||||
|
||||
LPVOID lpResLock = LockResource(hResLoad);
|
||||
if (!lpResLock)
|
||||
{
|
||||
throw std::exception("Could not lock resource");
|
||||
}
|
||||
|
||||
DWORD dwResSize = SizeofResource(hMod, hRes);
|
||||
if (dwResSize == 0)
|
||||
{
|
||||
throw std::exception("Could not aquire resource size");
|
||||
}
|
||||
|
||||
_hRes = hRes;
|
||||
_buff = (char*)lpResLock;
|
||||
_size = dwResSize;
|
||||
|
||||
setg(_buff, _buff, _buff + _size);
|
||||
}
|
||||
|
||||
virtual ~ResBuf()
|
||||
{
|
||||
FreeResource(_hRes);
|
||||
}
|
||||
|
||||
virtual int underflow()
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
|
||||
char* buff()
|
||||
{
|
||||
return _buff;
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
private:
|
||||
HRSRC _hRes;
|
||||
char* _buff;
|
||||
size_t _size;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Resource::Resource(int id, int type) : std::istream(new ResBuf(id, type))
|
||||
{
|
||||
}
|
||||
|
||||
Resource::~Resource()
|
||||
{
|
||||
delete rdbuf();
|
||||
}
|
||||
|
||||
const char* Resource::data()
|
||||
{
|
||||
return (const char*)(((ResBuf*)rdbuf())->buff());
|
||||
}
|
||||
|
||||
size_t Resource::size()
|
||||
{
|
||||
return ((ResBuf*)rdbuf())->size();
|
||||
}
|
||||
19
Resource.h
Normal file
19
Resource.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <istream>
|
||||
|
||||
#include "_resource.h"
|
||||
|
||||
|
||||
class Resource : public std::istream
|
||||
{
|
||||
public:
|
||||
Resource(int id, int type);
|
||||
virtual ~Resource();
|
||||
|
||||
Resource(const Resource&) = delete;
|
||||
Resource(Resource&&) = delete;
|
||||
|
||||
const char* data();
|
||||
size_t size();
|
||||
};
|
||||
507
Router.cpp
Normal file
507
Router.cpp
Normal file
@ -0,0 +1,507 @@
|
||||
#include "Router.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <streambuf>
|
||||
#include <iostream> // Only for warning when handling client error
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
#include "Socket.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
|
||||
static std::map<int, const char*> STATUS_STR =
|
||||
{
|
||||
{ 100, "Continue" },
|
||||
{ 101, "Switching Protocols" },
|
||||
{ 102, "Processing" },
|
||||
{ 103, "Early Hints" },
|
||||
{ 104, "Upload Resumption Supported" },
|
||||
{ 200, "OK" },
|
||||
{ 201, "Created" },
|
||||
{ 202, "Accepted" },
|
||||
{ 203, "Non - Authoritative Information" },
|
||||
{ 204, "No Content" },
|
||||
{ 205, "Reset Content" },
|
||||
{ 206, "Partial Content" },
|
||||
{ 207, "Multi - Status" },
|
||||
{ 208, "Already Reported" },
|
||||
{ 226, "IM Used" },
|
||||
{ 300, "Multiple Choices" },
|
||||
{ 301, "Moved Permanently" },
|
||||
{ 302, "Found" },
|
||||
{ 303, "See Other" },
|
||||
{ 304, "Not Modified" },
|
||||
{ 305, "Use Proxy" },
|
||||
{ 306, "Switch Proxy" },
|
||||
{ 307, "Temporary Redirect" },
|
||||
{ 308, "Permanent Redirect" },
|
||||
{ 400, "Bad Request" },
|
||||
{ 401, "Unauthorized" },
|
||||
{ 402, "Payment Required" },
|
||||
{ 403, "Forbidden" },
|
||||
{ 404, "Not Found" },
|
||||
{ 405, "Method Not Allowed" },
|
||||
{ 406, "Not Acceptable" },
|
||||
{ 407, "Proxy Authentication Required" },
|
||||
{ 408, "Request Timeout" },
|
||||
{ 409, "Conflict" },
|
||||
{ 410, "Gone" },
|
||||
{ 411, "Length Required" },
|
||||
{ 412, "Precondition Failed" },
|
||||
{ 413, "Content Too Large" },
|
||||
{ 414, "URI Too Long" },
|
||||
{ 415, "Unsupported Media Type" },
|
||||
{ 416, "Range Not Satisfiable" },
|
||||
{ 417, "Expectation Failed" },
|
||||
{ 418, "I<EFBFBD>m a Teapot" },
|
||||
{ 421, "Misdirected Request" },
|
||||
{ 422, "Unprocessable Content" },
|
||||
{ 423, "Locked" },
|
||||
{ 424, "Failed Dependency" },
|
||||
{ 425, "Too Early" },
|
||||
{ 426, "Upgrade Required" },
|
||||
{ 427, "Unassigned" },
|
||||
{ 428, "Precondition Required" },
|
||||
{ 429, "Too Many Requests" },
|
||||
{ 430, "Unassigned" },
|
||||
{ 431, "Request Header Fields Too Large" },
|
||||
{ 451, "Unavailable For Legal Reasons" },
|
||||
{ 500, "Internal Server Error" },
|
||||
{ 501, "Not Implemented" },
|
||||
{ 502, "Bad Gateway" },
|
||||
{ 503, "Service Unavailable" },
|
||||
{ 504, "Gateway Timeout" },
|
||||
{ 505, "HTTP Version Not Supported" },
|
||||
{ 506, "Variant Also Negotiates" },
|
||||
{ 507, "Insufficient Storage" },
|
||||
{ 508, "Loop Detected" },
|
||||
{ 509, "Unassigned" },
|
||||
{ 510, "Not Extended" },
|
||||
{ 511, "Network Authentication Required" },
|
||||
};
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
class ClientError : public std::exception
|
||||
{
|
||||
public:
|
||||
ClientError(const char* what) : std::exception(what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ReqBuf : public std::streambuf
|
||||
{
|
||||
public:
|
||||
ReqBuf(std::istream& stream) : _stream(stream)
|
||||
{
|
||||
constexpr int header_max = 64;
|
||||
constexpr int line_max = 512;
|
||||
|
||||
for (int n = 0;; n++)
|
||||
{
|
||||
if (n == header_max)
|
||||
{
|
||||
throw ClientError("Too many headers");
|
||||
}
|
||||
|
||||
std::string line;
|
||||
line += (char)_stream.get();
|
||||
line += (char)_stream.get();
|
||||
while (line.substr(line.size() - 2, 2) != "\r\n")
|
||||
{
|
||||
int byte = _stream.get();
|
||||
if (byte == EOF)
|
||||
{
|
||||
throw ClientError("Connection closed prmaturely");
|
||||
}
|
||||
if (line.size() > line_max)
|
||||
{
|
||||
throw ClientError("Header field too long");
|
||||
}
|
||||
line += (char)byte;
|
||||
}
|
||||
|
||||
if (line == "\r\n")
|
||||
break;
|
||||
|
||||
line = line.substr(0, line.size() - 2);
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
std::vector<std::string> req = StringUtil::splitClean(line, ' ');
|
||||
method = req[0];
|
||||
url = req[1];
|
||||
http_version = req[2];
|
||||
|
||||
std::transform(method.begin(), method.end(), method.begin(), ::toupper);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t sep = line.find(':');
|
||||
std::string name = StringUtil::strip(line.substr(0, sep));
|
||||
std::string value = StringUtil::strip(line.substr(sep + 1));
|
||||
headers[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual int underflow()
|
||||
{
|
||||
return _stream.get();
|
||||
}
|
||||
|
||||
std::string method, url, http_version;
|
||||
std::map<std::string, std::string> headers;
|
||||
|
||||
private:
|
||||
std::istream& _stream;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#define buf ((ReqBuf*)rdbuf())
|
||||
Request::Request(std::istream& stream) : std::istream(new ReqBuf(stream))
|
||||
{
|
||||
}
|
||||
|
||||
Request::~Request()
|
||||
{
|
||||
delete rdbuf();
|
||||
}
|
||||
|
||||
std::string Request::url() const
|
||||
{
|
||||
return buf->url;
|
||||
}
|
||||
|
||||
std::string Request::method() const
|
||||
{
|
||||
return buf->method;
|
||||
}
|
||||
|
||||
const std::string* Request::header(std::string name) const
|
||||
{
|
||||
auto field = buf->headers.find(name);
|
||||
if (field == buf->headers.end())
|
||||
return nullptr;
|
||||
return &field->second;
|
||||
}
|
||||
#undef buf
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
class ResBuf : public std::streambuf
|
||||
{
|
||||
public:
|
||||
ResBuf(std::ostream& stream) : _stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
void send_head()
|
||||
{
|
||||
if (head_sent)
|
||||
throw std::exception("Head has already been sent");
|
||||
head_sent = true;
|
||||
|
||||
_stream
|
||||
<< "HTTP/1.1 " << status << ' ' << STATUS_STR[status] << "\r\n";
|
||||
|
||||
for (auto& pair : headers)
|
||||
_stream << pair.first << ": " << pair.second << "\r\n";
|
||||
|
||||
_stream << "\r\n";
|
||||
}
|
||||
|
||||
int status = 200;
|
||||
bool head_sent = false;
|
||||
std::map<std::string, std::string> headers = {
|
||||
{"Connection", "Close"},
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual int overflow(int c) override
|
||||
{
|
||||
if (!head_sent)
|
||||
send_head();
|
||||
_stream.put(c);
|
||||
return c;
|
||||
}
|
||||
|
||||
virtual int sync() override
|
||||
{
|
||||
_stream.flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream& _stream;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#define buf ((ResBuf*)rdbuf())
|
||||
Response::Response(std::ostream& stream) : std::ostream(new ResBuf(stream))
|
||||
{
|
||||
}
|
||||
|
||||
Response::~Response()
|
||||
{
|
||||
delete rdbuf();
|
||||
}
|
||||
|
||||
void Response::status(int status)
|
||||
{
|
||||
buf->status = status;
|
||||
}
|
||||
|
||||
void Response::header(std::string name, std::string value)
|
||||
{
|
||||
if (buf->head_sent)
|
||||
throw std::exception("Headers already sent.");
|
||||
buf->headers[name] = value;
|
||||
}
|
||||
|
||||
void Response::send(std::string text)
|
||||
{
|
||||
if (buf->headers.find("Content-Type") == buf->headers.end())
|
||||
header("Content-Type", "text/plain");
|
||||
header("Content-Length", text.size());
|
||||
|
||||
*this << text;
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
void Response::send(const void* data, size_t size)
|
||||
{
|
||||
if (buf->headers.find("Content-Type") == buf->headers.end())
|
||||
header("Content-Type", "application/octet-stream");
|
||||
header("Content-Length", size);
|
||||
|
||||
write((const char*)data, size);
|
||||
|
||||
flush();
|
||||
}
|
||||
|
||||
void Response::sendFile(std::string filename)
|
||||
{
|
||||
std::ifstream fs(filename, std::ifstream::binary | std::ifstream::ate);
|
||||
|
||||
if (!fs.is_open())
|
||||
throw std::exception(("Could not open \""+filename+"\"").c_str());
|
||||
|
||||
header("Content-Length", (size_t)fs.tellg());
|
||||
fs.seekg(0, std::ifstream::beg);
|
||||
|
||||
*this << fs.rdbuf();
|
||||
|
||||
flush();
|
||||
}
|
||||
#undef buf
|
||||
|
||||
|
||||
static void default_404(Request& req, Response& res)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "<html>"
|
||||
<< "<head>"
|
||||
<< "<title>Not Found</title>"
|
||||
<< "</head>"
|
||||
<< "<body>"
|
||||
<< "<h1>Not Found</h1>"
|
||||
<< "<p>"
|
||||
<< '"' << req.url() << '"'
|
||||
<< " could not be found."
|
||||
<< "</p>"
|
||||
<< "</body>"
|
||||
<< "</html>";
|
||||
|
||||
res.status(404);
|
||||
res.header("Content-Type", "text/html");
|
||||
res.send(ss.str());
|
||||
}
|
||||
|
||||
|
||||
static void default_500(Request& req, Response& res, std::string msg)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "<html>"
|
||||
<< "<head>"
|
||||
<< "<title>Error</title>"
|
||||
<< "</head>"
|
||||
<< "<body>"
|
||||
<< "<h1>Error</h1>"
|
||||
<< "<p>"
|
||||
<< msg
|
||||
<< "</p>"
|
||||
<< "</body>"
|
||||
<< "</html>";
|
||||
|
||||
res.status(500);
|
||||
res.header("Content-Type", "text/html");
|
||||
res.send(ss.str());
|
||||
}
|
||||
|
||||
|
||||
Router::Router()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Router::handle(std::istream& req_s, std::ostream& res_s)
|
||||
{
|
||||
Request req(req_s);
|
||||
Response res(res_s);
|
||||
|
||||
auto f = _handlers.find(req.url());
|
||||
|
||||
if (f == _handlers.end())
|
||||
{
|
||||
default_404(req, res);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<Handler>& handlers = f->second;
|
||||
auto h = handlers.begin();
|
||||
|
||||
jmp_buf next;
|
||||
setjmp(next);
|
||||
|
||||
if (h == handlers.end())
|
||||
{
|
||||
default_404(req, res);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
(*h)(req, res, [&]() { h += 1; longjmp(next, 0); });
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
default_500(req, res, std::string(ex.what()));
|
||||
}
|
||||
catch (std::string& str)
|
||||
{
|
||||
default_500(req, res, str);
|
||||
}
|
||||
catch (const char* str)
|
||||
{
|
||||
default_500(req, res, std::string(str));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
default_500(req, res, "Unhandeled exception has accrued");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Router::on(std::string url, Handler handler)
|
||||
{
|
||||
// if vector already existed it is returned.
|
||||
// If not, a new one is created and returned.
|
||||
auto pair = _handlers.emplace(std::piecewise_construct, std::make_tuple(url), std::make_tuple());
|
||||
|
||||
// First is the key-value pair iterator,
|
||||
// second is true if new vector was created.
|
||||
auto& iter = pair.first;
|
||||
|
||||
iter
|
||||
// First is the key, second is the vector.
|
||||
->second
|
||||
.push_back(handler);
|
||||
}
|
||||
|
||||
void Router::on_get(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "GET") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::on_head(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "HEAD") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::on_options(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "OPTIONS") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::on_trace(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "TRACE") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::on_put(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "PUT") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::on_delete(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "DELETE") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::on_post(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "POST") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::on_patch(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "PATCH") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::on_connect(std::string url, Handler handler)
|
||||
{
|
||||
on(url, [=](Request& req, Response& res, Next next) { if (req.method() == "CONNECT") handler(req, res, next); else next(); });
|
||||
}
|
||||
|
||||
void Router::listen(std::string address, short port)
|
||||
{
|
||||
Socket server;
|
||||
server.bind(address.c_str(), port);
|
||||
server.listen();
|
||||
|
||||
while (true)
|
||||
{
|
||||
Socket client = server.accept();
|
||||
SocketStream stream(client);
|
||||
handle(stream, stream);
|
||||
}
|
||||
}
|
||||
|
||||
void Router::listen(short port)
|
||||
{
|
||||
Socket server;
|
||||
server.bind(port);
|
||||
server.listen();
|
||||
|
||||
while (true) try
|
||||
{
|
||||
Socket client = server.accept();
|
||||
SocketStream stream(client);
|
||||
handle(stream, stream);
|
||||
}
|
||||
catch (ClientError& err)
|
||||
{
|
||||
// Nothing major, ignore
|
||||
std::cout << "Client Error: " << err.what() << std::endl;
|
||||
}
|
||||
}
|
||||
75
Router.h
Normal file
75
Router.h
Normal file
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
class Request : public std::istream
|
||||
{
|
||||
public:
|
||||
Request(std::istream& stream);
|
||||
virtual ~Request();
|
||||
|
||||
Request(const Request&) = delete;
|
||||
Request(Request&&) = delete;
|
||||
|
||||
std::string url() const;
|
||||
std::string method() const;
|
||||
const std::string* header(std::string name) const;
|
||||
};
|
||||
|
||||
|
||||
class Response : public std::ostream
|
||||
{
|
||||
public:
|
||||
Response(std::ostream& stream);
|
||||
virtual ~Response();
|
||||
|
||||
Response(const Response&) = delete;
|
||||
Response(Response&&) = delete;
|
||||
|
||||
void status(int status);
|
||||
|
||||
template<typename T, std::enable_if_t<std::is_arithmetic<T>::value, bool> = true>
|
||||
void header(std::string name, T value) { header(name, std::to_string(value)); }
|
||||
void header(std::string name, std::string value);
|
||||
|
||||
void send(std::string text);
|
||||
void send(const void* data, size_t size);
|
||||
void sendFile(std::string filename);
|
||||
};
|
||||
|
||||
|
||||
using Next = std::function<void()>;
|
||||
class Router
|
||||
{
|
||||
public:
|
||||
using Handler = std::function<void(Request&, Response&, Next)>;
|
||||
|
||||
Router();
|
||||
|
||||
void handle(std::iostream& req) { handle(req, req); };
|
||||
void handle(std::istream& req, std::ostream& res);
|
||||
|
||||
void on(std::string url, Handler handler);
|
||||
|
||||
void on_get(std::string url, Handler handler);
|
||||
void on_head(std::string url, Handler handler);
|
||||
void on_options(std::string url, Handler handler);
|
||||
void on_trace(std::string url, Handler handler);
|
||||
void on_put(std::string url, Handler handler);
|
||||
void on_delete(std::string url, Handler handler);
|
||||
void on_post(std::string url, Handler handler);
|
||||
void on_patch(std::string url, Handler handler);
|
||||
void on_connect(std::string url, Handler handler);
|
||||
|
||||
void listen(std::string address, short port);
|
||||
void listen(short port);
|
||||
|
||||
private:
|
||||
std::map<std::string, std::vector<Handler>> _handlers;
|
||||
};
|
||||
133
Socket.cpp
Normal file
133
Socket.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "Socket.h"
|
||||
|
||||
#include "WinSock2.h"
|
||||
#include "WS2tcpip.h"
|
||||
#include "Windows.h"
|
||||
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
static bool wsa_initialized = false;
|
||||
|
||||
|
||||
Socket::Socket()
|
||||
{
|
||||
// Move out to a separate function
|
||||
if (!wsa_initialized)
|
||||
{
|
||||
WSAData data;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &data))
|
||||
throw std::exception("Failed to initialize WSA");
|
||||
wsa_initialized = true;
|
||||
}
|
||||
|
||||
_sock = socket(
|
||||
AF_INET,
|
||||
SOCK_STREAM,
|
||||
0 // IPPROTO_TCP
|
||||
);
|
||||
|
||||
if (_sock == INVALID_SOCKET)
|
||||
throw std::exception("Failed to create socket");
|
||||
}
|
||||
|
||||
Socket::~Socket()
|
||||
{
|
||||
if (!_rc.last())
|
||||
return;
|
||||
// Flush comunication before closing
|
||||
shutdown(_sock, SD_SEND);
|
||||
char buffer[512];
|
||||
while (read(buffer, sizeof(buffer))) {}
|
||||
shutdown(_sock, SD_RECEIVE);
|
||||
|
||||
closesocket(_sock);
|
||||
}
|
||||
|
||||
void Socket::bind(const char *address, unsigned short port)
|
||||
{
|
||||
sockaddr_in addr = { 0 };
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
if (address)
|
||||
inet_pton(AF_INET, address, &addr.sin_addr);
|
||||
else
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if (::bind(_sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
|
||||
throw std::exception("Failed to bind socket");
|
||||
}
|
||||
|
||||
void Socket::listen(int backlog)
|
||||
{
|
||||
if (::listen(_sock, backlog) == SOCKET_ERROR)
|
||||
throw std::exception("Failed to listen on socket");
|
||||
}
|
||||
|
||||
Socket Socket::accept()
|
||||
{
|
||||
SOCKET sock = ::accept(_sock, nullptr, nullptr);
|
||||
if (sock == INVALID_SOCKET)
|
||||
throw std::exception("Failed to accept socket");
|
||||
Socket socket(sock);
|
||||
return std::move(socket);
|
||||
}
|
||||
|
||||
int Socket::read(void* buffer, int size)
|
||||
{
|
||||
int ret = ::recv(_sock, (char*)buffer, size, 0);
|
||||
return max(0, ret); // Clamp to 0, as socket is always synchronious
|
||||
}
|
||||
|
||||
int Socket::write(const char *string)
|
||||
{
|
||||
return write(string, (int)strlen(string));
|
||||
}
|
||||
|
||||
int Socket::write(const void *data, int size)
|
||||
{
|
||||
return ::send(_sock, (const char *)data, size, 0);
|
||||
}
|
||||
|
||||
void Socket::end()
|
||||
{
|
||||
::shutdown(_sock, SD_SEND);
|
||||
}
|
||||
|
||||
|
||||
SocketStreamBuf::~SocketStreamBuf()
|
||||
{
|
||||
sync();
|
||||
}
|
||||
|
||||
int SocketStreamBuf::underflow()
|
||||
{
|
||||
// System should be buffering received data
|
||||
if (!_sock.read(&_c, 1))
|
||||
return EOF;
|
||||
setg(&_c, &_c, &_c+1);
|
||||
return _c;
|
||||
}
|
||||
|
||||
int SocketStreamBuf::overflow(int c)
|
||||
{
|
||||
if (_buf_size >= _buf_size_max)
|
||||
sync();
|
||||
|
||||
// This check is not required, but it muffles a warning in VisualStudio
|
||||
if (_buf_size < _buf_size_max)
|
||||
_buf[_buf_size++] = c;
|
||||
else
|
||||
assert(0);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int SocketStreamBuf::sync()
|
||||
{
|
||||
_sock.write(_buf, _buf_size);
|
||||
_buf_size = 0;
|
||||
return 0;
|
||||
}
|
||||
86
Socket.h
Normal file
86
Socket.h
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include "RC.h"
|
||||
|
||||
#include <streambuf>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
|
||||
class SocketStreamBuf;
|
||||
class ISocketStream;
|
||||
class OSocketStream;
|
||||
class SocketStream;
|
||||
|
||||
|
||||
class Socket
|
||||
{
|
||||
public:
|
||||
Socket();
|
||||
Socket(size_t socket) : _sock(socket) {};
|
||||
virtual ~Socket();
|
||||
|
||||
void bind(unsigned short port) { bind(nullptr, port); }
|
||||
void bind(const char* address, unsigned short port);
|
||||
void listen(int backlog = 1024);
|
||||
Socket accept();
|
||||
|
||||
int read(void* buffer, int size);
|
||||
|
||||
int write(const char* string);
|
||||
int write(const void* data, int size);
|
||||
void end();
|
||||
|
||||
size_t handle() const { return _sock; }
|
||||
|
||||
private:
|
||||
size_t _sock;
|
||||
RC _rc;
|
||||
};
|
||||
|
||||
|
||||
class SocketStreamBuf : public std::streambuf
|
||||
{
|
||||
public:
|
||||
SocketStreamBuf(Socket sock) : _sock(sock), _buf() {}
|
||||
virtual ~SocketStreamBuf();
|
||||
|
||||
virtual int underflow();
|
||||
virtual int overflow(int c);
|
||||
virtual int sync();
|
||||
|
||||
private:
|
||||
Socket _sock;
|
||||
|
||||
// Read buffer
|
||||
char _c = 0;
|
||||
|
||||
// Send buffer
|
||||
enum { _buf_size_max = 1024 };
|
||||
char _buf[_buf_size_max] = { 0 };
|
||||
int _buf_size = 0;
|
||||
};
|
||||
|
||||
|
||||
class ISocketStream : public std::istream
|
||||
{
|
||||
public:
|
||||
ISocketStream(Socket& sock) : std::istream(new SocketStreamBuf(sock)) {}
|
||||
virtual ~ISocketStream() { delete rdbuf(); }
|
||||
};
|
||||
|
||||
|
||||
class OSocketStream : public std::ostream
|
||||
{
|
||||
public:
|
||||
OSocketStream(Socket& sock) : std::ostream(new SocketStreamBuf(sock)) {}
|
||||
virtual ~OSocketStream() { delete rdbuf(); }
|
||||
};
|
||||
|
||||
|
||||
class SocketStream : public std::iostream
|
||||
{
|
||||
public:
|
||||
SocketStream(Socket& sock) : std::iostream(new SocketStreamBuf(sock)) {}
|
||||
virtual ~SocketStream() { delete rdbuf(); }
|
||||
};
|
||||
100
StringUtil.cpp
Normal file
100
StringUtil.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include "StringUtil.h"
|
||||
|
||||
|
||||
std::vector<std::string> StringUtil::split(std::string str, std::string sep)
|
||||
{
|
||||
std::vector<std::string> vec;
|
||||
|
||||
while (str.size() != 0)
|
||||
{
|
||||
size_t index = str.find(sep);
|
||||
if (index)
|
||||
vec.push_back(str.substr(0, index));
|
||||
else
|
||||
vec.push_back("");
|
||||
str = str.substr(index + sep.size());
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
std::vector<std::string> StringUtil::split(std::string str, char sep)
|
||||
{
|
||||
std::vector<std::string> vec;
|
||||
|
||||
int i, j;
|
||||
for (i = 0, j = 1; j < str.size(); j++)
|
||||
{
|
||||
if (str[j] == sep)
|
||||
{
|
||||
if (i == j)
|
||||
vec.push_back("");
|
||||
else
|
||||
vec.push_back(str.substr(i, j - i));
|
||||
i = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (j + 1 != i)
|
||||
vec.push_back(str.substr(i, j - 1));
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
std::vector<std::string> StringUtil::splitClean(std::string str, std::string sep)
|
||||
{
|
||||
std::vector<std::string> vec;
|
||||
|
||||
while (str.size() != 0)
|
||||
{
|
||||
size_t index = str.find(sep);
|
||||
if (index)
|
||||
vec.push_back(str.substr(0, index));
|
||||
str = str.substr(index + sep.size());
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
std::vector<std::string> StringUtil::splitClean(std::string str, char sep)
|
||||
{
|
||||
std::vector<std::string> vec;
|
||||
|
||||
int i, j;
|
||||
for (i = 0, j = 1; j < str.size(); j++)
|
||||
{
|
||||
if (str[j] == sep && i != j)
|
||||
{
|
||||
vec.push_back(str.substr(i, j - i));
|
||||
i = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (j + 1 != i)
|
||||
vec.push_back(str.substr(i, j - 1));
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
std::string StringUtil::strip(std::string str, char sep)
|
||||
{
|
||||
return stripLeft(stripRight(str, sep), sep);
|
||||
}
|
||||
|
||||
std::string StringUtil::stripLeft(std::string str, char sep)
|
||||
{
|
||||
int n;
|
||||
for (n = 0; n < str.size(); n++)
|
||||
if (str[n] != sep)
|
||||
break;
|
||||
return str.substr(n);
|
||||
}
|
||||
|
||||
std::string StringUtil::stripRight(std::string str, char sep)
|
||||
{
|
||||
int n;
|
||||
for (n = (int)str.size()-1; n > -1; n--)
|
||||
if (str[n] != sep)
|
||||
break;
|
||||
return str.substr(0, n+1);
|
||||
}
|
||||
18
StringUtil.h
Normal file
18
StringUtil.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace StringUtil
|
||||
{
|
||||
std::vector<std::string> split(std::string str, std::string sep);
|
||||
std::vector<std::string> split(std::string str, char sep);
|
||||
|
||||
std::vector<std::string> splitClean(std::string str, std::string sep);
|
||||
std::vector<std::string> splitClean(std::string str, char sep);
|
||||
|
||||
std::string strip(std::string str, char c = ' ');
|
||||
std::string stripLeft(std::string str, char c = ' ');
|
||||
std::string stripRight(std::string str, char c = ' ');
|
||||
}
|
||||
42
Terminal.h
Normal file
42
Terminal.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#define __TERM_INT2STR(n) #n
|
||||
|
||||
#define FG(r, g, b) ("\x1B[38;2;" __TERM_INT2STR(r) ";" __TERM_INT2STR(g) ";" __TERM_INT2STR(b) "m")
|
||||
#define BG(r, g, b) ("\x1B[48;2;" __TERM_INT2STR(r) ";" __TERM_INT2STR(g) ";" __TERM_INT2STR(b) "m")
|
||||
|
||||
#define RESET "\x1B[0m"
|
||||
|
||||
#define BLACK "\x1B[30m"
|
||||
#define RED "\x1B[31m"
|
||||
#define GREEN "\x1B[32m"
|
||||
#define YELLOW "\x1B[33m"
|
||||
#define BLUE "\x1B[34m"
|
||||
#define MAGENTA "\x1B[35m"
|
||||
#define CYAN "\x1B[36m"
|
||||
#define WHITE "\x1B[37m"
|
||||
#define BRIGHT_BLACK "\x1B[90m"
|
||||
#define BRIGHT_RED "\x1B[91m"
|
||||
#define BRIGHT_GREEN "\x1B[92m"
|
||||
#define BRIGHT_YELLOW "\x1B[93m"
|
||||
#define BRIGHT_BLUE "\x1B[94m"
|
||||
#define BRIGHT_MAGENTA "\x1B[95m"
|
||||
#define BRIGHT_CYAN "\x1B[96m"
|
||||
#define BRIGHT_WHITE "\x1B[97m"
|
||||
|
||||
#define BBLACK "\x1B[40m"
|
||||
#define BRED "\x1B[41m"
|
||||
#define BGREEN "\x1B[42m"
|
||||
#define BYELLOW "\x1B[43m"
|
||||
#define BBLUE "\x1B[44m"
|
||||
#define BMAGENTA "\x1B[45m"
|
||||
#define BCYAN "\x1B[46m"
|
||||
#define BWHITE "\x1B[47m"
|
||||
#define BBRIGHT_BLACK "\x1B[100m"
|
||||
#define BBRIGHT_RED "\x1B[101m"
|
||||
#define BBRIGHT_GREEN "\x1B[102m"
|
||||
#define BBRIGHT_YELLOW "\x1B[103m"
|
||||
#define BBRIGHT_BLUE "\x1B[104m"
|
||||
#define BBRIGHT_MAGENTA "\x1B[105m"
|
||||
#define BBRIGHT_CYAN "\x1B[106m"
|
||||
#define BBRIGHT_WHITE "\x1B[107m"
|
||||
19
_resource.h
Normal file
19
_resource.h
Normal file
@ -0,0 +1,19 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by hate.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define INDEX 1
|
||||
|
||||
#define HTML_FILE 256
|
||||
31
hate.sln
Normal file
31
hate.sln
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.14.36511.14 d17.14
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hate", "hate.vcxproj", "{0181C661-83F0-48E2-BBAF-D802CCFB2104}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0181C661-83F0-48E2-BBAF-D802CCFB2104}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0181C661-83F0-48E2-BBAF-D802CCFB2104}.Debug|x64.Build.0 = Debug|x64
|
||||
{0181C661-83F0-48E2-BBAF-D802CCFB2104}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{0181C661-83F0-48E2-BBAF-D802CCFB2104}.Debug|x86.Build.0 = Debug|Win32
|
||||
{0181C661-83F0-48E2-BBAF-D802CCFB2104}.Release|x64.ActiveCfg = Release|x64
|
||||
{0181C661-83F0-48E2-BBAF-D802CCFB2104}.Release|x64.Build.0 = Release|x64
|
||||
{0181C661-83F0-48E2-BBAF-D802CCFB2104}.Release|x86.ActiveCfg = Release|Win32
|
||||
{0181C661-83F0-48E2-BBAF-D802CCFB2104}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {69BFFB14-18F1-4AF0-80B7-BBF80722B98A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
151
hate.vcxproj
Normal file
151
hate.vcxproj
Normal file
@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{0181c661-83f0-48e2-bbaf-d802ccfb2104}</ProjectGuid>
|
||||
<RootNamespace>hate</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="Resource.cpp" />
|
||||
<ClCompile Include="Router.cpp" />
|
||||
<ClCompile Include="Socket.cpp" />
|
||||
<ClCompile Include="StringUtil.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Resource.h" />
|
||||
<ClInclude Include="_resource.h" />
|
||||
<ClInclude Include="Router.h" />
|
||||
<ClInclude Include="RC.h" />
|
||||
<ClInclude Include="Socket.h" />
|
||||
<ClInclude Include="StringUtil.h" />
|
||||
<ClInclude Include="Terminal.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="hate.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
62
hate.vcxproj.filters
Normal file
62
hate.vcxproj.filters
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Socket.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Router.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StringUtil.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Resource.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Socket.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RC.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Router.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Terminal.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StringUtil.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="_resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="hate.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
4
hate.vcxproj.user
Normal file
4
hate.vcxproj.user
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
10
res/index.html
Normal file
10
res/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Hate</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>H.A.T.E.</h1>
|
||||
<p>Time to <b>KILL</b> those pesky little CPU sucking processes!</p>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user