Implemented custom response headers for WebServerRequest.

This commit is contained in:
Relintai 2023-07-08 21:11:56 +02:00
parent 3244eab5c5
commit b68bbd3bfb
4 changed files with 159 additions and 34 deletions

View File

@ -139,13 +139,20 @@ void HTTPServerConnection::update() {
void HTTPServerConnection::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 " + itos(static_cast<int>(status_code)) + " Found\r\n";
String s = "HTTP/1.1 " + HTTPServerEnums::get_status_code_header_string(status_code) + "\r\n"; String s = "HTTP/1.1 " + HTTPServerEnums::get_status_code_header_string(status_code) + "\r\n";
s += "Location: " + location + "\r\n";
HashMap<StringName, String> custom_headers = request->custom_response_headers_get();
if (!custom_headers.has("Location")) {
s += "Location: " + location + "\r\n";
}
if (!custom_headers.has("Connection")) {
if (has_more_messages()) { if (has_more_messages()) {
s += "Connection: keep-alive\r\n"; s += "Connection: keep-alive\r\n";
} else { } else {
s += "Connection: close\r\n"; s += "Connection: close\r\n";
} }
}
for (int i = 0; i < request->response_get_cookie_count(); ++i) { for (int i = 0; i < request->response_get_cookie_count(); ++i) {
Ref<WebServerCookie> cookie = request->response_get_cookie(i); Ref<WebServerCookie> cookie = request->response_get_cookie(i);
@ -159,6 +166,10 @@ void HTTPServerConnection::send_redirect(Ref<WebServerRequest> request, const St
} }
} }
for (HashMap<StringName, String>::Element *E = custom_headers.front(); E; E = E->next) {
s += String(E->key()) + ": " + E->value() + "\r\n";
}
s += "\r\n"; s += "\r\n";
#if CONNECTION_RESPOSE_DEBUG #if CONNECTION_RESPOSE_DEBUG
@ -172,15 +183,25 @@ void HTTPServerConnection::send_redirect(Ref<WebServerRequest> request, const St
void HTTPServerConnection::send(Ref<WebServerRequest> request) { void HTTPServerConnection::send(Ref<WebServerRequest> request) {
String body = request->get_compiled_body(); String body = request->get_compiled_body();
String s = "HTTP/1.1 " + HTTPServerEnums::get_status_code_header_string(request->get_status_code()) + "\r\n"; HashMap<StringName, String> custom_headers = request->custom_response_headers_get();
s += "Content-Length: " + itos(body.utf8_byte_length()) + "\r\n";
s += "Content-type: text/html\r\n";
String s = "HTTP/1.1 " + HTTPServerEnums::get_status_code_header_string(request->get_status_code()) + "\r\n";
if (!custom_headers.has("Content-Length")) {
s += "Content-Length: " + itos(body.utf8_byte_length()) + "\r\n";
}
if (!custom_headers.has("Content-type")) {
s += "Content-type: text/html\r\n";
}
if (!custom_headers.has("Connection")) {
if (has_more_messages()) { if (has_more_messages()) {
s += "Connection: keep-alive\r\n"; s += "Connection: keep-alive\r\n";
} else { } else {
s += "Connection: close\r\n"; s += "Connection: close\r\n";
} }
}
for (int i = 0; i < request->response_get_cookie_count(); ++i) { for (int i = 0; i < request->response_get_cookie_count(); ++i) {
Ref<WebServerCookie> cookie = request->response_get_cookie(i); Ref<WebServerCookie> cookie = request->response_get_cookie(i);
@ -194,6 +215,10 @@ void HTTPServerConnection::send(Ref<WebServerRequest> request) {
} }
} }
for (HashMap<StringName, String>::Element *E = custom_headers.front(); E; E = E->next) {
s += String(E->key()) + ": " + E->value() + "\r\n";
}
s += "\r\n"; s += "\r\n";
s += body; s += body;
@ -205,14 +230,18 @@ void HTTPServerConnection::send(Ref<WebServerRequest> request) {
peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1); peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1);
} }
void HTTPServerConnection::send_file(Ref<WebServerRequest> request, const String &p_file_path) { void HTTPServerConnection::send_file(Ref<WebServerRequest> request, const String &p_file_path) {
HashMap<StringName, String> custom_headers = request->custom_response_headers_get();
if (!FileAccess::exists(p_file_path)) { if (!FileAccess::exists(p_file_path)) {
String s = "HTTP/1.1 404 Not Found\r\n"; String s = "HTTP/1.1 404 Not Found\r\n";
if (!custom_headers.has("Connection")) {
if (has_more_messages()) { if (has_more_messages()) {
s += "Connection: keep-alive\r\n"; s += "Connection: keep-alive\r\n";
} else { } else {
s += "Connection: close\r\n"; s += "Connection: close\r\n";
} }
}
for (int i = 0; i < request->response_get_cookie_count(); ++i) { for (int i = 0; i < request->response_get_cookie_count(); ++i) {
Ref<WebServerCookie> cookie = request->response_get_cookie(i); Ref<WebServerCookie> cookie = request->response_get_cookie(i);
@ -226,6 +255,10 @@ void HTTPServerConnection::send_file(Ref<WebServerRequest> request, const String
} }
} }
for (HashMap<StringName, String>::Element *E = custom_headers.front(); E; E = E->next) {
s += String(E->key()) + ": " + E->value() + "\r\n";
}
s += "\r\n"; s += "\r\n";
#if CONNECTION_RESPOSE_DEBUG #if CONNECTION_RESPOSE_DEBUG
@ -237,6 +270,19 @@ void HTTPServerConnection::send_file(Ref<WebServerRequest> request, const String
return; return;
} }
FileAccess *f = FileAccess::open(p_file_path, FileAccess::READ);
ERR_FAIL_COND(!f);
String s = "HTTP/1.1 200 OK\r\n";
if (!custom_headers.has("Connection")) {
if (has_more_messages()) {
s += "Connection: keep-alive\r\n";
} else {
s += "Connection: close\r\n";
}
}
if (!custom_headers.has("Content-Type")) {
String ctype; String ctype;
String req_ext = p_file_path.get_extension(); String req_ext = p_file_path.get_extension();
@ -246,17 +292,8 @@ void HTTPServerConnection::send_file(Ref<WebServerRequest> request, const String
ctype = "text/plain"; ctype = "text/plain";
} }
FileAccess *f = FileAccess::open(p_file_path, FileAccess::READ);
ERR_FAIL_COND(!f);
String s = "HTTP/1.1 200 OK\r\n";
if (has_more_messages()) {
s += "Connection: keep-alive\r\n";
} else {
s += "Connection: close\r\n";
}
s += "Content-Type: " + ctype + "\r\n"; s += "Content-Type: " + ctype + "\r\n";
}
for (int i = 0; i < request->response_get_cookie_count(); ++i) { for (int i = 0; i < request->response_get_cookie_count(); ++i) {
Ref<WebServerCookie> cookie = request->response_get_cookie(i); Ref<WebServerCookie> cookie = request->response_get_cookie(i);
@ -270,10 +307,10 @@ void HTTPServerConnection::send_file(Ref<WebServerRequest> request, const String
} }
} }
s += "Access-Control-Allow-Origin: *\r\n"; for (HashMap<StringName, String>::Element *E = custom_headers.front(); E; E = E->next) {
s += "Cross-Origin-Opener-Policy: same-origin\r\n"; s += String(E->key()) + ": " + E->value() + "\r\n";
s += "Cross-Origin-Embedder-Policy: require-corp\r\n"; }
s += "Cache-Control: no-store, max-age=0\r\n";
s += "\r\n"; s += "\r\n";
#if CONNECTION_RESPOSE_DEBUG #if CONNECTION_RESPOSE_DEBUG

