Initial cleanup of the folder serve nodes, also added them and HTMLBuilder to the build.

This commit is contained in:
Relintai 2022-07-02 16:40:08 +02:00
parent 56d2ccbb26
commit f81018f712
9 changed files with 160 additions and 95 deletions

View File

@ -22,8 +22,8 @@ sources = [
"http/web_server_middleware.cpp", "http/web_server_middleware.cpp",
"http/web_server_request.cpp", "http/web_server_request.cpp",
"html/html_builder_bind.cpp", "html/html_builder_bind.cpp",
"html/html_builder.cpp",
"http_server_simple/http_server_simple.cpp", "http_server_simple/http_server_simple.cpp",
"http_server_simple/web_server_simple.cpp", "http_server_simple/web_server_simple.cpp",
@ -35,6 +35,9 @@ sources = [
"nodes/static_pages/static_page.cpp", "nodes/static_pages/static_page.cpp",
"nodes/static_pages/static_page_file.cpp", "nodes/static_pages/static_page_file.cpp",
"nodes/static_pages/static_page_folder_files.cpp", "nodes/static_pages/static_page_folder_files.cpp",
"nodes/folder_serve_nodes/browsable_folder_serve_node.cpp",
"nodes/folder_serve_nodes/folder_serve_node.cpp",
] ]
if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes': if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes':

View File

@ -38,6 +38,9 @@ def get_doc_classes():
"StaticPage", "StaticPage",
"StaticPageFile", "StaticPageFile",
"StaticPageFolderFiles", "StaticPageFolderFiles",
"FolderServeNode",
"BrowsableFolderServeNode",
] ]

View File

@ -1,7 +1,4 @@
#include "html_builder.h" #include "html_builder.h"
#include "core/string.h"
#include "web/http/request.h"
HTMLTag *HTMLTag::str(const String &str) { HTMLTag *HTMLTag::str(const String &str) {
result += " " + str; result += " " + str;
@ -826,10 +823,11 @@ HTMLTag *HTMLTag::reset() {
} }
HTMLTag *HTMLTag::close() { HTMLTag *HTMLTag::close() {
if (simple) if (simple) {
result += "/>"; result += "/>";
else } else {
result += ">"; result += ">";
}
return this; return this;
} }
@ -2575,12 +2573,14 @@ HTMLBuilder *HTMLBuilder::form_post(const String &action, const String &cls, con
return this; return this;
} }
/*
HTMLBuilder *HTMLBuilder::form_post(const String &action, Request *request, const String &cls, const String &id) { HTMLBuilder *HTMLBuilder::form_post(const String &action, Request *request, const String &cls, const String &id) {
form_post(action, cls, id); form_post(action, cls, id);
csrf_token(request); csrf_token(request);
return this; return this;
} }
*/
HTMLTag *HTMLBuilder::input_button() { HTMLTag *HTMLBuilder::input_button() {
write_tag(); write_tag();
@ -3326,9 +3326,11 @@ HTMLBuilder *HTMLBuilder::csrf_token(const String &token) {
return this; return this;
} }
/*
HTMLBuilder *HTMLBuilder::csrf_token(Request *request) { HTMLBuilder *HTMLBuilder::csrf_token(Request *request) {
return csrf_token(request->get_csrf_token()); return csrf_token(request->get_csrf_token());
} }
*/
void HTMLBuilder::f() { void HTMLBuilder::f() {
write_tag(); write_tag();
@ -3359,7 +3361,8 @@ HTMLBuilder *HTMLBuilder::wns(const double val) {
HTMLBuilder *HTMLBuilder::wr(const double val, const bool p_trailing) { HTMLBuilder *HTMLBuilder::wr(const double val, const bool p_trailing) {
write_tag(); write_tag();
result += String::num_real(val, p_trailing); //TODO
//result += String::num_real(val, p_trailing);
return this; return this;
} }
@ -3393,13 +3396,10 @@ HTMLBuilder *HTMLBuilder::wbs(const bool val) {
return this; return this;
} }
// TODO!
HTMLBuilder *HTMLBuilder::we(const String &val) { HTMLBuilder *HTMLBuilder::we(const String &val) {
printf("HTMLBuilder::write_excaped NYI!");
write_tag(); write_tag();
result += val; result += val.http_escape();
return this; return this;
} }
@ -3419,4 +3419,4 @@ HTMLBuilder::HTMLBuilder() {
} }
HTMLBuilder::~HTMLBuilder() { HTMLBuilder::~HTMLBuilder() {
} }

View File

@ -1,7 +1,7 @@
#ifndef HTML_BUILDER_H #ifndef HTML_BUILDER_H
#define HTML_BUILDER_H #define HTML_BUILDER_H
#include "core/string.h" #include "core/ustring.h"
class Request; class Request;
class HTMLBuilder; class HTMLBuilder;
@ -470,7 +470,7 @@ public:
HTMLBuilder *form_get(const String &action, const String &cls = "", const String &id = ""); HTMLBuilder *form_get(const String &action, const String &cls = "", const String &id = "");
HTMLBuilder *form_post(const String &action, const String &cls = "", const String &id = ""); HTMLBuilder *form_post(const String &action, const String &cls = "", const String &id = "");
// will add a csrf token from request // will add a csrf token from request
HTMLBuilder *form_post(const String &action, Request *request, const String &cls = "", const String &id = ""); //HTMLBuilder *form_post(const String &action, Request *request, const String &cls = "", const String &id = "");
HTMLTag *input_button(); HTMLTag *input_button();
HTMLTag *input_checkbox(); HTMLTag *input_checkbox();
@ -521,7 +521,7 @@ public:
HTMLBuilder *input_hidden(const String &name, const String &value); HTMLBuilder *input_hidden(const String &name, const String &value);
HTMLBuilder *csrf_token(const String &token); HTMLBuilder *csrf_token(const String &token);
HTMLBuilder *csrf_token(Request *request); //HTMLBuilder *csrf_token(Request *request);
void f(); void f();
@ -548,4 +548,4 @@ protected:
HTMLTag tag; HTMLTag tag;
}; };
#endif #endif

