This commit is contained in:
Udo 2021-10-29 03:50:46 +00:00
parent 3f531aa48e
commit e630d10ad1
21 changed files with 335 additions and 37 deletions

Binary file not shown.

View File

@ -22,7 +22,8 @@ LIBS="-ldl -lm -lpthread "
SRCFLAGS="-D EXEC_NAME=\"$GF\" -D PLATFORM_NAME=\"linux\""
echo "Compliling executable..."
time -p $COMPILER src/linux_fastcgi.cpp $SRCFLAGS $FLAGS $LIBS -o bin/$GF.$BUILDMODE.linux.bin
#time -p
$COMPILER src/linux_fastcgi.cpp $SRCFLAGS $FLAGS $LIBS -o bin/$GF.$BUILDMODE.linux.bin 2>&1
if [ $? -eq 0 ]
then

View File

@ -97,7 +97,7 @@ protected:
bool close_socket;
};
typedef std::map<std::string, std::string> Pairs;
typedef StringMap Pairs;
std::vector<int> listen_sockets;
std::vector<std::string> listen_unlink;

View File

@ -1,6 +1,6 @@
#include <dlfcn.h>
#define RENDER() extern "C" void render()
#define RENDER() extern "C" void render()
typedef void (*call_handler)();
typedef void (*request_handler)(Request* request);
@ -30,12 +30,12 @@ string process_html_literal(string content, string file_name)
string pc;
string HT_START = "context->print(R\"(";
string HT_END = ")\");";
u8 mode = 0;
bool inside_quote = false;
string code_buffer = "";
bool is_field = false;
for(u32 i = 0; i < content.length(); i++)
{
char c = content[i];
@ -53,10 +53,10 @@ string process_html_literal(string content, string file_name)
if(is_field)
{
pc.append(
HT_END +
HT_END +
"echo(html_escape( " +
code_buffer +
" )); " +
" )); " +
HT_START
);
}
@ -67,7 +67,7 @@ string process_html_literal(string content, string file_name)
}
else
{
code_buffer.append(1, c);
code_buffer.append(1, c);
}
}
else if(!inside_quote && c == '<' && content[i+1] == '?')
@ -85,11 +85,11 @@ string process_html_literal(string content, string file_name)
}
mode = 1;
}
else if(c == '\"')
/*else if(c == '\"')
{
inside_quote = !inside_quote;
pc.append(1, c);
}
}*/
else
{
pc.append(1, c);
@ -115,7 +115,7 @@ string preprocess(string content, string file_name)
if(end_pos != string::npos)
{
u32 len = token.length() + 3 + end_pos - i;
html_buffer.append(content.substr(i, len));
html_buffer.append(content.substr(i, len - (token.length() == 0 ? 3 : 0)));
i += len - 1;
pc.append(process_html_literal(html_buffer, file_name));
}
@ -128,17 +128,24 @@ string preprocess(string content, string file_name)
else if(mode == 1)
{
if(isspace(c) || c == '>')
{
mode = 2;
if(token.length() > 0)
html_buffer.append(1, c);
}
else
{
token.append(1, c);
html_buffer.append(1, c);
html_buffer.append(1, c);
}
}
else if(!inside_quote && c == '<' && isalpha(content[i+1]))
else if(!inside_quote && c == '<' && (content[i+1] == '>' || isalpha(content[i+1])))
{
mode = 1;
token = "";
html_buffer = "";
html_buffer.append(1, c);
if(content[i+1] != '>')
html_buffer.append(1, c);
}
else if(c == '\"')
{
@ -203,7 +210,7 @@ SharedUnit* compile_shared_unit(string file_name)
printf("(i) compiled unit %s\n", file_name.c_str());
load_shared_unit(su);
load_shared_unit(su);
return(su);
}
@ -241,7 +248,7 @@ void invoke(Request* req, string file_name)
else
{
su->on_setup(req);
su->on_render();
su->on_render();
}
}
}
@ -249,4 +256,4 @@ void invoke(Request* req, string file_name)
void invoke(string file_name)
{
return(invoke(context, file_name));
}
}

View File