View File

@ -48,6 +48,34 @@
Takes the head, body and footer properties, and merges them into the [code]compiled_body[/code] property. It adds an html5 type declaration, then the opening [code]html[/code] tag, then the contents of the [code]head[/code] property to the [code]head[/code] section of the response, and then the contents of the [code]body[/code] then footer property into the [code]body[/code] section of the response, then it closes the main [code]html[/code] tag. Takes the head, body and footer properties, and merges them into the [code]compiled_body[/code] property. It adds an html5 type declaration, then the opening [code]html[/code] tag, then the contents of the [code]head[/code] property to the [code]head[/code] section of the response, and then the contents of the [code]body[/code] then footer property into the [code]body[/code] section of the response, then it closes the main [code]html[/code] tag.
</description> </description>
</method> </method>
<method name="custom_response_header_get">
<return type="String" />
<argument index="0" name="key" type="StringName" />
<description>
Returns a custom HTTP response header or an empty String if it's not set.
</description>
</method>
<method name="custom_response_header_has">
<return type="bool" />
<argument index="0" name="key" type="StringName" />
<description>
Returns whether a custom HTTP response header is set.
</description>
</method>
<method name="custom_response_header_set">
<return type="void" />
<argument index="0" name="key" type="StringName" />
<argument index="1" name="value" type="String" />
<description>
Set a custom HTTP response header that will be sent to the client.
</description>
</method>
<method name="custom_response_headers_get">
<return type="Dictionary" />
<description>
Returns all the custom response headers that were previously set.
</description>
</method>
<method name="get_cookie"> <method name="get_cookie">
<return type="String" /> <return type="String" />
<argument index="0" name="key" type="String" /> <argument index="0" name="key" type="String" />
@ -394,6 +422,10 @@
<member name="connection_closed" type="bool" setter="set_connection_closed" getter="get_connection_closed" default="false"> <member name="connection_closed" type="bool" setter="set_connection_closed" getter="get_connection_closed" default="false">
The server might set this to true if the connection got closed while handling the request. It's not yet used. The server might set this to true if the connection got closed while handling the request. It's not yet used.
</member> </member>
<member name="content_type" type="String" setter="set_content_type" getter="get_content_type" default="&quot;&quot;">
A shorthand property to set the Content-Type HTTP header.
Equivalent to [code]custom_response_header_set("Content-Type", content_type)[/code] and [code]custom_response_header_get("Content-Type")[/code].
</member>
<member name="footer" type="String" setter="set_footer" getter="get_footer" default="&quot;&quot;"> <member name="footer" type="String" setter="set_footer" getter="get_footer" default="&quot;&quot;">
When you call [code]compile_body()[/code] or [code]compile_and_send_body()[/code], the contents of this property will end up in the bottom of the [code]body[/code] portion of the resulting HTML. When you call [code]compile_body()[/code] or [code]compile_and_send_body()[/code], the contents of this property will end up in the bottom of the [code]body[/code] portion of the resulting HTML.
</member> </member>

