From 715737abfef16aa7b841cd32bcfa639db95efbd1 Mon Sep 17 00:00:00 2001 From: Relintai Date: Mon, 28 Aug 2023 12:54:30 +0200 Subject: [PATCH] Now HTTPServerSimple sends files in non-blocking mode. --- .../http_server_simple/http_server_simple.cpp | 146 +++++++++++------- .../http_server_simple/http_server_simple.h | 8 + .../simple_web_server_request.cpp | 5 + .../simple_web_server_request.h | 5 + 4 files changed, 112 insertions(+), 52 deletions(-) diff --git a/modules/http_server_simple/http_server_simple.cpp b/modules/http_server_simple/http_server_simple.cpp index 7fbd6bed0..30dfc519c 100644 --- a/modules/http_server_simple/http_server_simple.cpp +++ b/modules/http_server_simple/http_server_simple.cpp @@ -41,7 +41,9 @@ #define CONNECTION_RESPOSE_DEBUG 0 void HTTPServerConnection::update() { - ERR_FAIL_COND(closed()); + if (closed()) { + return; + } if (OS::get_singleton()->get_ticks_usec() - time > 1000000) { close(); @@ -91,6 +93,22 @@ void HTTPServerConnection::update() { } } + if (_current_request.is_valid()) { + udpate_send_file(_current_request); + + if (closed()) { + //some error happened + return; + } + + if (!_current_request->sent()) { + // we will get back to this + return; + } + + _current_request.unref(); + } + int read = 0; Error err = peer->get_partial_data(req_buf, 4096, read); @@ -118,13 +136,25 @@ void HTTPServerConnection::update() { } if (_http_parser->get_request_count() > 0) { - Ref request = _http_parser->get_next_request(); + _current_request = _http_parser->get_next_request(); - request->_server = _http_server; - request->_connection = Ref(this); - request->setup_url_stack(); + _current_request->_server = _http_server; + _current_request->_connection = Ref(this); + _current_request->setup_url_stack(); - _web_server->server_handle_request(request); + _web_server->server_handle_request(_current_request); + + if (closed()) { + //some error happened + return; + } + + if (!_current_request->sent()) { + // we will get back to this + return; + } + + _current_request.unref(); if (_http_parser->get_request_count() == 0 && _http_parser->is_finished()) { close(); @@ -233,45 +263,19 @@ void HTTPServerConnection::send_file(Ref request, const String HashMap custom_headers = request->custom_response_headers_get(); if (!FileAccess::exists(p_file_path)) { - String s = "HTTP/1.1 404 Not Found\r\n"; - - if (!custom_headers.has("Connection")) { - if (has_more_messages()) { - s += "Connection: keep-alive\r\n"; - } else { - s += "Connection: close\r\n"; - } - } - - for (int i = 0; i < request->response_get_cookie_count(); ++i) { - Ref cookie = request->response_get_cookie(i); - - ERR_CONTINUE(!cookie.is_valid()); - - String cookie_str = cookie->get_response_header_string(); - - if (cookie_str != "") { - s += cookie_str; - } - } - - for (HashMap::Element *E = custom_headers.front(); E; E = E->next) { - s += String(E->key()) + ": " + E->value() + "\r\n"; - } - - s += "\r\n"; - -#if CONNECTION_RESPOSE_DEBUG - ERR_PRINT(s); -#endif - - CharString cs = s.utf8(); - peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1); + request->send_error(HTTPServerEnums::HTTP_STATUS_CODE_404_NOT_FOUND); + return; + } + + Ref r = request; + + r->_sending_file_fa = FileAccess::open(p_file_path, FileAccess::READ); + + if (!r->_sending_file_fa) { + request->send_error(HTTPServerEnums::HTTP_STATUS_CODE_404_NOT_FOUND); return; } - FileAccess *f = FileAccess::open(p_file_path, FileAccess::READ); - ERR_FAIL_COND(!f); String s = "HTTP/1.1 " + HTTPServerEnums::get_status_code_header_string(request->get_status_code()) + "\r\n"; if (!custom_headers.has("Connection")) { @@ -295,6 +299,10 @@ void HTTPServerConnection::send_file(Ref request, const String s += "Content-Type: " + ctype + "\r\n"; } + uint64_t file_length = r->_sending_file_fa->get_len(); + + s += "Content-Length: " + itos(file_length) + "\r\n"; + for (int i = 0; i < request->response_get_cookie_count(); ++i) { Ref cookie = request->response_get_cookie(i); @@ -321,24 +329,55 @@ void HTTPServerConnection::send_file(Ref request, const String Error err = peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1); if (err != OK) { - memdelete(f); - ERR_FAIL(); + close(); + return; } + _buffer_start = 0; + _buffer_end = 0; + + udpate_send_file(r); +} + +void HTTPServerConnection::udpate_send_file(Ref request) { while (true) { - uint8_t bytes[4096]; - uint64_t read = f->get_buffer(bytes, 4096); - if (read == 0) { - break; + //read into buffer + if (_buffer_start == _buffer_end) { + _buffer_start = 0; + + _buffer_end = request->_sending_file_fa->get_buffer(_file_send_buffer, 4096); + + if (_buffer_end == 0) { + //finished + break; + } } - err = peer->put_data(bytes, read); + + int read = 0; + Error err = peer->put_partial_data(&_file_send_buffer[_buffer_start], _buffer_end - _buffer_start, read); + + _buffer_start += read; + + if (err == ERR_BUSY) { + // we can get ERR_BUSY is the socket is full -> we need to wait + return; + } + if (err != OK) { - memdelete(f); - ERR_FAIL(); + close(); + memdelete(request->_sending_file_fa); + request->_sending_file_fa = NULL; + _buffer_start = 0; + _buffer_end = 0; + return; } } - memdelete(f); + memdelete(request->_sending_file_fa); + request->_sending_file_fa = NULL; + + _buffer_start = 0; + _buffer_end = 0; } void HTTPServerConnection::close() { @@ -383,6 +422,9 @@ HTTPServerConnection::HTTPServerConnection() { memset(req_buf, 0, sizeof(req_buf)); _closed = false; + + _buffer_start = 0; + _buffer_end = 0; } HTTPServerConnection::~HTTPServerConnection() { } diff --git a/modules/http_server_simple/http_server_simple.h b/modules/http_server_simple/http_server_simple.h index b71954454..0448f099a 100644 --- a/modules/http_server_simple/http_server_simple.h +++ b/modules/http_server_simple/http_server_simple.h @@ -47,6 +47,7 @@ class HTTPParser; class WebServerSimple; class WebServerRequest; class HTTPServerSimple; +class SimpleWebServerRequest; class HTTPServerConnection : public Reference { GDCLASS(HTTPServerConnection, Reference); @@ -58,6 +59,8 @@ public: void send(Ref request); void send_file(Ref request, const String &p_file_path); + void udpate_send_file(Ref request); + void close(); bool closed(); @@ -82,6 +85,11 @@ public: uint64_t time = 0; uint8_t req_buf[4096]; + Ref _current_request; + uint8_t _file_send_buffer[4096]; + uint64_t _buffer_start; + uint64_t _buffer_end; + bool _closed; }; diff --git a/modules/http_server_simple/simple_web_server_request.cpp b/modules/http_server_simple/simple_web_server_request.cpp index b8039b2fc..284e24aee 100644 --- a/modules/http_server_simple/simple_web_server_request.cpp +++ b/modules/http_server_simple/simple_web_server_request.cpp @@ -211,9 +211,14 @@ void SimpleWebServerRequest::set_method(const HTTPServerEnums::HTTPMethod method _method = method; } +bool SimpleWebServerRequest::sent() { + return !_sending_file_fa; +} + SimpleWebServerRequest::SimpleWebServerRequest() { _server = nullptr; _method = HTTPServerEnums::HTTP_METHOD_GET; + _sending_file_fa = NULL; } SimpleWebServerRequest::~SimpleWebServerRequest() { diff --git a/modules/http_server_simple/simple_web_server_request.h b/modules/http_server_simple/simple_web_server_request.h index 2040d0dc6..ae3259e99 100644 --- a/modules/http_server_simple/simple_web_server_request.h +++ b/modules/http_server_simple/simple_web_server_request.h @@ -5,6 +5,7 @@ #include "core/containers/vector.h" #include "core/string/ustring.h" #include "core/variant/dictionary.h" +#include "core/os/file_access.h" #include "modules/web/http/web_server_request.h" @@ -60,12 +61,16 @@ public: //virtual String get_path_full() const; + bool sent(); + SimpleWebServerRequest(); ~SimpleWebServerRequest(); HTTPServerSimple *_server; Ref _connection; + FileAccess *_sending_file_fa; + protected: static void _bind_methods();