Compare commits

..

No commits in common. "d871f113b3a650c41135e6ec976f27d7954de98b" and "c25719167aa9a4a6f2dd8c5c9fbb766cf63c66ff" have entirely different histories.

27 changed files with 2 additions and 1598 deletions

13
.gitignore vendored
View File

@ -1,13 +0,0 @@
# Never use CMAKE in production
CMakeLists.txt
cmake-build-debug/
# Output of build system
built/
# This is a compilated build system script
building/main
building/*.png
building/*.svg
.idea/
compile_commands.json
local.sh

View File

@ -1,6 +1,6 @@
# ИУ9-21Б Вэб-чат C.A # Collarbone Anihilation
Сделан на летней практике 5-ю первокурсниками ИУ9 Веб-чат
# Список участников # Список участников

View File

@ -1,9 +0,0 @@
.aaa {font-size: 50px}
.ccc .aaa {
color: yellow;
}
.ccc #bbb {
color: green;
}

View File

@ -1,60 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>This is a test</title>
<link rel="stylesheet" href="/assets/css/test.css" >
</head>
<body>
<h1> Test Test Test</h1>
<p class="aaa"> Test Test asdasdsa Test</p>
<div class="ccc">
<p class="aaa"> Inside aaaa </p>
<p id="bbb"> Iside bbbb </p>
</div>
<form method="POST" action="/output" enctype="multipart/form-data">
<label for="inp1"> Bla-bla-bla </label>
<input type="text" name="Cool input 1+" id="inp1" class="text-input" value="Ouuups">
<label for="inp2"> Goot got </label>
<input type="text" name="Cool input 2 " id="inp2" class="text-input" value="Did it for you">
<hr>
<label for="r-1-1">Boba</label>
<input type="radio" id="r-1-1" name="r-1" value="First">
<label for="r-1-2">Biba</label>
<input type="radio" id="r-1-2" name="r-1" value="Second">
<label for="r-2-1">Buba</label>
<input type="radio" id="r-2-1" name="r-2" value="Third">
<label for="r-2-2">Duba</label>
<input type="radio" id="r-2-2" name="r-2" value="Fourth">
<hr>
<label for="chb1"> Check this </label>
<input type="checkbox" name="Cool input 3" id="chb1" value="AAAVVVV1VVV">
<label for="chb2"> More checkbozsdfsdsess </label>
<input type="checkbox" name="Cool input 4" id="chb2" value="___@@@222">
<label for="chb3"> Lmao i cbnat type stuff ia hva ee an insu=sslt </label>
<input type="checkbox" name="Cool input 5" id="chb3" value="_down_TO">
<hr>
<p> Lmao, get ready to handle file input:</p>
<input type="file" name="BEBRA" id="tututu">
<hr>
<input type="submit" value="SubmitButton">
</form>
<p> Ok, ima try that again</p>
<form method="post" action="/output" enctype="multipart/form-data">
<div>
<label for="file">Choose a file</label>
<input type="file" id="file" name="myFile" />
</div>
<div>
<button>Send the file</button>
</div>
</form>
</body>
</html>

View File

@ -1,10 +0,0 @@
#!/usr/bin/env sh
BUILDING_DIR="./building"
[ -d "$BUILDING_DIR" ] || exit 1
MAIN_FILE="$BUILDING_DIR/main.cpp"
[ -f "$MAIN_FILE" ] || exit 1
COOL_FLAGS="$(pkg-config --cflags regexis024-build-system)"
g++ $COOL_FLAGS -o "$BUILDING_DIR/main" "$MAIN_FILE" || exit 1

View File

@ -1,145 +0,0 @@
#include <utility>
#include "regexis024_build_system.h"
std::vector<std::string> getFromPkgConfig(const std::string& req, const std::string& name){
std::string pc_stdout, pc_stderr;
CommandReturnCode rc = executeCommand_and_save_output({"pkg-config", "--" + req, name}, pc_stdout, pc_stderr);
ASSERT(rc.isOk(), "failed to use pkg-config beacause of:\n" + pc_stderr);
// todo: learn how pkg-config actually stores these options
std::vector<std::string> result;
for (char ch: pc_stdout) {
if (result.empty())
result.emplace_back();
if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
if (!result.back().empty())
result.emplace_back();
} else {
result.back() += ch;
}
}
if (!result.empty() && result.back().empty())
result.pop_back();
return result;
}
ExternalLibraryTarget formExternalLibraryTargetWithNativeName(const std::string& name) {
return {name, {getFromPkgConfig("cflags", name), getFromPkgConfig("libs", name)}};
}
struct CAWebChat {
/* Building runlevel */
BuildUnitsArray runlevel_1;
/* Installation runlevel */
BuildUnitsArray runlevel_2;
std::string build_type;
std::vector<std::string> warning_flags = {"-Wall", "-Wno-unused-variable", "-Werror=return-type","-pedantic",
"-Wno-unused-but-set-variable", "-Wno-reorder"};
std::vector<std::string> version_flags = {"--std", "c++14", "-D", "_POSIX_C_SOURCE=200809L"};
std::vector<std::string> debug_defines_release = {"_GLIBCXX_DEBUG"};
std::vector<std::string> debug_defines_debug = {"_GLIBCXX_DEBUG", "DEBUG_ALLOW_LOUD"};
std::vector<std::string> opt_flags_release = {"-g", "-O2"};
std::vector<std::string> opt_flags_debug = {"-g", "-ggdb", "-O0"};
std::vector<std::string> getSomeRadFlags() const {
std::vector<std::string> my_flag_collection;
gxx_add_cli_options(my_flag_collection, warning_flags);
gxx_add_cli_options(my_flag_collection, version_flags);
if (build_type == "release") {
gxx_add_cli_defines(my_flag_collection, debug_defines_release);
gxx_add_cli_options(my_flag_collection, opt_flags_release);
} else if (build_type == "debug") {
gxx_add_cli_defines(my_flag_collection, debug_defines_debug);
gxx_add_cli_options(my_flag_collection, opt_flags_debug);
}
return my_flag_collection;
}
CAWebChat(std::string _build_type, const NormalCBuildSystemCommandMeaning& cmd)
: build_type(std::move(_build_type))
{
ASSERT(build_type == "release" || build_type == "debug", "Unknown build type");
std::vector<ExternalLibraryTarget> ext_targets = {
formExternalLibraryTargetWithNativeName("libjsonincpp"),
formExternalLibraryTargetWithNativeName("sqlite3"),
formExternalLibraryTargetWithNativeName("libregexis024"),
};
std::vector<CTarget> my_targets;
{ CTarget T{"engine_engine_number_9", "shared_library"};
T.additional_compilation_flags = getSomeRadFlags();
T.proj_deps = {};
T.external_deps = {
CTargetDependenceOnExternalLibrary{"libjsonincpp", {true, true}},
CTargetDependenceOnExternalLibrary{"libregexis024", {true, true}}
};
T.units = {
"baza.cpp",
"thread_synchronization.cpp",
"os_utils.cpp",
"http_structures/client_request_parse.cpp",
"http_structures/response_gen.cpp",
"connecting_assets/static_asset_manager.cpp",
"running_mainloop.cpp",
"form_data_structure/urlencoded_query.cpp",
};
for (std::string& u: T.units)
u = "http_server/engine_engine_number_9/" + u;
T.include_pr = "http_server";
T.include_ir = "";
T.exported_headers = {
"baza.h",
"baza_throw.h",
"thread_synchronization.h",
"os_utils.h",
"connecting_assets/static_asset_manager.h",
"http_structures/client_request.h",
"http_structures/response_gen.h",
"running_mainloop.h",
"form_data_structure/urlencoded_query.h",
};
for (std::string& u: T.exported_headers)
u = "engine_engine_number_9/" + u;
T.installation_dir = "";
my_targets.push_back(T);
}
{ CTarget T{"iu9-ca-web-chat", "executable"};
T.additional_compilation_flags = getSomeRadFlags();
T.proj_deps = {CTargetDependenceOnProjectsLibrary{"engine_engine_number_9"}};
T.external_deps = {CTargetDependenceOnExternalLibrary{"sqlite3"}};
T.units = {"main.cpp"};
for (std::string& u: T.units)
u = "web_chat/" + u;
T.include_pr = "web_chat";
T.installation_dir = "";
my_targets.push_back(T);
}
regular_ctargets_to_2bus_conversion(ext_targets, my_targets, runlevel_1, runlevel_2,
cmd.project_root, cmd.installation_root);
}
};
int main(int argc, char** argv) {
try {
ASSERT_pl(argc > 0);
std::vector<std::string> args(argc - 1);
for (int i = 0; i + 1 < argc; i++) {
args[i] = argv[i + 1];
}
NormalCBuildSystemCommandMeaning cmd;
regular_bs_cli_cmd_interpret(args, cmd);
CAWebChat bs("debug", cmd);
if (cmd.need_to_build)
complete_tasks_of_build_units(bs.runlevel_1);
umask(~0755);
if (cmd.need_to_install)
complete_tasks_of_build_units(bs.runlevel_2);
} catch (const buildSystemFailure& e) {
printf("Build system failure\n""%s\n", e.toString().c_str());
}
}