View File

@ -176,6 +176,41 @@ void WebServerRequest::response_remove_cookie_simple(const String &key) {
_cookies.push_back(cookie); _cookies.push_back(cookie);
} }
void WebServerRequest::custom_response_header_set(const StringName &key, const String &value) {
_custom_response_headers[key] = value;
}
String WebServerRequest::custom_response_header_get(const StringName &key) {
String *e = _custom_response_headers.getptr(key);
if (!e) {
return "";
}
return *e;
}
bool WebServerRequest::custom_response_header_has(const StringName &key) {
return _custom_response_headers.has(key);
}
HashMap<StringName, String> WebServerRequest::custom_response_headers_get() {
return _custom_response_headers;
}
Dictionary WebServerRequest::custom_response_headers_get_bind() {
Dictionary ret;
for (HashMap<StringName, String>::Element *E = _custom_response_headers.front(); E; E = E->next) {
ret[E->key()] = E->value();
}
return ret;
}
String WebServerRequest::get_content_type() {
return custom_response_header_get("Content-Type");
}
void WebServerRequest::set_content_type(const String &content_type) {
custom_response_header_set("Content-Type", content_type);
}
HTTPServerEnums::HTTPMethod WebServerRequest::get_method() const { HTTPServerEnums::HTTPMethod WebServerRequest::get_method() const {
return HTTPServerEnums::HTTP_METHOD_GET; return HTTPServerEnums::HTTP_METHOD_GET;
} }
@ -550,6 +585,15 @@ void WebServerRequest::_bind_methods() {
ClassDB::bind_method(D_METHOD("response_remove_cookie", "index"), &WebServerRequest::response_remove_cookie); ClassDB::bind_method(D_METHOD("response_remove_cookie", "index"), &WebServerRequest::response_remove_cookie);
ClassDB::bind_method(D_METHOD("response_remove_cookie_simple", "key"), &WebServerRequest::response_remove_cookie_simple); ClassDB::bind_method(D_METHOD("response_remove_cookie_simple", "key"), &WebServerRequest::response_remove_cookie_simple);
ClassDB::bind_method(D_METHOD("custom_response_header_set", "key", "value"), &WebServerRequest::custom_response_header_set);
ClassDB::bind_method(D_METHOD("custom_response_header_get", "key"), &WebServerRequest::custom_response_header_get);
ClassDB::bind_method(D_METHOD("custom_response_header_has", "key"), &WebServerRequest::custom_response_header_has);
ClassDB::bind_method(D_METHOD("custom_response_headers_get"), &WebServerRequest::custom_response_headers_get_bind);
ClassDB::bind_method(D_METHOD("get_content_type"), &WebServerRequest::get_content_type);
ClassDB::bind_method(D_METHOD("set_content_type", "content_type"), &WebServerRequest::set_content_type);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "content_type"), "set_content_type", "get_content_type");
ClassDB::bind_method(D_METHOD("get_method"), &WebServerRequest::get_method); ClassDB::bind_method(D_METHOD("get_method"), &WebServerRequest::get_method);
ClassDB::bind_method(D_METHOD("parse_files"), &WebServerRequest::parse_files); ClassDB::bind_method(D_METHOD("parse_files"), &WebServerRequest::parse_files);

