From a155e4449137adbc6d2b8929cb6dc0dc1c1ec53b Mon Sep 17 00:00:00 2001 From: Relintai Date: Sat, 18 Mar 2023 11:52:25 +0100 Subject: [PATCH] Implement max request size limit for HTTPServerSimple. --- modules/http_server_simple/http_parser.cpp | 15 ++++++++ modules/http_server_simple/http_parser.h | 4 ++ .../http_server_simple/http_server_simple.cpp | 4 ++ .../http_server_simple/http_server_simple.h | 4 ++ .../http_server_simple/web_server_simple.cpp | 38 +++++++++++++++++++ .../http_server_simple/web_server_simple.h | 26 +++++++++++++ 6 files changed, 91 insertions(+) diff --git a/modules/http_server_simple/http_parser.cpp b/modules/http_server_simple/http_parser.cpp index 7844c5148..7b34b85c8 100644 --- a/modules/http_server_simple/http_parser.cpp +++ b/modules/http_server_simple/http_parser.cpp @@ -51,10 +51,23 @@ int HTTPParser::read_from_buffer(const char *p_buffer, const int p_data_length) parsed_bytes = static_cast(http_parser_execute(parser, settings, p_buffer, p_data_length)); + _current_request_size += parsed_bytes; + + if (_current_request_size >= max_request_size) { + _error = true; +#if PROTOCOL_ERROR_LOGGING_ENABLED + PLOG_ERR("_current_request_size >= max_request_size"); +#endif + } + return parsed_bytes; } HTTPParser::HTTPParser() { + // Should always get set from the outside, if it remains 0 it's a bug. + max_request_size = 0; + _current_request_size = 0; + _is_ready = false; _content_type = REQUEST_CONTENT_URLENCODED; _multipart_form_is_file = false; @@ -206,6 +219,8 @@ int HTTPParser::on_message_begin() { ERR_PRINT("Request was valid!"); } + _current_request_size = 0; + _in_header = true; _content_type = REQUEST_CONTENT_URLENCODED; _multipart_form_is_file = false; diff --git a/modules/http_server_simple/http_parser.h b/modules/http_server_simple/http_parser.h index 25c05737f..d3b373f4e 100644 --- a/modules/http_server_simple/http_parser.h +++ b/modules/http_server_simple/http_parser.h @@ -22,6 +22,8 @@ public: REQUEST_CONTENT_TEXT_PLAIN, }; + uint64_t max_request_size; + Ref get_next_request(); int get_request_count() const; @@ -42,6 +44,8 @@ protected: String _partial_data; + uint64_t _current_request_size; + Ref _request; Vector> _requests; diff --git a/modules/http_server_simple/http_server_simple.cpp b/modules/http_server_simple/http_server_simple.cpp index e05575417..c9616f407 100644 --- a/modules/http_server_simple/http_server_simple.cpp +++ b/modules/http_server_simple/http_server_simple.cpp @@ -340,6 +340,7 @@ HTTPServerConnection::HTTPServerConnection() { _http_server = nullptr; _http_parser.instance(); + _http_parser->max_request_size = max_request_size; time = 0; memset(req_buf, 0, sizeof(req_buf)); @@ -428,6 +429,9 @@ void HTTPServerSimple::poll() { connection->_web_server = _web_server; connection->_http_server = this; + connection->max_request_size = max_request_size; + connection->_http_parser->max_request_size = max_request_size; + connection->use_ssl = use_ssl; connection->key = key; diff --git a/modules/http_server_simple/http_server_simple.h b/modules/http_server_simple/http_server_simple.h index 3953f87ad..b71954454 100644 --- a/modules/http_server_simple/http_server_simple.h +++ b/modules/http_server_simple/http_server_simple.h @@ -69,6 +69,8 @@ public: WebServerSimple *_web_server; HTTPServerSimple *_http_server; + uint64_t max_request_size; + bool use_ssl = false; Ref key; @@ -98,6 +100,8 @@ public: WebServerSimple *_web_server; + uint64_t max_request_size; + RBMap mimes; Ref cert; diff --git a/modules/http_server_simple/web_server_simple.cpp b/modules/http_server_simple/web_server_simple.cpp index 1fc884452..3208f5275 100644 --- a/modules/http_server_simple/web_server_simple.cpp +++ b/modules/http_server_simple/web_server_simple.cpp @@ -105,6 +105,22 @@ void WebServerSimple::set_worker_thread_count(const int val) { _worker_thread_count = val; } +WebServerSimple::MaxRequestSizeTypes WebServerSimple::get_max_request_size_type() { + return _max_request_size_type; +} +void WebServerSimple::set_max_request_size_type(const MaxRequestSizeTypes val) { + _max_request_size_type = val; + _apply_max_request_size_type(); +} + +int WebServerSimple::get_max_request_size() { + return _max_request_size; +} +void WebServerSimple::set_max_request_size(const int val) { + _max_request_size = val; + _apply_max_request_size_type(); +} + void WebServerSimple::add_mime_type(const String &file_extension, const String &mime_type) { _server->mimes[file_extension] = mime_type; } @@ -200,6 +216,9 @@ void WebServerSimple::_stop() { } WebServerSimple::WebServerSimple() { + _max_request_size_type = MAX_REQUEST_SIZE_TYPE_MEGA_BYTE; + _max_request_size = 3; + _bind_port = 8080; _bind_host = "127.0.0.1"; @@ -216,6 +235,8 @@ WebServerSimple::WebServerSimple() { _server.instance(); _server->_web_server = this; + + _apply_max_request_size_type(); } WebServerSimple::~WebServerSimple() { @@ -228,6 +249,10 @@ WebServerSimple::~WebServerSimple() { } } +void WebServerSimple::_apply_max_request_size_type() { + _server->max_request_size = (static_cast(1) << (10 * static_cast(_max_request_size_type))) * static_cast(_max_request_size); +} + void WebServerSimple::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { if (_single_threaded_poll) { @@ -271,10 +296,23 @@ void WebServerSimple::_bind_methods() { ClassDB::bind_method(D_METHOD("set_worker_thread_count", "val"), &WebServerSimple::set_worker_thread_count); ADD_PROPERTY(PropertyInfo(Variant::INT, "worker_thread_count"), "set_worker_thread_count", "get_worker_thread_count"); + ClassDB::bind_method(D_METHOD("get_max_request_size_type"), &WebServerSimple::get_max_request_size_type); + ClassDB::bind_method(D_METHOD("set_max_request_size_type", "val"), &WebServerSimple::set_max_request_size_type); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_request_size_type", PROPERTY_HINT_ENUM, "B,KB,MB,GB"), "set_max_request_size_type", "get_max_request_size_type"); + + ClassDB::bind_method(D_METHOD("get_max_request_size"), &WebServerSimple::get_max_request_size); + ClassDB::bind_method(D_METHOD("set_max_request_size", "val"), &WebServerSimple::set_max_request_size); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_request_size"), "set_max_request_size", "get_max_request_size"); + ClassDB::bind_method(D_METHOD("add_mime_type", "file_extension", "mime_type"), &WebServerSimple::add_mime_type); ClassDB::bind_method(D_METHOD("remove_mime_type", "file_extension"), &WebServerSimple::remove_mime_type); ClassDB::bind_method(D_METHOD("is_running"), &WebServerSimple::is_running); + + BIND_ENUM_CONSTANT(MAX_REQUEST_SIZE_TYPE_BYTE); + BIND_ENUM_CONSTANT(MAX_REQUEST_SIZE_TYPE_KILO_BYTE); + BIND_ENUM_CONSTANT(MAX_REQUEST_SIZE_TYPE_MEGA_BYTE); + BIND_ENUM_CONSTANT(MAX_REQUEST_SIZE_TYPE_GIGA_BYTE); } void WebServerSimple::_server_thread_poll(void *data) { diff --git a/modules/http_server_simple/web_server_simple.h b/modules/http_server_simple/web_server_simple.h index 0f6bb2fca..8dcfd0b51 100644 --- a/modules/http_server_simple/web_server_simple.h +++ b/modules/http_server_simple/web_server_simple.h @@ -47,6 +47,13 @@ class WebServerSimple : public WebServer { GDCLASS(WebServerSimple, WebServer); public: + enum MaxRequestSizeTypes { + MAX_REQUEST_SIZE_TYPE_BYTE = 0, + MAX_REQUEST_SIZE_TYPE_KILO_BYTE = 1, + MAX_REQUEST_SIZE_TYPE_MEGA_BYTE = 2, + MAX_REQUEST_SIZE_TYPE_GIGA_BYTE = 3, + }; + int get_bind_port(); void set_bind_port(const int val); @@ -71,6 +78,18 @@ public: int get_worker_thread_count(); void set_worker_thread_count(const int val); + MaxRequestSizeTypes get_max_request_size_type(); + void set_max_request_size_type(const MaxRequestSizeTypes val); + + // Note, that the implementation is extremely simple for now. + // This includes the entire request header, including file uploads, + // as right now uploaded files are stored in memory, + // so this will not change until temp files are implemented. + // (A big file upload / request can eat all the ram in a server!) + // Also 0 means 0, not unlimited -> This should NOT change (Reason: line above). + int get_max_request_size(); + void set_max_request_size(const int val); + void add_mime_type(const String &file_extension, const String &mime_type); void remove_mime_type(const String &file_extension); @@ -83,6 +102,8 @@ public: ~WebServerSimple(); protected: + void _apply_max_request_size_type(); + void _notification(int p_what); static void _bind_methods(); @@ -101,6 +122,9 @@ protected: bool _single_threaded_poll; + MaxRequestSizeTypes _max_request_size_type; + int _max_request_size; + Ref _server; bool _server_quit; Mutex _server_lock; @@ -110,4 +134,6 @@ protected: static void _server_thread_poll(void *data); }; +VARIANT_ENUM_CAST(WebServerSimple::MaxRequestSizeTypes); + #endif