View File

@ -1,3 +0,0 @@
{
"name": "Web chat"
}

View File

@ -1,47 +0,0 @@
#include "baza.h"
#include "baza_inter.h"
#include <errno.h>
#include <string.h>
namespace een9 {
ServerError::ServerError(const std::string &err, const std::string &file, const std::string &func, int line): err(err),
FILE(file),
func(func),
LINE(line) {
char buf[4096];
snprintf(buf, 4096, "Error occured in function %s (line %d of %s)\n"
"Error: %s",
func.c_str(), LINE, FILE.c_str(), err.c_str());
WHAT = buf;
}
const char * ServerError::what() const noexcept {
return WHAT.c_str();
}
std::string prettyprint_errno(const std::string &pref) {
const char* d = strerrorname_np(errno);
return pref.empty() ? std::string(d) : std::string(pref) + ": " + d;
}
/* This function is VITAL */
bool strIn(const std::string &str, const char *arr[]) {
for (const char** elPtr = arr; *elPtr != NULL; elPtr += 1) {
if (str == (*elPtr))
return true;
}
return false;
}
bool endsIn(const std::string &a, const std::string &b) {
if (b.size() > a.size())
return false;
return std::equal(a.end() - (ssize_t)b.size(), a.end(), b.begin());
}
std::string getSubstring(const std::string &str, size_t A, size_t B) {
ASSERT(A <= B && B <= str.size(), "Incorrect substring segment");
return str.substr(A, B - A);
}
}

View File

@ -1,34 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_BAZA_H
#define ENGINE_ENGINE_NUMBER_9_BAZA_H
#include <string>
#include <memory>
namespace een9 {
class ServerError : public std::exception{
std::string err;
std::string FILE;
std::string func;
int LINE;
std::string WHAT;
public:
ServerError(const std::string &err, const std::string &file, const std::string &func, int line);
const char *what() const noexcept override;
};
std::string prettyprint_errno(const std::string& pref);
bool strIn(const std::string& str, const char* arr[]);
bool endsIn(const std::string& a, const std::string& b);
/* In case of error, throws een9::ServerError */
std::string getSubstring(const std::string& str, size_t A, size_t B);
template<typename T>
using uptr = std::unique_ptr<T>;
}
#endif

View File

@ -1,16 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_BAZA_INTER_H
#define ENGINE_ENGINE_NUMBER_9_BAZA_INTER_H
/* Do not export this file */
#include "baza.h"
#define THROW(err) throw ServerError(err, __FILE__, __func__, __LINE__)
#define THROW_on_errno(err) THROW(prettyprint_errno(err))
#define THROW_on_errno_pl() THROW(prettyprint_errno(""))
#define ASSERT(cond, err) do { if (!(cond)) { THROW(err); } } while (0);
#define ASSERT_pl(cond) ASSERT(cond, "Failed assertion `" #cond "`")
#define ASSERT_on_iret(iret, err) ASSERT((iret) >= 0, prettyprint_errno(err));
#define ASSERT_on_iret_pl(iret) ASSERT(iret >= 0, prettyprint_errno(""));
#endif

View File

@ -1,15 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_BAZA_THROW_H
#define ENGINE_ENGINE_NUMBER_9_BAZA_THROW_H
#include "baza.h"
#define een9_THROW(err) throw een9::ServerError(err, __FILE__, __func__, __LINE__)
#define een9_THROW_on_errno(err) een9_THROW(een9::prettyprint_errno(err))
#define een9_THROW_on_errno_pl() een9_THROW(een9::prettyprint_errno(""))
#define een9_ASSERT(cond, err) do { if (!(cond)) { een9_THROW(err); } } while (0);
#define een9_ASSERT_pl(cond) een9_ASSERT(cond, "Failed assertion `" #cond "`")
#define een9_ASSERT_on_iret(iret, err) een9_ASSERT((iret) >= 0, een9::prettyprint_errno(err));
#define een9_ASSERT_on_iret_pl(iret) een9_ASSERT(iret >= 0, een9::prettyprint_errno(""));
#endif

View File