View File

@ -1,21 +1,33 @@
#include "browsable_folder_serve_node.h" #include "browsable_folder_serve_node.h"
#include "core/os/directory.h" #include "core/os/dir_access.h"
#include "web/file_cache.h"
#include "web/html/html_builder.h"
#include "web/http/request.h"
void BrowsableFolderServeNode::_handle_request_main(Request *request) { #include "../../html/html_builder.h"
#include "../../file_cache.h"
#include "../../http/web_permission.h"
#include "../../http/web_server_request.h"
#include "../../http/http_server_enums.h"
bool BrowsableFolderServeNode::get_should_render_menu() {
return _should_render_menu;
}
void BrowsableFolderServeNode::set_should_render_menu(const bool &val) {
_should_render_menu = val;
}
void BrowsableFolderServeNode::_handle_request_main(Ref<WebServerRequest> request) {
String file_name = request->get_path(true, false); String file_name = request->get_path(true, false);
String *s = _folder_indexes[file_name]; String *s = _folder_indexes[file_name];
if (!s) { if (!s) {
request->send_error(HTTP_STATUS_CODE_404_NOT_FOUND); request->send_error(HTTPServerEnums::HTTP_STATUS_CODE_404_NOT_FOUND);
return; return;
} }
if (should_render_menu) { if (_should_render_menu) {
render_menu(request); render_menu(request);
} }
@ -23,7 +35,7 @@ void BrowsableFolderServeNode::_handle_request_main(Request *request) {
request->compile_and_send_body(); request->compile_and_send_body();
} }
void BrowsableFolderServeNode::render_index(Request *request) { void BrowsableFolderServeNode::render_index(Ref<WebServerRequest> request) {
String *s = _folder_indexes["/"]; String *s = _folder_indexes["/"];
if (!s) { if (!s) {
@ -32,29 +44,28 @@ void BrowsableFolderServeNode::render_index(Request *request) {
request->body += (*s); request->body += (*s);
} }
void BrowsableFolderServeNode::render_preview(Request *request) { void BrowsableFolderServeNode::render_preview(Ref<WebServerRequest> request) {
} }
void BrowsableFolderServeNode::load() { void BrowsableFolderServeNode::load() {
if (serve_folder == "") { if (_serve_folder == "") {
return; return;
} }
FolderServeNode::load(); FolderServeNode::load();
evaluate_dir(serve_folder, true); evaluate_dir(_serve_folder, true);
} }
void BrowsableFolderServeNode::evaluate_dir(const String &path, const bool top_level) { void BrowsableFolderServeNode::evaluate_dir(const String &path, const bool top_level) {
Ref<Directory> dir; DirAccess *dir = DirAccess::open(path);
dir.instance();
ERR_FAIL_COND_MSG(dir->open_dir(path) != OK, "Error opening folde!r: " + String(path)); ERR_FAIL_COND_MSG(!dir, "Error opening folde!r: " + String(path));
String dir_uri; String dir_uri;
if (!top_level) { if (!top_level) {
dir_uri = path.substr(serve_folder.size(), path.size() - serve_folder.size()); dir_uri = path.substr(_serve_folder.size(), path.size() - _serve_folder.size());
} else { } else {
dir_uri = "/"; dir_uri = "/";
} }
@ -62,23 +73,34 @@ void BrowsableFolderServeNode::evaluate_dir(const String &path, const bool top_l
Vector<String> folders; Vector<String> folders;
Vector<String> files; Vector<String> files;
while (dir->next()) { dir->list_dir_begin();
String np = dir->current_get_path();
np = np.substr(serve_folder.size(), np.size() - serve_folder.size());
if (dir->current_is_file()) { String file = dir->get_next();
files.push_back(np);
while (file != "") {
String np = path.append_path(file);
String nnp = np.substr(_serve_folder.size(), np.size() - _serve_folder.size());
if (dir->current_is_dir() && file != "." && file != "..") {
folders.push_back(nnp);
evaluate_dir(np);
} else { } else {
folders.push_back(np); files.push_back(nnp);
evaluate_dir(dir->current_get_path());
} }
file = dir->get_next();
} }
dir->close_dir(); dir->list_dir_end();
folders.sort_inc(); memdelete(dir);
files.sort_inc();
folders.sort();
files.sort();
//folders.sort_inc();
//files.sort_inc();
render_dir_page(dir_uri, folders, files, top_level); render_dir_page(dir_uri, folders, files, top_level);
} }
@ -101,7 +123,7 @@ void BrowsableFolderServeNode::render_dir_page(const String &dir_uri, const Vect
for (int i = 0; i < folders.size(); ++i) { for (int i = 0; i < folders.size(); ++i) {
b.div("file_list_entry"); b.div("file_list_entry");
{ {
b.a(uri + folders[i])->w("(Folder) ")->w(folders[i].path_get_basename())->ca(); b.a(uri + folders[i])->w("(Folder) ")->w(folders[i].get_basename())->ca();
} }
b.cdiv(); b.cdiv();
} }
@ -109,29 +131,32 @@ void BrowsableFolderServeNode::render_dir_page(const String &dir_uri, const Vect
for (int i = 0; i < files.size(); ++i) { for (int i = 0; i < files.size(); ++i) {
b.div("file_list_entry"); b.div("file_list_entry");
{ {
b.a(uri + files[i])->w("(File) ")->w(files[i].path_get_basename())->ca(); b.a(uri + files[i])->w("(File) ")->w(files[i].get_basename())->ca();
} }
b.cdiv(); b.cdiv();
} }
} }
b.cdiv(); b.cdiv();
String *s = new String(); String *s = memnew(String);
s->append_str(b.result); s->operator+=(b.result);
_folder_indexes[dir_uri] = s; _folder_indexes[dir_uri] = s;
} }
BrowsableFolderServeNode::BrowsableFolderServeNode() : BrowsableFolderServeNode::BrowsableFolderServeNode() {
FolderServeNode() { _should_render_menu = true;
should_render_menu = true;
} }
BrowsableFolderServeNode::~BrowsableFolderServeNode() { BrowsableFolderServeNode::~BrowsableFolderServeNode() {
for (std::map<String, String *>::iterator E = _folder_indexes.begin(); E != _folder_indexes.end(); E++) { const String *key = nullptr;
if (E->second) { while ((key = _folder_indexes.next(key))) {
delete E->second; String k = *key;
String *v = _folder_indexes[k];
if (v) {
memdelete(v);
} }
} }

View File

@ -1,12 +1,14 @@
#ifndef BROWSABLE_FOLDER_SERVE_NODE_H #ifndef BROWSABLE_FOLDER_SERVE_NODE_H
#define BROWSABLE_FOLDER_SERVE_NODE_H #define BROWSABLE_FOLDER_SERVE_NODE_H
#include "core/string.h" #include "core/hash_map.h"
#include <map> #include "core/ustring.h"
#include "folder_serve_node.h" #include "folder_serve_node.h"
// On top of serving the files from the folder set to it's serve_folder property, class WebServerRequest;
// On top of serving the files from the folder set to it's serve_folder property,
// this class also generates HTML directory lists. (Similar to apache's directory listing) // this class also generates HTML directory lists. (Similar to apache's directory listing)
// It caches folder contents on ENTER_TREE, it does not watch for folder changes yet. // It caches folder contents on ENTER_TREE, it does not watch for folder changes yet.
@ -19,26 +21,28 @@
// </div> // </div>
class BrowsableFolderServeNode : public FolderServeNode { class BrowsableFolderServeNode : public FolderServeNode {
RCPP_OBJECT(BrowsableFolderServeNode, FolderServeNode); GDCLASS(BrowsableFolderServeNode, FolderServeNode);
public: public:
void _handle_request_main(Request *request); bool get_should_render_menu();
void set_should_render_menu(const bool &val);
void render_index(Request *request); void _handle_request_main(Ref<WebServerRequest> request);
void render_preview(Request *request);
virtual void load(); void render_index(Ref<WebServerRequest> request);
void render_preview(Ref<WebServerRequest> request);
void load();
void evaluate_dir(const String &path, const bool top_level = false); void evaluate_dir(const String &path, const bool top_level = false);
virtual void render_dir_page(const String &dir_uri, const Vector<String> &folders, const Vector<String> &files, const bool top_level); virtual void render_dir_page(const String &dir_uri, const Vector<String> &folders, const Vector<String> &files, const bool top_level);
bool should_render_menu;
BrowsableFolderServeNode(); BrowsableFolderServeNode();
~BrowsableFolderServeNode(); ~BrowsableFolderServeNode();
protected: protected:
std::map<String, String *> _folder_indexes; bool _should_render_menu;
HashMap<String, String *> _folder_indexes;
}; };
#endif #endif

View File

@ -1,9 +1,17 @@
#include "folder_serve_node.h" #include "folder_serve_node.h"
#include "web/http/request.h" #include "../../file_cache.h"
#include "web/http/web_permission.h" #include "../../http/web_permission.h"
#include "../../http/web_server_request.h"
void FolderServeNode::handle_request_main(Request *request) { String FolderServeNode::get_serve_folder() {
return _serve_folder;
}
void FolderServeNode::set_serve_folder(const String &val) {
_serve_folder = val;
}
void FolderServeNode::_handle_request_main(Ref<WebServerRequest> request) {
if (_web_permission.is_valid()) { if (_web_permission.is_valid()) {
if (_web_permission->activate(request)) { if (_web_permission->activate(request)) {
return; return;
@ -20,12 +28,16 @@ void FolderServeNode::handle_request_main(Request *request) {
} }
String file_name = request->get_path(true, false); String file_name = request->get_path(true, false);
file_name = file_name.to_lower();
if (file_cache->wwwroot_has_file(file_name)) { int file_indx = _file_cache->wwwroot_get_file_index(file_name);
String fp = file_cache->wwwroot;
fp.append_path(file_name); if (file_indx != -1) {
String fp = _file_cache->get_wwwroot_abs();
fp = fp.append_path(file_name);
request->send_file(_file_cache->wwwroot_get_file_orig_path(file_indx));
request->send_file(fp);
return; return;
} }
@ -35,16 +47,15 @@ void FolderServeNode::handle_request_main(Request *request) {
} }
void FolderServeNode::load() { void FolderServeNode::load() {
file_cache->clear(); _file_cache->clear();
if (serve_folder == "") { if (_serve_folder == "") {
return; _file_cache->set_wwwroot(_serve_folder);
_file_cache->clear();
} else {
_file_cache->set_wwwroot(_serve_folder);
_file_cache->wwwroot_refresh_cache();
} }
serve_folder.path_clean_end_slash();
file_cache->wwwroot = serve_folder;
file_cache->wwwroot_refresh_cache();
} }
void FolderServeNode::_notification(const int what) { void FolderServeNode::_notification(const int what) {
@ -57,11 +68,17 @@ void FolderServeNode::_notification(const int what) {
} }
} }
FolderServeNode::FolderServeNode() : FolderServeNode::FolderServeNode() {
WebNode() { _file_cache.instance();
file_cache = new FileCache();
} }
FolderServeNode::~FolderServeNode() { FolderServeNode::~FolderServeNode() {
} }
void FolderServeNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_serve_folder"), &FolderServeNode::get_serve_folder);
ClassDB::bind_method(D_METHOD("set_serve_folder", "val"), &FolderServeNode::set_serve_folder);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "serve_folder"), "set_serve_folder", "get_serve_folder");
ClassDB::bind_method(D_METHOD("load"), &FolderServeNode::load);
}

View File

@ -1,33 +1,40 @@
#ifndef FOLDER_SERVE_NODE_H #ifndef FOLDER_SERVE_NODE_H
#define FOLDER_SERVE_NODE_H #define FOLDER_SERVE_NODE_H
#include "core/string.h" #include "core/reference.h"
#include "core/ustring.h"
#include "web/file_cache.h" #include "../../http/web_node.h"
#include "web/http/web_node.h"
class WebServerRequest;
class FileCache;
// This class will serve the files from the folder set to it's serve_folder property. // This class will serve the files from the folder set to it's serve_folder property.
// It will cache the folder's contents on ENTER_TREE, and will match against the cached list, // It will cache the folder's contents on ENTER_TREE, and will match against the cached list,
// this means directory walking (for example sending http://webapp.com/files/../../../etc/passwd), // this means directory walking (for example sending http://webapp.com/files/../../../etc/passwd),
// and other techniques like it should not be possible. // and other techniques like it should not be possible.
class FolderServeNode : public WebNode { class FolderServeNode : public WebNode {
RCPP_OBJECT(FolderServeNode, WebNode); GDCLASS(FolderServeNode, WebNode);
public: public:
void handle_request_main(Request *request); String get_serve_folder();
void set_serve_folder(const String &val);
void _handle_request_main(Ref<WebServerRequest> request);
virtual void load(); virtual void load();
void _notification(const int what);
String serve_folder;
FolderServeNode(); FolderServeNode();
~FolderServeNode(); ~FolderServeNode();
protected: protected:
FileCache *file_cache; void _notification(const int what);
static void _bind_methods();
String _serve_folder;
Ref<FileCache> _file_cache;
}; };
#endif #endif

View File

@ -46,6 +46,9 @@ SOFTWARE.
#include "nodes/static_pages/static_page_file.h" #include "nodes/static_pages/static_page_file.h"
#include "nodes/static_pages/static_page_folder_files.h" #include "nodes/static_pages/static_page_folder_files.h"
#include "nodes/folder_serve_nodes/browsable_folder_serve_node.h"
#include "nodes/folder_serve_nodes/folder_serve_node.h"
void register_web_types() { void register_web_types() {
ClassDB::register_class<_HTMLBuilder>(); ClassDB::register_class<_HTMLBuilder>();
ClassDB::register_class<_HTMLTag>(); ClassDB::register_class<_HTMLTag>();
@ -71,6 +74,9 @@ void register_web_types() {
ClassDB::register_class<StaticPage>(); ClassDB::register_class<StaticPage>();
ClassDB::register_class<StaticPageFile>(); ClassDB::register_class<StaticPageFile>();
ClassDB::register_class<StaticPageFolderFiles>(); ClassDB::register_class<StaticPageFolderFiles>();
ClassDB::register_class<FolderServeNode>();
ClassDB::register_class<BrowsableFolderServeNode>();
} }
void unregister_web_types() { void unregister_web_types() {