POST
This commit is contained in:
parent
3f531aa48e
commit
e630d10ad1
Binary file not shown.
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
);
|
||||
|
||||
0
test/.fuse_hidden0000015700000003
Normal file
0
test/.fuse_hidden0000015700000003
Normal file
0
test/.fuse_hidden0000015c00000005
Normal file
0
test/.fuse_hidden0000015c00000005
Normal file
0
test/.fuse_hidden0000018600000004
Normal file
0
test/.fuse_hidden0000018600000004
Normal file
0
test/.fuse_hidden000001f600000006
Normal file
0
test/.fuse_hidden000001f600000006
Normal 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
20
test/index.uce
Normal 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
47
test/post-multipart.uce
Normal 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
43
test/post.uce
Normal 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
71
test/style.css
Normal 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);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user