@ -1,86 +0,0 @@
#include "static_asset_manager.h"
#include "../os_utils.h"
#include "../baza_inter.h"
#include <memory>
#include <utility>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
namespace een9 {
std::vector<std::string> detour_over_regular_folder(const std::string& path) {
std::vector<std::string> result;
int ret;
std::vector<std::string> todo;
todo.emplace_back();
while (!todo.empty()) {
std::string cur = std::move(todo.back());
todo.pop_back();
std::string path_to_cur_ent = path + "/" + cur;
struct stat info;
ret = stat(path_to_cur_ent.c_str(), &info);
ASSERT_on_iret(ret, "stat(\"" + cur + "\")");
if (S_ISDIR(info.st_mode)) {
DIR* D = opendir(path_to_cur_ent.c_str());
cur += "/";
ASSERT(D != NULL, prettyprint_errno("opendir(\"" + cur +"\")"));
struct Guard1{ DIR*& D; ~Guard1(){ closedir(D); } } g1{D};
while (true) {
errno = 0;
struct dirent* Dent = readdir(D);
if (Dent == NULL) {
if (errno == 0)
break;
THROW_on_errno("dirent in \"" + cur + "\"");
}
std::string child_entry = Dent->d_name;
if (child_entry != "." && child_entry != "..")
todo.push_back(cur + child_entry);
}
} else if (S_ISREG(info.st_mode)) {
result.push_back(cur);
} else {
THROW("unknown fs entry type \"" + cur + "\"");
}
}
return result;
}
void updateStaticAssetManager(StaticAssetManager& sam) {
sam.url_to_asset.clear();
for (const StaticAssetManagerRule& dir_rule: sam.rules) {
std::vector<std::string> c_files = detour_over_regular_folder(dir_rule.directory);
for (const std::string& file: c_files) {
for (const StaticAssetManagerRulePostfixFilter& ext: dir_rule.postfix_rules_type_assign) {
if (endsIn(file, ext.required_postfix)) {
/* Found it! */
StaticAsset etot{ext.assigned_type, };
readFile(dir_rule.directory + "/" + file, etot.content);
sam.url_to_asset[dir_rule.url_prefix + file] = etot;
break;
}
}
}
}
}
int StaticAssetManagerSlaveModule::get_asset(const std::string& url, StaticAsset& ret) {
RwlockReadGuard lg(mut);
if (sam.url_to_asset.count(url) == 0)
return -1;
ret = sam.url_to_asset[url];
return 0;
}
void StaticAssetManagerSlaveModule::update() {
RwlockWriteGuard lg(mut);
updateStaticAssetManager(sam);
}
void StaticAssetManagerSlaveModule::update(std::vector<StaticAssetManagerRule> new_rules) {
RwlockWriteGuard lg(mut);
sam.rules = std::move(new_rules);
updateStaticAssetManager(sam);
}
}

View File

@ -1,50 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_CONNECTING_ASSETS_STATIC_ASSET_MANAGER_H
#define ENGINE_ENGINE_NUMBER_9_CONNECTING_ASSETS_STATIC_ASSET_MANAGER_H
#include <vector>
#include <string>
#include <map>
#include "../thread_synchronization.h"
namespace een9 {
struct StaticAssetManagerRulePostfixFilter {
std::string required_postfix;
std::string assigned_type;
};
struct StaticAssetManagerRule {
std::string directory;
std::string url_prefix; // Better end with /
/* These are rules that filter name ending. First is a required name postfix, Second is a type of document
* that gets assigned to matching files
*/
std::vector<StaticAssetManagerRulePostfixFilter> postfix_rules_type_assign;
};
struct StaticAsset {
std::string type;
std::string content;
};
struct StaticAssetManager {
std::vector<StaticAssetManagerRule> rules;
std::map<std::string, StaticAsset> url_to_asset;
};
void updateStaticAssetManager(StaticAssetManager& sam);
struct StaticAssetManagerSlaveModule {
RwlockObj mut;
StaticAssetManager sam;
/* Returns newgative on failure. Still can throw execptions derived from std::execption */
int get_asset(const std::string& url, StaticAsset& ret);
void update();
void update(std::vector<StaticAssetManagerRule> new_rules);
};
}
#endif

View File

@ -1,41 +0,0 @@
#include "urlencoded_query.h"
#include <stdint.h>
namespace een9 {
std::vector<std::pair<std::string, std::string>> split_html_query(const std::string &query) {
std::vector<std::pair<std::string, std::string>> result;
if (query.empty())
return result;
result = {{"", ""}};
bool filling_second = false;
auto fref = [&]() -> std::string& { return filling_second ? result.back().second : result.back().first; };
for (size_t i = 0; i < query.size();) {
if (query[i] == '&') {
result.emplace_back("", "");
filling_second = false;
} else if (query[i] == '=') {
filling_second = true;
} else if (query[i] == '+') {
fref() += ' ';
} else if (query[i] == '%') {
if (i + 3 > query.size())
return {};
auto readhex = [&](char ch) -> uint8_t {
if ('0' <= ch && ch <= '9')
return ch - '0';
if ('a' <= ch && ch <= 'h')
return ch - 'a' + 10;
if ('A' <= ch && ch <= 'H')
return ch - 'A' + 10;
return 10;
};
fref() += (char)((readhex(query[i + 1]) << 4) | readhex(query[i + 2]));
i += 2;
} else {
fref() += query[i];
}
i++;
}
return result;
}
}

View File

@ -1,12 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_FORM_DATA_STRUCTURE_URLENCODED_QUERY_H
#define ENGINE_ENGINE_NUMBER_9_FORM_DATA_STRUCTURE_URLENCODED_QUERY_H
#include <string>
#include <vector>
namespace een9{
/* application/x-www-form-urlencoded */
std::vector<std::pair<std::string, std::string>> split_html_query(const std::string& query);
}
#endif

View File

@ -1,22 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_HTTP_STRUCTURES_CLIENT_REQUEST_H
#define ENGINE_ENGINE_NUMBER_9_HTTP_STRUCTURES_CLIENT_REQUEST_H
#include <vector>
#include <string>
#include <utility>
namespace een9 {
/* host:port scheme:authority and asterisk types of URI in http request are not supported by een9 */
struct ClientRequest {
std::string method;
std::string uri_path;
bool has_query = false;
std::string uri_query;
std::string http_version;
std::vector<std::pair<std::string, std::string>> headers;
bool has_body = false;
std::string body;
};
}
#endif

View File