View File

@ -4,6 +4,7 @@
#include "core/variant/dictionary.h" #include "core/variant/dictionary.h"
#include "core/string/ustring.h" #include "core/string/ustring.h"
#include "core/containers/vector.h" #include "core/containers/vector.h"
#include "core/containers/hash_map.h"
#include "core/object/object.h" #include "core/object/object.h"
#include "core/object/reference.h" #include "core/object/reference.h"
@ -67,6 +68,15 @@ public:
void response_remove_cookie(const int index); void response_remove_cookie(const int index);
void response_remove_cookie_simple(const String &key); void response_remove_cookie_simple(const String &key);
void custom_response_header_set(const StringName &key, const String& value);
String custom_response_header_get(const StringName &key);
bool custom_response_header_has(const StringName &key);
HashMap<StringName, String> custom_response_headers_get();
Dictionary custom_response_headers_get_bind();
String get_content_type();
void set_content_type(const String &content_type);
virtual HTTPServerEnums::HTTPMethod get_method() const; virtual HTTPServerEnums::HTTPMethod get_method() const;
virtual void parse_files(); virtual void parse_files();
@ -143,6 +153,8 @@ protected:
int _path_stack_pointer; int _path_stack_pointer;
Vector<Ref<WebServerCookie>> _cookies; Vector<Ref<WebServerCookie>> _cookies;
HashMap<StringName, String> _custom_response_headers;
Ref<WebPermission> _active_permission; Ref<WebPermission> _active_permission;
int _permissions; int _permissions;