@ -71,7 +71,7 @@ string implode(StringList l, string delim = "\n")
string html_escape(string s)
{
string result;
for(u32 i = 0; i < s.length(); i++)
{
char c = s[i];
@ -111,4 +111,21 @@ string html_escape(f64 a)
u64 int_val(string s, u32 base = 10)
{
return(strtoll(s.c_str(), 0, base));
}
}
string nibble(string div, string& haystack)
{
auto pos = haystack.find(div);
if(pos == string::npos)
{
auto result = haystack;
haystack.clear();
return(result);
}
else
{
auto result = haystack.substr(0, pos);
haystack.erase(0, pos+div.length());
return(result);
}
}

View File

@ -5,6 +5,7 @@ struct Settings {
string LIT_ESC = "3d5b5_1";
string CONTENT_TYPE = "text/html; charset=utf-8";
string SOCKET_PATH = "/run/uce.sock";
string TMP_UPLOAD = "/tmp";
u32 LISTEN_PORT = 9993;
} Config;
} Config;

View File

@ -110,3 +110,8 @@ time_t file_mtime(string file_name)
return(info.st_mtime);
}
}
void unlink(string file_name)
{
remove(file_name.c_str());
}

View File

@ -2,6 +2,7 @@
#include <unistd.h>
#include <iostream>
#include <string>
//#include <unordered_map>
#include <map>
#include <filesystem>
#include <ctype.h>
@ -32,5 +33,11 @@ typedef long long s64;
typedef std::map<string, string> StringMap;
typedef std::vector<string> StringList;
struct UploadedFile {
string file_name;
string tmp_name;
u32 size;
};
#include "dtree.h"

View File