@ -1,116 +0,0 @@
#include "client_request_parse.h"
#include "../baza_inter.h"
#include <libregexis024tools/delayed_matching.h>
#include <algorithm>
#include <assert.h>
namespace een9 {
ClientRequestParser_CommonPrograms::ClientRequestParser_CommonPrograms() {
regexis024::track_var_list vars;
std::string emsg;
#define reg_ALPHA "[a-zA-Z]"
#define reg_pchar "([a-zA-Z0-9\\-._~\\!$\\&'()*+@:,;=]|%[0-9a-hA-H]!r{2})"
#define reg_query "(" reg_pchar"|[?/])*"
#define reg_lin_ws "([ \t]|\r\n[ \t])*"
#define reg_request_line "#method(" reg_ALPHA"+) #uri_path(/(" reg_pchar"|/)*)(\\?#uri_query(" reg_query"))? HTTP/#http_version(!digit;+.!digit;+)\r\n"
#define reg_filed_value "(" reg_lin_ws"#header_field_value_part([\\u0021-\\u007e&^\r\n]+))*" reg_lin_ws
#define reg_HTTP_message reg_request_line "(#header_field_name([\\u0021-\\u007E&^:]+):" reg_filed_value "\r\n)*\r\n"
int ret = compile(reg_HTTP_message, vars, http_request_parse_prg, emsg);
ASSERT(ret >= 0, "regexis024::compile. " + emsg);
#define retrieve_variable(name) ASSERT_pl(vars.count(#name) > 0); ASSERT_pl(vars[#name].colarr_first >= 0); \
ASSERT_pl(vars[#name].colarr_second >= 0); name ## _beg = vars[#name].colarr_first; name ## _end = vars[#name].colarr_second;
retrieve_variable(method);
retrieve_variable(uri_path);
retrieve_variable(uri_query);
retrieve_variable(http_version);
retrieve_variable(header_field_name);
retrieve_variable(header_field_value_part);
}
ClientRequestParser_WorkerBuffers::ClientRequestParser_WorkerBuffers(
const ClientRequestParser_CommonPrograms &common_comp_program
): http_request_parse_vm(
common_comp_program.http_request_parse_prg.size(), common_comp_program.http_request_parse_prg.data(),
UINT64_MAX, UINT16_MAX, UINT32_MAX, UINT32_MAX, UINT64_MAX)
{
ASSERT_pl(http_request_parse_vm.initialize() == 0);
}
ClientHttpRequestParser_Ctx::ClientHttpRequestParser_Ctx(
ClientRequest &res, ClientRequestParser_WorkerBuffers &wb, ClientRequestParser_CommonPrograms& cp
): res(res), vm(wb.http_request_parse_vm), cp(cp)
{
vm.wipeToInit();
ASSERT_pl(vm.addNewMatchingThread() == 0);
}
int ClientHttpRequestParser_Ctx::feedCharacter(char ch) {
assert(status == 0);
if (collecting_body) {
res.body += ch;
if (res.body.size() >= body_size) {
status = 1;
}
} else {
header += ch;
if (vm.feedCharacter(ch, 1) < 0) {
THROW("vm error");
}
if (vm.isMatched()) {
/* Finishing line */
std::vector<regexis024::CAEvent> ca = vm.getMatchedThreadCABranchReverse();
std::reverse(ca.begin(), ca.end());
size_t cur_ca_i = 0;
auto getCaV = [&](ssize_t offset) -> uint64_t { return ca[cur_ca_i + offset].value; };
auto getCaK = [&](ssize_t offset) -> regexis024::tai_t { return ca[cur_ca_i + offset].key; };
auto isThat = [&](ssize_t offset, regexis024::tai_t key) -> bool {
return ca.size() > cur_ca_i + offset && getCaK(offset) == key;
};
#define vibe_check(boff, name) isThat(boff, cp.name ## _beg) && isThat(boff + 1, cp.name ## _end)
ASSERT_pl(vibe_check(0, method) && vibe_check(2, uri_path));
res.method = getSubstring(header, getCaV(0), getCaV(1));
res.uri_path = getSubstring(header, getCaV(2), getCaV(3));
cur_ca_i += 4;
if (isThat(0, cp.uri_query_beg)) {
ASSERT_pl(vibe_check(0, uri_query));
res.has_query = true;
res.uri_query = getSubstring(header, getCaV(0), getCaV(1));
cur_ca_i += 2;
}
ASSERT_pl(vibe_check(0, http_version));
res.http_version = getSubstring(header, getCaV(0), getCaV(1));
cur_ca_i += 2;
while (isThat(0, cp.header_field_name_beg)) {
ASSERT_pl(vibe_check(0, header_field_name));
std::string field_name = getSubstring(header, getCaV(0), getCaV(1));
cur_ca_i += 2;
std::string field_value;
while (isThat(0, cp.header_field_value_part_beg)) {
ASSERT_pl(vibe_check(0, header_field_value_part));
if (!field_value.empty())
field_value += " ";
field_value += getSubstring(header, getCaV(0), getCaV(1));
cur_ca_i += 2;
}
res.headers.emplace_back(field_name, field_value);
}
/* Finished header processing */
for (auto& p: res.headers) {
if (p.first == "Content-Length") {
collecting_body = res.has_body = true;
body_size = std::stoull(p.second);
res.body.reserve(body_size);
}
}
if (!res.has_body) {
status = 1;
}
/* We either finish now or we finish later */
} else if (!vm.haveSurvivors()) {
status = -1;
THROW("bad request");
}
}
return status;
}
}

View File

@ -1,57 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_HTTP_CLIENT_REQUEST_PARSE_H
#define ENGINE_ENGINE_NUMBER_9_HTTP_CLIENT_REQUEST_PARSE_H
/* Do not export this file */
#include "../baza.h"
#include "client_request.h"
#include <libregexis024vm/libregexis024vm_interface.h>
namespace een9 {
/* One structure that contains regexp program and C.A.T. keys. All accesscan and should be read only */
struct ClientRequestParser_CommonPrograms {
std::vector<uint8_t> http_request_parse_prg;
regexis024::tai_t method_beg;
regexis024::tai_t method_end;
regexis024::tai_t uri_path_beg;
regexis024::tai_t uri_path_end;
/* Splitting of query into components (with & and =) is defined in html spec, not in http spec */
regexis024::tai_t uri_query_beg;
regexis024::tai_t uri_query_end;
regexis024::tai_t http_version_beg;
regexis024::tai_t http_version_end;
regexis024::tai_t header_field_name_beg;
regexis024::tai_t header_field_name_end;
regexis024::tai_t header_field_value_part_beg;
regexis024::tai_t header_field_value_part_end;
ClientRequestParser_CommonPrograms();
};
/* Many structures (one for each worker) that stores regexp machine that reads program from one common buffer
* VM buffers should not be reallocateed between user requests. Note that after ClientRequestParser_CommonPrograms
* has been destroyed, this vm should not be used */
struct ClientRequestParser_WorkerBuffers {
regexis024::VirtualMachine http_request_parse_vm;
explicit ClientRequestParser_WorkerBuffers(const ClientRequestParser_CommonPrograms& common_comp_program);
};
/* Ou yeah, baby, it's time for more OOP */
struct ClientHttpRequestParser_Ctx {
ClientRequest& res;
regexis024::VirtualMachine& vm;
ClientRequestParser_CommonPrograms& cp;
/* 1 if reading has completed, 0 if reading can be continued, -1 if error occured (input is incorrect) */
int status = 0;
bool collecting_body = false;
size_t body_size = 0;
std::string header;
ClientHttpRequestParser_Ctx(ClientRequest& res, ClientRequestParser_WorkerBuffers& wb, ClientRequestParser_CommonPrograms& cp);
int feedCharacter(char ch);
};
}
#endif

View File

@ -1,41 +0,0 @@
#include "response_gen.h"
#include "../baza_inter.h"
#include <assert.h>
#include <string.h>
namespace een9 {
std::string form_http_server_response_header(const char* code, const std::map<std::string, std::string>& headers) {
assert(strlen(code) == 3);
std::string result = std::string("HTTP/1.0 ") + code + " " + (code[0] < '4' ? "OK" : "ERROR") + "\r\n";
for (auto& p: headers)
result += (p.first + ": " + p.second + "\r\n");
return result;
}
std::string form_http_server_reponse_header_only(const char* code, const std::map<std::string, std::string>& headers) {
return form_http_server_response_header(code, headers) + "\r\n";
}
std::string form_http_server_response_with_body(const char* code,
const std::map<std::string, std::string>& headers,
const std::string& body)
{
std::string result = form_http_server_response_header(code, headers)
+ "Content-Length: " + std::to_string(body.size()) + "\r\n\r\n" + body;
return result;
}
/* Message from server to client */
std::string form_http_server_response_200(const std::string& Content_Type, const std::string& body) {
return form_http_server_response_with_body("200", {
{"Content-Type", Content_Type}
}, body);
}
std::string form_http_server_response_404(const std::string& Content_Type, const std::string& body) {
return form_http_server_response_with_body("404", {
{"Content-Type", Content_Type}
}, body);
}
}

View File

@ -1,21 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_HTTP_STRUCTURES_RESPONSE_GEN_H
#define ENGINE_ENGINE_NUMBER_9_HTTP_STRUCTURES_RESPONSE_GEN_H
#include <map>
#include <string>
namespace een9 {
std::string form_http_server_response_header(const char* code, const std::map<std::string, std::string>& headers);
std::string form_http_server_reponse_header_only(const char* code, const std::map<std::string, std::string>& headers);
std::string form_http_server_response_with_body(const char* code,
const std::map<std::string, std::string>& headers,
const std::string& body);
std::string form_http_server_response_200(const std::string& Content_Type, const std::string& body);
std::string form_http_server_response_404(const std::string& Content_Type, const std::string& body);
}
#endif

View File

@ -1,77 +0,0 @@
#include "os_utils.h"
#include <utility>
#include "baza_inter.h"
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
namespace een9 {
UniqueFdWrapper::UniqueFdWrapper(int fd_): fd(fd_) {}
UniqueFdWrapper::UniqueFdWrapper(UniqueFdWrapper &&formerOwner) noexcept {
fd = formerOwner.fd;
formerOwner.fd = -1;
}
UniqueFdWrapper& UniqueFdWrapper::operator=(UniqueFdWrapper &&formerOwner) noexcept {
std::swap(fd, formerOwner.fd);
return *this;
}
int UniqueFdWrapper::operator()() const {
return fd;
}
UniqueFdWrapper::~UniqueFdWrapper() {
// printf("DEBUG!!! Closing fd = %d\n", fd);
if (fd >= 0)
close(fd);
}
bool isNeededFsEntity(const std::string &path, mode_t t_mode) {
struct stat info;
errno = 0;
int ret = stat(path.c_str(), &info);
if (errno == 0) {
return (info.st_mode & S_IFMT) == t_mode;
} if (errno == ENOENT)
return false;
THROW_on_errno("stat\"" + path + "\"");
}
bool isRegularFile(const std::string &path) {
return isNeededFsEntity(path, S_IFREG);
}
bool isDirectory(const std::string &path) {
return isNeededFsEntity(path, S_IFDIR);
}
void readFromFileDescriptor(int fd, std::string &result, const std::string &description) {
int ret;
char buf[2048];
while ((ret = (int)read(fd, buf, 2048)) > 0) {
size_t oldN = result.size();
result.resize(oldN + ret);
memcpy(&result[oldN], buf, ret);
}
ASSERT_on_iret(ret, "Reading from " + description);
}
void readFile(const std::string &path, std::string &result) {
int fd = open(path.c_str(), O_RDONLY);
ASSERT_on_iret(fd, "Opening \"" + path + "\"");
UniqueFdWrapper fdw(fd);
readFromFileDescriptor(fdw(), result, "file \"" + path + "\"");
}
void configure_socket_rcvsndtimeo(int fd, timeval tv) {
int ret;
ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(timeval));
ASSERT_on_iret_pl(ret);
ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(timeval));
ASSERT_on_iret_pl(ret);
}
}

