mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-01-12 22:01:10 +01:00
Refactored the SimpleHTTPServer to be able to multi thread it a bit later.
This commit is contained in:
parent
7b7b27297f
commit
492f29163c
@ -35,50 +35,11 @@
|
||||
#include "simple_web_server_request.h"
|
||||
#include "web_server_simple.h"
|
||||
|
||||
void HTTPServerSimple::stop() {
|
||||
server->stop();
|
||||
_clear_client();
|
||||
}
|
||||
void HTTPServerConnection::update() {
|
||||
ERR_FAIL_COND(closed());
|
||||
|
||||
Error HTTPServerSimple::listen(int p_port, IP_Address p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) {
|
||||
use_ssl = p_use_ssl;
|
||||
if (use_ssl) {
|
||||
Ref<Crypto> crypto = Crypto::create();
|
||||
if (crypto.is_null()) {
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
if (!p_ssl_key.empty() && !p_ssl_cert.empty()) {
|
||||
key = Ref<CryptoKey>(CryptoKey::create());
|
||||
Error err = key->load(p_ssl_key);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
cert = Ref<X509Certificate>(X509Certificate::create());
|
||||
err = cert->load(p_ssl_cert);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
} else {
|
||||
_set_internal_certs(crypto);
|
||||
}
|
||||
}
|
||||
return server->listen(p_port, p_address);
|
||||
}
|
||||
|
||||
bool HTTPServerSimple::is_listening() const {
|
||||
return server->is_listening();
|
||||
}
|
||||
|
||||
void HTTPServerSimple::poll() {
|
||||
if (!server->is_listening()) {
|
||||
return;
|
||||
}
|
||||
if (tcp.is_null()) {
|
||||
if (!server->is_connection_available()) {
|
||||
return;
|
||||
}
|
||||
tcp = server->take_connection();
|
||||
peer = tcp;
|
||||
time = OS::get_singleton()->get_ticks_usec();
|
||||
}
|
||||
if (OS::get_singleton()->get_ticks_usec() - time > 1000000) {
|
||||
_clear_client();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
if (tcp->get_status() != StreamPeerTCP::STATUS_CONNECTED) {
|
||||
@ -90,8 +51,8 @@ void HTTPServerSimple::poll() {
|
||||
ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create());
|
||||
peer = ssl;
|
||||
ssl->set_blocking_handshake_enabled(false);
|
||||
if (ssl->accept_stream(tcp, key, cert) != OK) {
|
||||
_clear_client();
|
||||
if (ssl->accept_stream(tcp, key, _http_server->cert) != OK) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -101,7 +62,7 @@ void HTTPServerSimple::poll() {
|
||||
return;
|
||||
}
|
||||
if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) {
|
||||
_clear_client();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -111,7 +72,7 @@ void HTTPServerSimple::poll() {
|
||||
|
||||
if (err != OK) {
|
||||
// Got an error
|
||||
_clear_client();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -130,18 +91,19 @@ void HTTPServerSimple::poll() {
|
||||
if (_http_parser->get_request_count() > 0) {
|
||||
Ref<SimpleWebServerRequest> request = _http_parser->get_next_request();
|
||||
|
||||
request->_server = this;
|
||||
request->_server = _http_server;
|
||||
request->_connection = Ref<HTTPServerConnection>(this);
|
||||
request->setup_url_stack();
|
||||
|
||||
_web_server->server_handle_request(request);
|
||||
|
||||
if (_http_parser->get_request_count() == 0 && _http_parser->is_finished()) {
|
||||
_clear_client();
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPServerSimple::send_redirect(Ref<WebServerRequest> request, const String &location, const HTTPServerEnums::HTTPStatusCode status_code) {
|
||||
void HTTPServerConnection::send_redirect(Ref<WebServerRequest> request, const String &location, const HTTPServerEnums::HTTPStatusCode status_code) {
|
||||
//String s = "HTTP/1.1 " + itos(static_cast<int>(status_code)) + " Found\r\n";
|
||||
String s = "HTTP/1.1 " + HTTPServerEnums::get_status_code_header_string(status_code) + "\r\n";
|
||||
s += "Location: " + location + "\r\n";
|
||||
@ -163,7 +125,7 @@ void HTTPServerSimple::send_redirect(Ref<WebServerRequest> request, const String
|
||||
CharString cs = s.utf8();
|
||||
peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
|
||||
}
|
||||
void HTTPServerSimple::send(Ref<WebServerRequest> request) {
|
||||
void HTTPServerConnection::send(Ref<WebServerRequest> request) {
|
||||
String body = request->get_compiled_body();
|
||||
|
||||
String s = "HTTP/1.1 " + HTTPServerEnums::get_status_code_header_string(request->get_status_code()) + "\r\n";
|
||||
@ -189,7 +151,7 @@ void HTTPServerSimple::send(Ref<WebServerRequest> request) {
|
||||
CharString cs = s.utf8();
|
||||
peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
|
||||
}
|
||||
void HTTPServerSimple::send_file(Ref<WebServerRequest> request, const String &p_file_path) {
|
||||
void HTTPServerConnection::send_file(Ref<WebServerRequest> request, const String &p_file_path) {
|
||||
if (!FileAccess::exists(p_file_path)) {
|
||||
String s = "HTTP/1.1 404 Not Found\r\n";
|
||||
s += "Connection: Close\r\n";
|
||||
@ -215,8 +177,8 @@ void HTTPServerSimple::send_file(Ref<WebServerRequest> request, const String &p_
|
||||
String ctype;
|
||||
String req_ext = p_file_path.get_extension();
|
||||
|
||||
if (!mimes.has(req_ext)) {
|
||||
ctype = mimes[req_ext];
|
||||
if (!_http_server->mimes.has(req_ext)) {
|
||||
ctype = _http_server->mimes[req_ext];
|
||||
} else {
|
||||
ctype = "text/plain";
|
||||
}
|
||||
@ -268,6 +230,98 @@ void HTTPServerSimple::send_file(Ref<WebServerRequest> request, const String &p_
|
||||
memdelete(f);
|
||||
}
|
||||
|
||||
void HTTPServerConnection::close() {
|
||||
tcp.unref();
|
||||
ssl.unref();
|
||||
peer.unref();
|
||||
|
||||
_closed = true;
|
||||
}
|
||||
bool HTTPServerConnection::closed() {
|
||||
return _closed;
|
||||
}
|
||||
|
||||
HTTPServerConnection::HTTPServerConnection() {
|
||||
_web_server = nullptr;
|
||||
_http_server = nullptr;
|
||||
|
||||
_http_parser.instance();
|
||||
time = 0;
|
||||
|
||||
memset(req_buf, 0, sizeof(req_buf));
|
||||
|
||||
_closed = false;
|
||||
}
|
||||
HTTPServerConnection::~HTTPServerConnection() {
|
||||
}
|
||||
|
||||
void HTTPServerSimple::stop() {
|
||||
server->stop();
|
||||
_clear_clients();
|
||||
}
|
||||
|
||||
Error HTTPServerSimple::listen(int p_port, IP_Address p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) {
|
||||
use_ssl = p_use_ssl;
|
||||
if (use_ssl) {
|
||||
Ref<Crypto> crypto = Crypto::create();
|
||||
if (crypto.is_null()) {
|
||||
return ERR_UNAVAILABLE;
|
||||
}
|
||||
if (!p_ssl_key.empty() && !p_ssl_cert.empty()) {
|
||||
key = Ref<CryptoKey>(CryptoKey::create());
|
||||
Error err = key->load(p_ssl_key);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
cert = Ref<X509Certificate>(X509Certificate::create());
|
||||
err = cert->load(p_ssl_cert);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
} else {
|
||||
_set_internal_certs(crypto);
|
||||
}
|
||||
}
|
||||
return server->listen(p_port, p_address);
|
||||
}
|
||||
|
||||
bool HTTPServerSimple::is_listening() const {
|
||||
return server->is_listening();
|
||||
}
|
||||
|
||||
void HTTPServerSimple::poll() {
|
||||
if (!server->is_listening()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//todo add connection limit
|
||||
while (server->is_connection_available()) {
|
||||
Ref<HTTPServerConnection> connection;
|
||||
connection.instance();
|
||||
|
||||
connection->_web_server = _web_server;
|
||||
connection->_http_server = this;
|
||||
|
||||
connection->use_ssl = use_ssl;
|
||||
connection->key = key;
|
||||
|
||||
connection->tcp = server->take_connection();
|
||||
connection->peer = connection->tcp;
|
||||
connection->time = OS::get_singleton()->get_ticks_usec();
|
||||
|
||||
_connections.push_back(connection);
|
||||
}
|
||||
|
||||
//TODO This should be done by worker threads (with a proper lock free queue)
|
||||
for (int i = 0; i < _connections.size(); ++i) {
|
||||
Ref<HTTPServerConnection> c = _connections[i];
|
||||
|
||||
if (c->closed()) {
|
||||
_connections.remove(i);
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
c->update();
|
||||
}
|
||||
}
|
||||
|
||||
HTTPServerSimple::HTTPServerSimple() {
|
||||
_web_server = nullptr;
|
||||
|
||||
@ -280,19 +334,18 @@ HTTPServerSimple::HTTPServerSimple() {
|
||||
mimes["wasm"] = "application/wasm";
|
||||
|
||||
server.instance();
|
||||
_http_parser.instance();
|
||||
stop();
|
||||
}
|
||||
|
||||
HTTPServerSimple::~HTTPServerSimple() {
|
||||
}
|
||||
|
||||
void HTTPServerSimple::_clear_client() {
|
||||
peer = Ref<StreamPeer>();
|
||||
ssl = Ref<StreamPeerSSL>();
|
||||
tcp = Ref<StreamPeerTCP>();
|
||||
memset(req_buf, 0, sizeof(req_buf));
|
||||
time = 0;
|
||||
void HTTPServerSimple::_clear_clients() {
|
||||
for (int i = 0; i < _connections.size(); ++i) {
|
||||
_connections.write[i]->close();
|
||||
}
|
||||
|
||||
_connections.clear();
|
||||
}
|
||||
|
||||
void HTTPServerSimple::_set_internal_certs(Ref<Crypto> p_crypto) {
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "core/io/stream_peer_ssl.h"
|
||||
#include "core/io/tcp_server.h"
|
||||
#include "core/io/zip_io.h"
|
||||
#include "core/vector.h"
|
||||
|
||||
#include "core/project_settings.h"
|
||||
|
||||
@ -42,8 +43,44 @@
|
||||
class HTTPParser;
|
||||
class WebServerSimple;
|
||||
class WebServerRequest;
|
||||
class HTTPServerSimple;
|
||||
|
||||
class HTTPServerConnection : public Reference {
|
||||
GDCLASS(HTTPServerConnection, Reference);
|
||||
|
||||
public:
|
||||
void update();
|
||||
|
||||
void send_redirect(Ref<WebServerRequest> request, const String &location, const HTTPServerEnums::HTTPStatusCode status_code);
|
||||
void send(Ref<WebServerRequest> request);
|
||||
void send_file(Ref<WebServerRequest> request, const String &p_file_path);
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
HTTPServerConnection();
|
||||
~HTTPServerConnection();
|
||||
|
||||
WebServerSimple *_web_server;
|
||||
HTTPServerSimple *_http_server;
|
||||
|
||||
bool use_ssl = false;
|
||||
Ref<CryptoKey> key;
|
||||
|
||||
Ref<StreamPeerTCP> tcp;
|
||||
Ref<StreamPeerSSL> ssl;
|
||||
Ref<StreamPeer> peer;
|
||||
|
||||
Ref<HTTPParser> _http_parser;
|
||||
uint64_t time = 0;
|
||||
uint8_t req_buf[4096];
|
||||
|
||||
bool _closed;
|
||||
};
|
||||
|
||||
class HTTPServerSimple : public Reference {
|
||||
GDCLASS(HTTPServerSimple, Reference);
|
||||
|
||||
public:
|
||||
void stop();
|
||||
|
||||
@ -51,29 +88,25 @@ public:
|
||||
bool is_listening() const;
|
||||
void poll();
|
||||
|
||||
void send_redirect(Ref<WebServerRequest> request, const String &location, const HTTPServerEnums::HTTPStatusCode status_code);
|
||||
void send(Ref<WebServerRequest> request);
|
||||
void send_file(Ref<WebServerRequest> request, const String &p_file_path);
|
||||
|
||||
HTTPServerSimple();
|
||||
~HTTPServerSimple();
|
||||
|
||||
WebServerSimple *_web_server;
|
||||
|
||||
Map<String, String> mimes;
|
||||
|
||||
Ref<X509Certificate> cert;
|
||||
|
||||
private:
|
||||
Ref<TCP_Server> server;
|
||||
Map<String, String> mimes;
|
||||
Ref<StreamPeerTCP> tcp;
|
||||
Ref<StreamPeerSSL> ssl;
|
||||
Ref<StreamPeer> peer;
|
||||
Ref<CryptoKey> key;
|
||||
Ref<X509Certificate> cert;
|
||||
Ref<HTTPParser> _http_parser;
|
||||
bool use_ssl = false;
|
||||
uint64_t time = 0;
|
||||
uint8_t req_buf[4096];
|
||||
|
||||
void _clear_client();
|
||||
Ref<CryptoKey> key;
|
||||
bool use_ssl = false;
|
||||
|
||||
//TODO add a lock free queue
|
||||
Vector<Ref<HTTPServerConnection>> _connections;
|
||||
|
||||
void _clear_clients();
|
||||
void _set_internal_certs(Ref<Crypto> p_crypto);
|
||||
};
|
||||
|
||||
|
@ -75,13 +75,13 @@ String SimpleWebServerRequest::get_parameter(const String &key) const {
|
||||
void SimpleWebServerRequest::send_redirect(const String &location, const HTTPServerEnums::HTTPStatusCode status_code) {
|
||||
ERR_FAIL_COND(!_server);
|
||||
|
||||
_server->send_redirect(Ref<WebServerRequest>(this), location, status_code);
|
||||
_connection->send_redirect(Ref<WebServerRequest>(this), location, status_code);
|
||||
}
|
||||
|
||||
void SimpleWebServerRequest::send() {
|
||||
ERR_FAIL_COND(!_server);
|
||||
|
||||
_server->send(Ref<WebServerRequest>(this));
|
||||
_connection->send(Ref<WebServerRequest>(this));
|
||||
|
||||
// if (connection_closed) {
|
||||
// SimpleWebServerRequestPool::return_request(this);
|
||||
@ -92,9 +92,9 @@ void SimpleWebServerRequest::send() {
|
||||
}
|
||||
|
||||
void SimpleWebServerRequest::send_file(const String &p_file_path) {
|
||||
ERR_FAIL_COND(!_server);
|
||||
ERR_FAIL_COND(!_connection.is_valid());
|
||||
|
||||
_server->send_file(Ref<WebServerRequest>(this), p_file_path);
|
||||
_connection->send_file(Ref<WebServerRequest>(this), p_file_path);
|
||||
|
||||
// SimpleWebServerRequestPool::return_request(this);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ class HTTPSession;
|
||||
class WebPermission;
|
||||
class WebNode;
|
||||
class HTTPServerSimple;
|
||||
class HTTPServerConnection;
|
||||
|
||||
class SimpleWebServerRequest : public WebServerRequest {
|
||||
GDCLASS(SimpleWebServerRequest, WebServerRequest);
|
||||
@ -57,6 +58,7 @@ public:
|
||||
~SimpleWebServerRequest();
|
||||
|
||||
HTTPServerSimple *_server;
|
||||
Ref<HTTPServerConnection> _connection;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
Loading…
Reference in New Issue
Block a user