@ -6,14 +6,18 @@
#include "uri.h"
struct FastCGIRequest {
StringMap params;
StringMap get;
StringMap post;
std::vector<UploadedFile> uploaded_files;
StringMap header;
URI uri;
std::string in;
std::string out;
std::string err;
f64 time_init;
f64 time_start;
f64 time_end;

View File

@ -137,6 +137,7 @@ struct URI {
result[URI::decode(key)] = URI::decode(value);
key = "";
value = "";
is_key = true;
}
else if(is_key)
{
@ -153,6 +154,48 @@ struct URI {
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 = 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;

View File

@ -11,9 +11,6 @@ int handle_request(FastCGIRequest& request) {
// server receives all parameters. There may be more data coming on the
// standard input stream.
request.time_init = microtime();
request.out.reserve(128 * 1024);
request.in.reserve(128 * 1024);
request.err.reserve(128 * 1024);
if (request.params.count("REQUEST_URI"))
return 0; // OK, continue processing
else
@ -42,20 +39,39 @@ int handle_complete(FastCGIRequest& request) {
// event occurs when the parameters and standard input streams are
// both closed, and thus the request is complete.
request.time_start = microtime();
request.header["Content-Type"] = Config.CONTENT_TYPE;
request.uri = URI::parse(request.params["REQUEST_URI"]);
request.uri.parts["scheme"] = request.params["REQUEST_SCHEME"];
request.uri.parts["method"] = request.params["REQUEST_METHOD"];
request.uri.parts["host"] = request.params["HTTP_HOST"];
request.get = URI::parse_query(request.params["QUERY_STRING"]);
string ct_info = request.params["CONTENT_TYPE"];
string ct_type = nibble(";", ct_info);
if(request.params["REQUEST_METHOD"] == "POST")
{
if(ct_type == "multipart/form-data")
{
nibble("boundary=", ct_info);
request.post = URI::parse_multipart(request.in, string("--")+ct_info, request.uploaded_files);
}
else
{
request.post = URI::parse_query(request.in);
}
}
invoke(&request, request.params["SCRIPT_FILENAME"]);
string headers = var_dump(request.header, "", "\r\n") + "\r\n";
request.out = headers + request.out;
for( auto &f : request.uploaded_files)
{
unlink(f.tmp_name);
}
request.time_end = microtime();
printf("(r) %s\t%0.6fs\t%0.1fkB\n",
request.params["REQUEST_URI"].c_str(),
printf("(r) %s\t%0.6fs\t%0.1fkB\n",
request.params["REQUEST_URI"].c_str(),
request.time_end - request.time_start,
(f32)(request.out.length()/1024)
);

View File

View File

View File

View File

View File

@ -1,6 +1,6 @@
RENDER()
void show_stuff()
{
//context->header["Content-Type"] = "text/plain";
//echo(to_string(time())+"\n");
@ -8,7 +8,7 @@ RENDER()
<html>
Mwahahaaha <?= time() ?>
<div>hello world: <?= context->params["HTTP_HOST"] ?></div>
<pre style="background:rgba(0,0,0,0.1);max-height: 200px; overflow: auto;">
<pre>
Display the date using any or all of the following elements:
%a: abbreviated day name (i.e. mon, tue, wed)
@ -174,3 +174,17 @@ Lifewire is part of the Dotdash publishing family.
}
RENDER()
{
<html>
<link rel="stylesheet" href='style.css?v=1'></link>
<h1>
<a href="index.uce">UCE Test</a>:
Index
</h1>
<? show_stuff(); ?>
<pre><?= var_dump(context->params) ?></pre>
</html>
}

20
test/index.uce Normal file
View File

@ -0,0 +1,20 @@
RENDER()
{
<html>
<link rel="stylesheet" href='style.css?v=1'></link>
<h1>
<a href="index.uce">UCE Test</a>:
Index
</h1>
<ul>
<li><a href="hello.uce">Hello</a></li>
<li><a href="post.uce">Form Post</a></li>
<li><a href="post-multipart.uce">Form Multipart Post</a></li>
</ul>
<pre><?= var_dump(context->params) ?></pre>
</html>
}

47
test/post-multipart.uce Normal file
View File

@ -0,0 +1,47 @@
void show_form()
{
<form action="?" method="post" enctype="multipart/form-data">
<div>
<label>Some text:</label>
<input type="text" name="fühld" value="<?= context->post["fühld"] ?>"/>
</div>
<div>
<label>Some multiline text:</label>
<textarea name="field2"><?= context->post["field2"] ?></textarea>
</div>
<div>
<input type="submit" value="Submit Form"/>
</div>
</form>
}
RENDER()
{
<>
<link rel="stylesheet" href='style.css?v=1'></link>
<h1>
<a href="index.uce">UCE Test</a>:
Multipart-Encoded Form POST
</h1>
<? show_form(); ?>
<div>
</div>
<label>Parsed POST fields</label>
<pre><?= var_dump(context->post) ?></pre>
<label>Raw POST content</label>
<pre><?= context->in ?></pre>
<label>CGI Params</label>
<pre><?= var_dump(context->params) ?></pre>
</>
}

43
test/post.uce Normal file
View File

@ -0,0 +1,43 @@
void show_form()
{
<form action="?" method="post">
<div>
<label>Some text:</label>
<input type="text" name="field" value="<?= context->post["field"] ?>"/>
</div>
<div>
<label>Some multiline text:</label>
<textarea name="field2"><?= context->post["field2"] ?></textarea>
</div>
<div>
<input type="submit" value="Submit Form"/>
</div>
</form>
}
RENDER()
{
<html>
<link rel="stylesheet" href='style.css?v=1'></link>
<h1>
<a href="index.uce">UCE Test</a>:
Form POST
</h1>
<? show_form(); ?>
<label>Parsed POST fields</label>
<pre><?= var_dump(context->post) ?></pre>
<label>Raw POST content</label>
<pre><?= context->in ?></pre>
<label>CGI Params</label>
<pre><?= var_dump(context->params) ?></pre>
</html>
}

71
test/style.css Normal file
View File

@ -0,0 +1,71 @@
* {
font-family: inherit;
font-size: inherit;
box-sizing: inherit;
color: inherit;
line-height: inherit;
}
a {
color: yellow;
}
h1 {
font-size: 200%;
padding-top: 8px;
padding-bottom: 8px;
}
body {
max-width: 1024px;
margin-left: auto;
margin-right: auto;
font-family: Tahoma, Helvetica, Arial;
font-size: 1.2em;
box-sizing: border-box;
background: #24f;
color: white;
line-height: 150%;
}
form > div, label {
display: block;
padding-top: 8px;
padding-bottom: 8px;
}
input, textarea {
background: rgba(0,0,0,0.2);
border: 2px solid rgba(255,255,255,0.2);
}
input[type=submit], button {
padding: 8px;
cursor: pointer;
}
input[type=submit]:hover, button:hover {
color: yellow;
background: rgba(0,0,0,0.5);
}
input[type=text], textarea {
padding: 8px;
width: 100%;
}
input[type=text]:hover, textarea:hover {
background: rgba(0,0,0,0.25);
}
textarea {
height: 20%;
}
pre {
height: 20%;
overflow: auto;
padding. 8px;
border: 2px solid rgba(0,0,0,0.2);
background: rgba(100,100,100,0.15);
}

View File

@ -15,13 +15,15 @@ Library
Bugs
=================================
- shell_escape()
- Include Path
- include path
- current request working directory
- preprocessor
- nested tags
Framework
=================================
- DTree
- POST
- File Upload
- Proxy mode
- WebSockets