View File

@ -1,36 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_OS_UTILS_H
#define ENGINE_ENGINE_NUMBER_9_OS_UTILS_H
#include "baza.h"
namespace een9 {
class UniqueFdWrapper {
int fd = -1;
public:
explicit UniqueFdWrapper() = default;
explicit UniqueFdWrapper(int fd_);
UniqueFdWrapper(const UniqueFdWrapper&) = delete;
UniqueFdWrapper& operator=(const UniqueFdWrapper&) = delete;
UniqueFdWrapper(UniqueFdWrapper&& formerOwner) noexcept;
UniqueFdWrapper& operator=(UniqueFdWrapper&& formerOwner) noexcept;
int operator()() const;
~UniqueFdWrapper();
};
bool isRegularFile(const std::string& path);
bool isDirectory(const std::string& path);
/* result += read(fd); Argument description is for error handling */
void readFromFileDescriptor(int fd, std::string& result, const std::string& description = "");
void readFile(const std::string& path, std::string& result);
void configure_socket_rcvsndtimeo(int fd, timeval tv);
}
#endif

View File

@ -1,259 +0,0 @@
#include "running_mainloop.h"
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <poll.h>
#include <assert.h>
#include <map>
#include <queue>
#include <utility>
#include "thread_synchronization.h"
#include "os_utils.h"
#include "http_structures/client_request_parse.h"
#include "http_structures/response_gen.h"
#include "baza_inter.h"
namespace een9 {
struct QElementHttpConnections {
SlaveTask task;
QElementHttpConnections* nxt = NULL;
explicit QElementHttpConnections(SlaveTask task): task(std::move(task)) {}
};
struct WorkersTaskQueue {
QElementHttpConnections* first = NULL;
QElementHttpConnections** afterLastPtr;
size_t sz = 0;
WorkersTaskQueue() {
afterLastPtr = &first;
}
bool empty() const {
return sz == 0;
}
size_t size() const {
return sz;
}
void push_back(SlaveTask task) {
/* Throws a goddamn execption. Because why not. Ofcourse everything has to throw an exception */
/* CLion says. Allocated memory is leaking. YOUR MOTHER IS LEAKING YOU FOOL!! MY CODE IS FINE!! */
QElementHttpConnections* el = new QElementHttpConnections(std::move(task));
/* Exception does not leave queue in incorrect state */
*afterLastPtr = el;
afterLastPtr = &(el->nxt);
sz++;
}
void pop_first(SlaveTask& ret_task) {
assert(!empty());
ret_task = std::move(first->task);
if (sz == 1) {
delete first;
first = NULL;
afterLastPtr = &first;
sz = 0;
} else {
/* Before I popped the first, this element was second, but now it took place of the first */
QElementHttpConnections* old_deut = first->nxt;
delete first;
first = old_deut;
sz--;
}
}
};
struct WorkersEnvCommon {
/* This alarm notifies about new tasks and termination signal. Because we are polite people, we don't cancel threads */
CondVarBedObj corvee_bed;
WorkersTaskQueue queue;
bool& termination;
guest_core_t guest_core;
/* Parser programs */
ClientRequestParser_CommonPrograms parser_programs;
WorkersEnvCommon(bool& term, guest_core_t g_c): termination(term), guest_core(std::move(g_c)){}
};
struct WorkersEnv {
WorkersEnvCommon& wtec;
int id;
ClientRequestParser_WorkerBuffers personal_parser_buffer;
explicit WorkersEnv(WorkersEnvCommon& wtec, int id): wtec(wtec), id(id), personal_parser_buffer(wtec.parser_programs){}
};
// todo: add timeout for multiple bytes, add more settings
ClientRequest process_connection_input(int fd, const EEN9_ServerTips& s_tips, WorkersEnv& wte) {
ClientRequest res;
ClientHttpRequestParser_Ctx parser(res, wte.personal_parser_buffer, wte.wtec.parser_programs);
int ret;
char buf[2048];
ASSERT_pl(parser.status == 0);
while ((ret = (int)recv(fd, buf, 2048, 0)) > 0) {
for (size_t i = 0; i < ret; i++) {
/* Throws ServerError on bad input */
if (parser.feedCharacter(buf[i]) > 0) {
break;
}
}
if (parser.status > 0)
break;
}
ASSERT_on_iret(ret, "recv");
ASSERT_pl(parser.status == 1);
// printf("Log: worker received clients request\n%s\n", client_request.toString().c_str());
return res;
}
void process_connection_output(int fd, const std::string& server_response) {
size_t N = server_response.size(), i = 0;
while (i < N) {
/* MSG_NOSIGNAL set to prevent SIGPIPE */
int written = (int)send(fd, &server_response[i], std::min(2048lu, N - i), MSG_NOSIGNAL);
ASSERT_on_iret(written, "sending");
ASSERT_pl(written > 0);
i += written;
}
printf("Log: worker: succesfully asnwered with response\n");
}
void process_connection(const SlaveTask& task, WorkersEnv& wte) {
ClientRequest client_request = process_connection_input(task.fd(), task.s_tips, wte);
std::string server_response = wte.wtec.guest_core(task, client_request);
process_connection_output(task.fd(), server_response);
}
void* worker_func(void* wte_ptr) {
WorkersEnv& wte = *((WorkersEnv*)wte_ptr);
WorkersEnvCommon& wtec = wte.wtec;
printf("Worker started\n");
while (true) {
try {
MutexLockGuard cb_lg(wtec.corvee_bed, __func__);
woke:
if (wtec.termination)
break;
if (wtec.queue.empty()) {
wtec.corvee_bed.sleep(__func__);
goto woke;
}
SlaveTask task;
wtec.queue.pop_first(task);
process_connection(task, wte);
} catch (const std::exception& e) {
printf("Client request procession failure in worker\n");
printf("%s\n", e.what());
}
}
printf("Worker finished\n");
return NULL;
}
// todo: retrieve address of connected client
void electric_boogaloo(const MainloopParameters& params, bool& termination_trigger) {
WorkersEnvCommon wtec(termination_trigger, params.guest_core);
ASSERT(params.slave_number > 0, "No workers spawned");
size_t Nip = params.ports_to_listen.size();
ASSERT(Nip > 0, "No open listeting addresses");
std::vector<pthread_t> workers(params.slave_number);
std::vector<uptr<WorkersEnv>> wtes(params.slave_number);
for (size_t i = 0; i < params.slave_number; i++) {
wtes[i] = std::make_unique<WorkersEnv>(wtec, i);
}
for (size_t i = 0; i < params.slave_number; i++) {
pthread_create(&workers[i], NULL, worker_func, wtes[i].get());
}
try {
int ret;
std::vector<UniqueFdWrapper> listening_socks(Nip);
for (size_t i = 0; i < Nip; i++) {
printf("Creating listening socket\n");
uint16_t port = params.ports_to_listen[i];
int listening_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
ASSERT_on_iret(listening_socket_fd, "Listening socket creation");
UniqueFdWrapper listening_socket(listening_socket_fd);
printf("Listening socket created\n");
sockaddr_in listening_address;
listening_address.sin_family = AF_INET;
listening_address.sin_port = htons(port);
uint32_t lca = (127u << 24) | 1;
listening_address.sin_addr.s_addr = htonl(lca);
int reuseaddr_nozero_option_value = 1;
ret = setsockopt(listening_socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_nozero_option_value, sizeof(int));
ASSERT_on_iret(ret, "setting SO_REUSEADDR befire binding to address");
ret = bind(listening_socket(), (const sockaddr*)&listening_address, sizeof(listening_address));
ASSERT_on_iret(ret, "binding to INADDR_ANY:" + std::to_string(port));
printf("Binded socket to address\n");
ret = listen(listening_socket(), 128);
ASSERT_on_iret(ret, "listening for connections");
printf("Listening socket succesfully started listening\n");
listening_socks[i] = std::move(listening_socket);
}
std::vector<pollfd> pollfds(Nip);
for (size_t i = 0; i < Nip; i++) {
pollfds[i].fd = listening_socks[i]();
pollfds[i].events = POLLRDNORM;
}
printf("Entering mainloop\n");
ASSERT(params.mainloop_recheck_interval_us > 0, "Incorrect poll timeout");
while (true) {
MutexLockGuard lg1(wtec.corvee_bed, "poller termination check");
if (wtec.termination)
break;
lg1.unlock();
for (size_t i = 0; i < Nip; i++) {
pollfds[i].revents = 0;
}
errno = 0;
ret = poll(pollfds.data(), Nip, params.mainloop_recheck_interval_us);
if (errno == EINTR)
break;
ASSERT_on_iret(ret, "polling");
for (size_t i = 0; i < Nip; i++) {
if ((pollfds[i].revents & POLLRDNORM)) {
try {
sockaddr client_address;
socklen_t client_addr_len = sizeof(client_address);
int session_sock = accept(pollfds[i].fd, &client_address, &client_addr_len);
ASSERT_on_iret(session_sock, "Failed to accept incoming connection");
printf("Log: successful connection\n");
UniqueFdWrapper session_sock_fdw(session_sock);
configure_socket_rcvsndtimeo(session_sock_fdw(), params.s_conf.request_timeout);
{ MutexLockGuard lg2(wtec.corvee_bed, "poller adds connection");
SlaveTask task{ConnectionInfo{}, std::move(session_sock_fdw),
EEN9_ServerTips{wtec.queue.size(),
params.s_conf.critical_load_1, params.s_conf.request_timeout}};
if (wtec.queue.size() < params.s_conf.critical_load_2)
wtec.queue.push_back(std::move(task));
}
wtec.corvee_bed.din_don();
} catch (const std::exception& e) {
printf("Error aceepting connection\n");
printf("%s\n", e.what());
}
}
}
}
} catch (const std::exception& e) {
printf("System failure 2\n");
printf("%s\n", e.what());
/* There is no need to tiptoe around this multi-access field. It is write-onle-and-for-good-kind */
wtec.termination = true;
wtec.corvee_bed.wake_them_all();
}
wtec.termination = true;
wtec.corvee_bed.wake_them_all();
for (size_t i = 0; i < params.slave_number; i++) {
pthread_join(workers[i], NULL);
}
}
}

