This commit is contained in:
udo
2021-10-30 01:51:46 +00:00
parent fa432a0482
commit af3f2a1f96
20 changed files with 772 additions and 296 deletions
+5 -1
View File
@@ -254,7 +254,11 @@ SharedUnit* get_shared_unit(string file_name)
void invoke(string file_name)
{
printf("(i) invoke(%s)\n", file_name.c_str());
if(file_name[0] != '/')
{
file_name = expand_path(file_name);
}
//printf("(i) invoke(%s)\n", file_name.c_str());
auto su = get_shared_unit(file_name);
if(!su)
{
+28 -5
View File
@@ -10,6 +10,18 @@ string var_dump(StringMap map, string prefix = "", string postfix = "\n")
return(result);
}
string var_dump(StringList map, string prefix = "", string postfix = "\n")
{
string result = "";
for (u32 i = 0; i < map.size(); i++)
{
result.append(prefix + map[i] + postfix);
}
return(result);
}
u8 char_to_u8(char input)
{
if(input >= '0' && input <= '9')
@@ -26,6 +38,15 @@ u8 hex_to_u8(string src)
return(char_to_u8(src[0])*16 + char_to_u8(src[1]));
}
template <typename ITYPE> string to_hex(ITYPE w, size_t hex_len = sizeof(ITYPE)<<1)
{
static const char* digits = "0123456789ABCDEF";
string rc(hex_len,'0');
for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
rc[i] = digits[(w>>j) & 0x0f];
return(rc);
}
string trim(string raw)
{
u32 len = raw.length();
@@ -47,22 +68,24 @@ StringList explode(string str, string delim = "\n")
StringList result;
int start = 0;
int end = str.find(delim);
while (end != -1)
while (end != string::npos)
{
result.push_back(str.substr(start, end - start));
result.push_back(str.substr(start, end - start));
start = end + delim.size();
end = str.find(delim, start);
}
result.push_back(str.substr(start, end - start));
return(result);
}
string implode(StringList l, string delim = "\n")
{
string result;
for(string &s : l)
for(u32 i = 0; i < l.size(); i++)
{
if(result.length() > 0)
result.append(delim+s);
string s = l[i];
if(i > 0)
result.append(delim);
result.append(s);
}
return(result);
-12
View File
@@ -1,12 +0,0 @@
struct ServerSettings {
string BIN_DIRECTORY = "work";
string COMPILE_SCRIPT = "scripts/compile";
string LIT_ESC = "3d5b5_1";
string CONTENT_TYPE = "text/html; charset=utf-8";
string SOCKET_PATH = "/run/uce.sock";
string TMP_UPLOAD = "/tmp";
string COMPILER_SYS_PATH = "";
u32 LISTEN_PORT = 9993;
};
+24 -3
View File
@@ -49,12 +49,21 @@ $ U+0024 Dollar sign Parameter expansion
string basename(string fn)
{
return(trim(shell_exec("basename "+shell_escape(fn))));
string result;
while(fn.length() > 0)
result = nibble("/", fn);
//printf("basename(%s) %s\n", fn.c_str(), result.c_str());
return(result);
}
string dirname(string fn)
{
return(trim(shell_exec("dirname "+shell_escape(fn))));
string result;
auto seg = explode(fn, "/");
seg.pop_back();
result = implode(seg, "/");
//printf("dirname(%s) %s seg#%i\n", fn.c_str(), result.c_str(), seg.size());
return(result);
}
bool file_exists(string path)
@@ -109,7 +118,7 @@ time_t file_mtime(string file_name)
struct stat info;
if (stat(file_name.c_str(), &info) != 0)
{
printf("file_mtime(%s) error\n", file_name.c_str());
return(0);
}
else
{
@@ -121,3 +130,15 @@ void unlink(string file_name)
{
remove(file_name.c_str());
}
string expand_path(string path)
{
string result;
char buf[PATH_MAX];
char *res = realpath(path.c_str(), buf);
if(res)
{
result.append(res);
}
return(result);
}
+11 -5
View File
@@ -13,8 +13,10 @@ string date(string format = "", u64 timestamp = 0)
{
string ts;
string fmt;
if(timestamp > 0) ts = string("-d '@")+to_string(timestamp)+"'";
if(format != "") fmt = string("+'"+format+"'");
if(timestamp > 0)
ts = string("-d '@")+to_string(timestamp)+"'";
if(format != "")
fmt = string("+'"+format+"'");
return(trim(shell_exec("date "+ts+" "+fmt)));
}
@@ -22,12 +24,16 @@ string gmdate(string format = "", u64 timestamp = 0)
{
string ts;
string fmt;
if(timestamp > 0) ts = string("'@")+to_string(timestamp)+"'";
if(format != "") fmt = string("+'"+format+"'");
if(timestamp > 0)
ts = string("-d '@")+to_string(timestamp)+"'";
if(format == "RFC1123")
format = "%a, %d %b %Y %T GMT";
if(format != "")
fmt = string("+'"+format+"'");
return(trim(shell_exec("date -u "+ts+" "+fmt)));
}
u64 parse_time(string time_string)
{
return(int_val(trim(shell_exec("date -u -d '"+time_string+"' +'%s'"))));
}
}
+63 -7
View File
@@ -2,7 +2,6 @@
#include <unistd.h>
#include <iostream>
#include <string>
//#include <unordered_map>
#include <map>
#include <filesystem>
#include <ctype.h>
@@ -11,6 +10,7 @@
#include <sys/stat.h>
#include <ctime>
#include <dlfcn.h>
#include <limits.h>
typedef std::string string;
@@ -36,17 +36,24 @@ typedef std::vector<string> StringList;
typedef void (*invoke_handler)(string file_name);
struct UploadedFile {
string file_name;
string tmp_name;
u32 size;
};
struct Request;
typedef void (*call_handler)();
typedef void (*request_handler)(Request* request);
struct ServerSettings {
string BIN_DIRECTORY = "work";
string COMPILE_SCRIPT = "scripts/compile";
string LIT_ESC = "3d5b5_1";
string CONTENT_TYPE = "text/html; charset=utf-8";
string SOCKET_PATH = "/run/uce.sock";
string TMP_UPLOAD = "/tmp";
string COMPILER_SYS_PATH = "";
u32 LISTEN_PORT = 9993;
};
struct SharedUnit {
string file_name;
@@ -78,3 +85,52 @@ struct SharedUnit {
#include "dtree.h"
struct UploadedFile {
string file_name;
string tmp_name;
u32 size;
};
struct ServerState {
std::map<string, SharedUnit*> units;
ServerSettings config;
} server_state;
struct Request {
ServerState* server_state;
StringMap params;
StringMap get;
StringMap post;
StringMap cookies;
std::vector<UploadedFile> uploaded_files;
StringMap header;
StringList set_cookies;
std::string in;
std::string out;
std::string err;
f64 time_init;
f64 time_start;
f64 time_end;
void print(string s)
{
out.append(s);
}
};
struct URI {
StringMap query;
StringMap parts;
};
typedef Request FastCGIRequest;
+2 -36
View File
@@ -1,44 +1,10 @@
#include "types.h"
#include "settings.h"
#include "datastructures.h"
#include "sys.h"
#include "time.h"
struct ServerState {
std::map<string, SharedUnit*> units;
ServerSettings config;
} server_state;
struct Request {
ServerState* server_state;
StringMap params;
StringMap get;
StringMap post;
std::vector<UploadedFile> uploaded_files;
StringMap header;
std::string in;
std::string out;
std::string err;
f64 time_init;
f64 time_start;
f64 time_end;
void print(string s)
{
out.append(s);
}
};
typedef Request FastCGIRequest;
Request* context;
#include "uri.h"
+254 -217
View File
@@ -1,221 +1,4 @@
struct URI {
StringMap query;
StringMap parts;
static URI parse(string uri_string)
{
URI result;
u8 state = 0;
string current = "";
char expect = 0;
result.parts["raw"] = uri_string;
string part_names[] = {
"scheme",
"host",
"port",
"path",
"query",
"fragment",
};
if(uri_string[0] == '/')
state = 3;
for (char &c: uri_string)
{
bool append_it = true;
if(expect && expect != c)
{
result.parts["error"] = string("\'") + c + string("\' expected");
result.parts["error_parsing"] = current;
result.parts["error_part"] = part_names[state];
return(result);
}
expect = 0;
switch(state)
{
case(0): // scheme
if(c == ':')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 1;
}
break;
case(1): // host name
if(c == '/')
{
if(current == "")
{
append_it = false;
break;
}
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 3;
expect = '/';
}
else if(c == ':')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 2;
}
break;
case(2): // port
if(c == '/')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 3;
expect = '/';
}
break;
case(3): // path
if(c == '/' && current == "")
{
append_it = false;
break;
}
if(c == '?')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 4;
}
break;
case(4): // query
if(c == '#')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 5;
}
break;
}
if(append_it)
current.append(1, c);
}
result.parts[part_names[state]] = current;
result.query = URI::parse_query(result.parts["query"]);
return(result);
}
static StringMap parse_query(string q)
{
StringMap result;
if(q.length() == 0)
return(result);
bool is_key = true;
string key = "";
string value = "";
for (char &c: q)
{
if(c == '=')
{
is_key = !is_key;
}
else if(c == '&')
{
result[URI::decode(key)] = URI::decode(value);
key = "";
value = "";
is_key = true;
}
else if(is_key)
{
key.append(1, c);
}
else
{
value.append(1, c);
}
}
result[URI::decode(key)] = URI::decode(value);
return(result);
}
static StringMap parse_multipart(string q, string boundary, std::vector<UploadedFile>& uploaded_files)
{
StringMap result;
auto i = boundary.length();
while(i < q.length())
{
auto end_pos = q.find(boundary, i);
if(end_pos != string::npos)
{
string field = q.substr(i, end_pos - i);
nibble(":", field);
string ftype = trim(nibble(";", field));
if(ftype == "form-data")
{
nibble("=\"", field);
string field_name = nibble("\"", field);
result[field_name] = field.substr(4, field.length()-6);
}
else if(ftype == "attachment")
{
nibble("=\"", field);
UploadedFile f;
f.tmp_name = context->server_state->config.TMP_UPLOAD + to_string(rand());
f.file_name = nibble("\"", field);
string bin = field.substr(4, field.length()-6);
f.size = bin.length();
file_put_contents(f.tmp_name, bin);
uploaded_files.push_back(f);
}
}
else
{
// we're done
end_pos = q.length();
}
i = end_pos + boundary.length();
}
return(result);
}
static string decode(string q)
{
string result;
for(u32 i = 0; i < q.length(); i++)
{
char c = q[i];
if(c == '%' && q[i+1] != '%')
{
result.append(1, hex_to_u8(q.substr(i+1, 2)));
i += 2;
}
else
{
result.append(1, c);
}
}
return(result);
}
};
string var_dump(URI uri, string prefix = "", string postfix = "\n")
{
@@ -226,3 +9,257 @@ string var_dump(URI uri, string prefix = "", string postfix = "\n")
var_dump(uri.query, prefix+" ", postfix)
);
}
string uri_decode(string q)
{
string result;
for(u32 i = 0; i < q.length(); i++)
{
char c = q[i];
if(c == '%' && q[i+1] != '%')
{
result.append(1, hex_to_u8(q.substr(i+1, 2)));
i += 2;
}
else
{
result.append(1, c);
}
}
return(result);
}
string uri_encode(string q)
{
string result;
for(u32 i = 0; i < q.length(); i++)
{
char c = q[i];
if(isalnum(c) || c == '~' || c == '.' || c == '_' || c == '-')
result.append(1, c);
else
{
result.append(1, '%');
result.append(to_hex(c));
}
}
return(result);
}
StringMap parse_query(string q)
{
StringMap result;
if(q.length() == 0)
return(result);
bool is_key = true;
string key = "";
string value = "";
for (char &c: q)
{
if(c == '=')
{
is_key = !is_key;
}
else if(c == '&')
{
result[uri_decode(key)] = uri_decode(value);
key = "";
value = "";
is_key = true;
}
else if(is_key)
{
key.append(1, c);
}
else
{
value.append(1, c);
}
}
result[uri_decode(key)] = uri_decode(value);
return(result);
}
StringMap parse_multipart(string q, string boundary, std::vector<UploadedFile>& uploaded_files)
{
StringMap result;
auto i = boundary.length();
while(i < q.length())
{
auto end_pos = q.find(boundary, i);
if(end_pos != string::npos)
{
string field = q.substr(i, end_pos - i);
nibble(":", field);
string ftype = trim(nibble(";", field));
if(ftype == "form-data")
{
nibble("=\"", field);
string field_name = nibble("\"", field);
result[field_name] = field.substr(4, field.length()-6);
}
else if(ftype == "attachment")
{
nibble("=\"", field);
UploadedFile f;
f.tmp_name = context->server_state->config.TMP_UPLOAD + to_string(rand());
f.file_name = nibble("\"", field);
string bin = field.substr(4, field.length()-6);
f.size = bin.length();
file_put_contents(f.tmp_name, bin);
uploaded_files.push_back(f);
}
}
else
{
// we're done
end_pos = q.length();
}
i = end_pos + boundary.length();
}
return(result);
}
URI parse_uri(string uri_string)
{
URI result;
u8 state = 0;
string current = "";
char expect = 0;
result.parts["raw"] = uri_string;
string part_names[] = {
"scheme",
"host",
"port",
"path",
"query",
"fragment",
};
if(uri_string[0] == '/')
state = 3;
for (char &c: uri_string)
{
bool append_it = true;
if(expect && expect != c)
{
result.parts["error"] = string("\'") + c + string("\' expected");
result.parts["error_parsing"] = current;
result.parts["error_part"] = part_names[state];
return(result);
}
expect = 0;
switch(state)
{
case(0): // scheme
if(c == ':')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 1;
}
break;
case(1): // host name
if(c == '/')
{
if(current == "")
{
append_it = false;
break;
}
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 3;
expect = '/';
}
else if(c == ':')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 2;
}
break;
case(2): // port
if(c == '/')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 3;
expect = '/';
}
break;
case(3): // path
if(c == '/' && current == "")
{
append_it = false;
break;
}
if(c == '?')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 4;
}
break;
case(4): // query
if(c == '#')
{
result.parts[part_names[state]] = current;
append_it = false;
current = "";
state = 5;
}
break;
}
if(append_it)
current.append(1, c);
}
result.parts[part_names[state]] = current;
result.query = parse_query(result.parts["query"]);
return(result);
}
void set_cookie(
string name, string value = "",
u64 expires = 0, string path = "/", string domain = "",
bool secure = false, bool http_only = true)
{
string cookie = "Set-Cookie: ";
cookie.append(uri_encode(name) + "=" + uri_encode(value));
if(expires > 0)
cookie.append(string("; Expires=") + gmdate("RFC1123", expires));
context->set_cookies.push_back(cookie);
}
StringMap parse_cookies(string cookie_string)
{
StringMap result;
while(cookie_string.length() > 0)
{
string key = trim(nibble("=", cookie_string));
string value = nibble(";", cookie_string);
result[key] = value;
}
return(result);
}
+13 -4
View File
@@ -43,7 +43,10 @@ int handle_complete(FastCGIRequest& request) {
request.time_start = microtime();
request.header["Content-Type"] = context->server_state->config.CONTENT_TYPE;
request.get = URI::parse_query(request.params["QUERY_STRING"]);
request.get = parse_query(request.params["QUERY_STRING"]);
if(request.params["HTTP_COOKIE"].length() > 0)
request.cookies = parse_cookies(request.params["HTTP_COOKIE"]);
string ct_info = request.params["CONTENT_TYPE"];
string ct_type = nibble(";", ct_info);
@@ -53,17 +56,20 @@ int handle_complete(FastCGIRequest& request) {
if(ct_type == "multipart/form-data")
{
nibble("boundary=", ct_info);
request.post = URI::parse_multipart(request.in, string("--")+ct_info, request.uploaded_files);
request.post = parse_multipart(request.in, string("--")+ct_info, request.uploaded_files);
}
else
{
request.post = URI::parse_query(request.in);
request.post = parse_query(request.in);
}
}
invoke(request.params["SCRIPT_FILENAME"]);
string headers = var_dump(request.header, "", "\r\n") + "\r\n";
string headers =
var_dump(request.header, "", "\r\n") +
var_dump(request.set_cookies, "", "\r\n") +
"\r\n";
request.out = headers + request.out;
for( auto &f : request.uploaded_files)
@@ -101,6 +107,9 @@ int main(int argc, char** argv)
server.listen(server_state.config.SOCKET_PATH);
chmod(server_state.config.SOCKET_PATH.c_str(), S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
dirname(server_state.config.COMPILER_SYS_PATH);
basename(server_state.config.COMPILER_SYS_PATH);
//server.process(100);
//server.process();
server.process_forever();