View File

@ -1,58 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_MAINLOOP_H
#define ENGINE_ENGINE_NUMBER_9_MAINLOOP_H
#include "baza.h"
#include <functional>
#include <sys/time.h>
#include "os_utils.h"
#include "http_structures/client_request.h"
#include <stdint.h>
namespace een9 {
struct ConnectionInfo {
// todo: add server address field
// todo: add client address field
int type; // O_o why??
};
/* This structure is passed to guest function. It contains server info that might be or might be not used
* by guest */
struct EEN9_ServerTips {
size_t server_load;
size_t critical_load_1;
timeval recommended_timeout;
};
struct SlaveTask {
ConnectionInfo conn_info;
UniqueFdWrapper fd;
EEN9_ServerTips s_tips;
};
/* guest_core function must not throw anything that is not derived from std::exception */
typedef std::function<std::string(const SlaveTask&, const ClientRequest&)> guest_core_t;
struct ServersConfiguration {
size_t critical_load_1 = 90;
size_t critical_load_2 = 100;
timeval request_timeout{20, 0};
};
struct MainloopParameters {
bool do_logging = true;
bool open_admin_listener = true;
// todo: add support for unix socket address
uint16_t admin_listener_port = 12345;
guest_core_t guest_core;
size_t slave_number = 2;
std::vector<uint16_t> ports_to_listen;
int mainloop_recheck_interval_us = 100;
ServersConfiguration s_conf;
};
void electric_boogaloo(const MainloopParameters& params, bool& termination_trigger);
}
#endif

View File

@ -1,161 +0,0 @@
#include "thread_synchronization.h"
#include "baza_inter.h"
#include <assert.h>
namespace een9 {
/*==================================================== RwlockObj ============ */
void RwlockObj::unlock(int el, const char *who) {
assert(lock == el);
lock = 0;
if (me)
printf("Rwl %s unlocked by %s\n", me, who);
int ret = pthread_rwlock_unlock(&mut);
assert(ret == 0);
}
RwlockObj::RwlockObj(const char *me): me(me) {
int ret = pthread_rwlock_init(&mut, NULL);
ASSERT_on_iret(ret, "pthread rwlock init");
}
void RwlockObj::read_lock(const char *who) {
int ret = pthread_rwlock_rdlock(&mut);
assert(ret == 0);
if (me)
printf("Rwl %s read-locked by %s\n", me, who);
lock = 1;
}
void RwlockObj::write_lock(const char *who) {
int ret = pthread_rwlock_wrlock(&mut);
assert(ret == 0);
if (me)
printf("Rwl %s write-locked by %s\n", me, who);
lock = 2;
}
void RwlockObj::read_unclock(const char *who) {
unlock(1, who);
}
void RwlockObj::write_unclock(const char *who) {
unlock(2, who);
}
RwlockObj::~RwlockObj() {
pthread_rwlock_destroy(&mut);
}
/*==================================================== MutexObj ============ */
MutextObj::MutextObj(const char *me): me(me) {
int ret = pthread_mutex_init(&mut, NULL);
ASSERT_on_iret(ret == 0, "pthread mutex init");
}
void MutextObj::lock(const char *who) {
int ret = pthread_mutex_lock(&mut);
assert(ret == 0);
if (me)
printf("Mut %s locked by %s\n", me, who);
locked = 1;
}
void MutextObj::unlock(const char *who) {
assert(locked == 1);
locked = 0;
if (me)
printf("Mut %s unlocked by %s\n", me, who);
int ret = pthread_mutex_unlock(&mut);
assert(ret == 0);
}
MutextObj::~MutextObj() {
pthread_mutex_destroy(&mut);
}
/*==================================================== CondVarBedObj ============ */
CondVarBedObj::CondVarBedObj(const char *me): MutextObj(me) {
int ret = pthread_cond_init(&alarm, NULL);
ASSERT_on_iret(ret, "pthread cond variable init");
}
void CondVarBedObj::sleep(const char *who) {
assert(locked == 1);
locked = 0;
if (me)
printf("Mut %s unlocked. Sleeping (%s)\n", me, who);
int ret = pthread_cond_wait(&alarm, &mut);
assert(ret == 0);
if (me)
printf("Mut %s locked. Woke up (%s)\n", me, who);
locked = 1;
}
void CondVarBedObj::din_don() {
int ret = pthread_cond_signal(&alarm);
assert(ret == 0);
}
void CondVarBedObj::wake_them_all() {
int ret = pthread_cond_broadcast(&alarm);
assert(ret == 0);
}
CondVarBedObj::~CondVarBedObj() {
pthread_mutex_destroy(&mut);
pthread_cond_destroy(&alarm);
}
/*==================================================== MutexLockGuard ============ */
MutexLockGuard::MutexLockGuard(MutextObj &mut, const char *who): mut(mut), who(who) {
mut.lock(who);
}
void MutexLockGuard::unlock() {
assert(!premature_unlock);
premature_unlock = true;
mut.unlock(who);
}
MutexLockGuard::~MutexLockGuard() {
if (!premature_unlock)
mut.unlock(who);
}
/*==================================================== RwLockReadLockGuard ============ */
RwlockReadGuard::RwlockReadGuard(RwlockObj &mut, const char *who): mut(mut), who(who) {
mut.read_lock(who);
}
void RwlockReadGuard::unlock() {
assert(!premature_unlock);
premature_unlock = true;
mut.read_unclock(who);
}
RwlockReadGuard::~RwlockReadGuard() {
if (!premature_unlock)
mut.read_unclock(who);
}
/*==================================================== RwLockWriteLockGuard ============ */
RwlockWriteGuard::RwlockWriteGuard(RwlockObj &mut, const char *who): mut(mut), who(who) {
mut.write_lock(who);
}
void RwlockWriteGuard::unlock() {
assert(!premature_unlock);
premature_unlock = true;
mut.write_unclock(who);
}
RwlockWriteGuard::~RwlockWriteGuard() {
if (!premature_unlock)
mut.write_unclock(who);
}
}

View File

@ -1,109 +0,0 @@
#ifndef ENGINE_ENGINE_NUMBER_9_THREAD_SYNCHRONIZATION_H
#define ENGINE_ENGINE_NUMBER_9_THREAD_SYNCHRONIZATION_H
#include "baza.h"
#include <pthread.h>
namespace een9 {
class RwlockObj {
protected:
pthread_rwlock_t mut;
int lock = 0;
const char* me;
void unlock(int el, const char* who);
public:
RwlockObj(const RwlockObj& ) = delete;
RwlockObj& operator=(const RwlockObj& ) = delete;
explicit RwlockObj(const char* me = NULL);
void read_lock(const char* who = "");
void write_lock(const char* who = "");
void read_unclock(const char* who = "");
void write_unclock(const char* who = "");
~RwlockObj();
};
class MutextObj {
protected:
pthread_mutex_t mut;
int locked = 0;
const char* me;
public:
MutextObj(const MutextObj&) = delete;
MutextObj& operator= (const MutextObj&) = delete;
explicit MutextObj(const char* me = NULL);
void lock(const char* who = "");
void unlock(const char* who = "");
~MutextObj();
};
class CondVarBedObj : public MutextObj{
pthread_cond_t alarm;
/* In this case, variable `locked` check won't ensure proper mutex usage, but it can help sometimes */
public:
CondVarBedObj(const CondVarBedObj& ) = delete;
CondVarBedObj& operator=(const CondVarBedObj& ) = delete;
explicit CondVarBedObj(const char* me = NULL);
void sleep(const char* who = "");
void din_don();
void wake_them_all();
~CondVarBedObj();
};
class MutexLockGuard {
MutextObj& mut;
const char* who;
bool premature_unlock = false;
public:
explicit MutexLockGuard(MutextObj &mut, const char* who = "");
void unlock();
~MutexLockGuard();
};
class RwlockReadGuard {
RwlockObj& mut;
const char* who;
bool premature_unlock = false;
public:
explicit RwlockReadGuard(RwlockObj &mut, const char *who = "");
void unlock();
~RwlockReadGuard();
};
class RwlockWriteGuard {
RwlockObj& mut;
const char* who;
bool premature_unlock = false;
public:
explicit RwlockWriteGuard(RwlockObj &mut, const char *who = "");
void unlock();
~RwlockWriteGuard();
};
}
#endif

View File

@ -1,98 +0,0 @@
#include <engine_engine_number_9/baza_throw.h>
#include <engine_engine_number_9/running_mainloop.h>
#include <engine_engine_number_9/http_structures/response_gen.h>
#include <signal.h>
#include <engine_engine_number_9/connecting_assets/static_asset_manager.h>
#include <assert.h>
#include <sqlite3.h>
#include <libjsonincpp/string_representation.h>
#include <libregexis024vm/vm_opcodes.h>
#include <engine_engine_number_9/form_data_structure/urlencoded_query.h>
bool termination = false;
void sigterm_action(int) {
termination = true;
}
void usage(char** argv) {
printf("Usage: %s <file with settings> <assets folder>\n", argv[0]);
exit(1);
}
std::string unsafe_client_request_stringification(const een9::ClientRequest& req) {
std::string text = "\n\nGot some cool stuff\n";
text += (req.method + " " + req.uri_path + " " + req.http_version + "\n");
for (auto& p: req.headers) {
text += p.first; text += ": "; text += p.second; text += "\n";
}
text += "Body\n"; text += req.body; text += "\n";
return text;
}
int main(int argc, char** argv){
printf("%s\n", regexis024::opcode_to_str(regexis024::opcode_t::DIE));
try {
een9_ASSERT_pl(argc > 0);
if (argc < 1 + 2)
usage(argv);
if (!een9::isRegularFile(argv[1]) || !een9::endsIn(argv[1], ".json")) {
printf("\"%s\" is not a json file\n", argv[1]);
usage(argv);
}
std::string config_file = argv[1];
if (!een9::isDirectory(argv[2])) {
printf("\"%s\" is not a directory\n", argv[2]);
usage(argv);
}
std::string assets_dir = argv[2];
std::string config_text;
een9::readFile(config_file, config_text);
json::JSON config = json::parse_str_flawless(config_text);
een9_ASSERT(config.isDictionary(), "config root is not dictionary");
een9::StaticAssetManagerSlaveModule samI;
samI.update({
een9::StaticAssetManagerRule{assets_dir + "/html", "/assets/html", {{".html", "text/html"}} },
een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} },
een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/js"}} },
});
een9::MainloopParameters params;
params.guest_core = [&samI](const een9::SlaveTask& task, const een9::ClientRequest& req) -> std::string {
een9::StaticAsset sa;
int ret;
// printf("%s", unsafe_client_request_stringification(req).c_str());
if (req.uri_path == "/output") {
std::string text = unsafe_client_request_stringification(req);
return een9::form_http_server_response_200("text/plain", text);
}
if (req.uri_path == "/" || req.uri_path == "/index.html") {
for (auto& p: een9::split_html_query(req.uri_query)) {
printf("Query: %s = %s\n", p.first.c_str(), p.second.c_str());
}
printf("");
ret = samI.get_asset("/assets/html/test.html", sa);
een9_ASSERT_pl(ret == 0);
return een9::form_http_server_response_200(sa.type, sa.content);
}
ret = samI.get_asset(req.uri_path, sa);
if (ret >= 0) {
return een9::form_http_server_response_200(sa.type, sa.content);
}
return een9::form_http_server_response_404("text/html", "<h1> Not found! </h1>");
};
params.ports_to_listen = {1025};
params.slave_number = 8;
params.open_admin_listener = false;
signal(SIGINT, sigterm_action);
signal(SIGTERM, sigterm_action);
een9::electric_boogaloo(params, termination);
} catch (std::exception& e) {
printf("System failure\n%s\n", e.what());
}
return 0;
}