summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/dictionary.cpp26
-rw-r--r--core/dictionary.h2
-rw-r--r--core/io/http_client.cpp64
-rw-r--r--core/io/http_client.h1
-rw-r--r--core/project_settings.cpp1
-rw-r--r--core/script_debugger_remote.cpp4
-rw-r--r--core/script_language.cpp2
-rw-r--r--core/script_language.h2
-rw-r--r--core/ustring.cpp40
-rw-r--r--core/ustring.h1
-rw-r--r--core/variant_call.cpp2
11 files changed, 128 insertions, 17 deletions
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index ba0de95861..d68411a572 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -50,6 +50,32 @@ void Dictionary::get_key_list(List<Variant> *p_keys) const {
}
}
+Variant Dictionary::get_key_at_index(int p_index) const {
+
+ int index = 0;
+ for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ if (index == p_index) {
+ return E.key();
+ }
+ index++;
+ }
+
+ return Variant();
+}
+
+Variant Dictionary::get_value_at_index(int p_index) const {
+
+ int index = 0;
+ for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ if (index == p_index) {
+ return E.value();
+ }
+ index++;
+ }
+
+ return Variant();
+}
+
Variant &Dictionary::operator[](const Variant &p_key) {
return _p->variant_map[p_key];
diff --git a/core/dictionary.h b/core/dictionary.h
index 9eef265d5b..84a5cafe1d 100644
--- a/core/dictionary.h
+++ b/core/dictionary.h
@@ -47,6 +47,8 @@ class Dictionary {
public:
void get_key_list(List<Variant> *p_keys) const;
+ Variant get_key_at_index(int p_index) const;
+ Variant get_value_at_index(int p_index) const;
Variant &operator[](const Variant &p_key);
const Variant &operator[](const Variant &p_key) const;
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 9e301ccac5..8d85e78226 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -248,6 +248,7 @@ void HTTPClient::close() {
body_size = 0;
body_left = 0;
chunk_left = 0;
+ read_until_eof = false;
response_num = 0;
}
@@ -352,10 +353,17 @@ Error HTTPClient::poll() {
chunked = false;
body_left = 0;
chunk_left = 0;
+ read_until_eof = false;
response_str.clear();
response_headers.clear();
response_num = RESPONSE_OK;
+ // Per the HTTP 1.1 spec, keep-alive is the default, but in practice
+ // it's safe to assume it only if the explicit header is found, allowing
+ // to handle body-up-to-EOF responses on naive servers; that's what Curl
+ // and browsers do
+ bool keep_alive = false;
+
for (int i = 0; i < responses.size(); i++) {
String header = responses[i].strip_edges();
@@ -365,13 +373,14 @@ Error HTTPClient::poll() {
if (s.begins_with("content-length:")) {
body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int();
body_left = body_size;
- }
- if (s.begins_with("transfer-encoding:")) {
+ } else if (s.begins_with("transfer-encoding:")) {
String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges();
if (encoding == "chunked") {
chunked = true;
}
+ } else if (s.begins_with("connection: keep-alive")) {
+ keep_alive = true;
}
if (i == 0 && responses[i].begins_with("HTTP")) {
@@ -384,11 +393,16 @@ Error HTTPClient::poll() {
}
}
- if (body_size == 0 && !chunked) {
+ if (body_size || chunked) {
- status = STATUS_CONNECTED; // Ready for new requests
- } else {
status = STATUS_BODY;
+ } else if (!keep_alive) {
+
+ read_until_eof = true;
+ status = STATUS_BODY;
+ } else {
+
+ status = STATUS_CONNECTED;
}
return OK;
}
@@ -515,34 +529,53 @@ PoolByteArray HTTPClient::read_response_body_chunk() {
} else {
- int to_read = MIN(body_left, read_chunk_size);
+ int to_read = !read_until_eof ? MIN(body_left, read_chunk_size) : read_chunk_size;
PoolByteArray ret;
ret.resize(to_read);
int _offset = 0;
- while (to_read > 0) {
+ while (read_until_eof || to_read > 0) {
int rec = 0;
{
PoolByteArray::Write w = ret.write();
err = _get_http_data(w.ptr() + _offset, to_read, rec);
}
- if (rec > 0) {
- body_left -= rec;
- to_read -= rec;
- _offset += rec;
- } else {
+ if (rec < 0) {
if (to_read > 0) // Ended up reading less
ret.resize(_offset);
break;
+ } else {
+ _offset += rec;
+ if (!read_until_eof) {
+ body_left -= rec;
+ to_read -= rec;
+ } else {
+ if (rec < to_read) {
+ ret.resize(_offset);
+ err = ERR_FILE_EOF;
+ break;
+ }
+ ret.resize(_offset + to_read);
+ }
}
}
- if (body_left == 0) {
- status = STATUS_CONNECTED;
+ if (!read_until_eof) {
+ if (body_left == 0) {
+ status = STATUS_CONNECTED;
+ }
+ return ret;
+ } else {
+ if (err == ERR_FILE_EOF) {
+ err = OK; // EOF is expected here
+ close();
+ return ret;
+ }
}
- return ret;
}
if (err != OK) {
+
close();
+
if (err == ERR_FILE_EOF) {
status = STATUS_DISCONNECTED; // Server disconnected
@@ -602,6 +635,7 @@ HTTPClient::HTTPClient() {
body_size = 0;
chunked = false;
body_left = 0;
+ read_until_eof = false;
chunk_left = 0;
response_num = 0;
ssl = false;
diff --git a/core/io/http_client.h b/core/io/http_client.h
index 839012e701..38ec82ce8c 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -173,6 +173,7 @@ private:
int chunk_left;
int body_size;
int body_left;
+ bool read_until_eof;
Ref<StreamPeerTCP> tcp_connection;
Ref<StreamPeer> connection;
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index ac4a4b7d15..ef485cb3b2 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -1071,6 +1071,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_mode", 2);
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
+ GLOBAL_DEF("debug/settings/performance/update_frequency_msec", 250);
//assigning here, because using GLOBAL_GET on every block for compressing can be slow
Compression::zstd_long_distance_matching = GLOBAL_DEF("compression/formats/zstd/long_distance_matching", false);
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp
index 75bcedbbc8..7a30a33c67 100644
--- a/core/script_debugger_remote.cpp
+++ b/core/script_debugger_remote.cpp
@@ -854,7 +854,7 @@ void ScriptDebuggerRemote::idle_poll() {
if (performance) {
uint64_t pt = OS::get_singleton()->get_ticks_msec();
- if (pt - last_perf_time > 1000) {
+ if (pt - last_perf_time > update_frequency) {
last_perf_time = pt;
int max = performance->get("MONITOR_MAX");
@@ -1081,7 +1081,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() :
eh.userdata = this;
add_error_handler(&eh);
- profile_info.resize(CLAMP(int(ProjectSettings::get_singleton()->get("debug/settings/profiler/max_functions")), 128, 65535));
+ profile_info.resize(CLAMP(int(GLOBAL_GET("debug/settings/profiler/max_functions")), 128, 65535));
profile_info_ptrs.resize(profile_info.size());
}
diff --git a/core/script_language.cpp b/core/script_language.cpp
index 1dab58e29e..ce9b138bb2 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "script_language.h"
+#include "project_settings.h"
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
int ScriptServer::_language_count = 0;
@@ -283,6 +284,7 @@ ScriptDebugger::ScriptDebugger() {
lines_left = -1;
depth = -1;
break_lang = NULL;
+ update_frequency = GLOBAL_GET("debug/settings/performance/update_frequency_msec");
}
bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) {
diff --git a/core/script_language.h b/core/script_language.h
index b4c55cac9e..64c6f2eb81 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -352,6 +352,8 @@ class ScriptDebugger {
public:
typedef void (*RequestSceneTreeMessageFunc)(void *);
+ int update_frequency;
+
struct LiveEditFuncs {
void *udata;
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 85b7a16e6a..51f05468e2 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -753,6 +753,46 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p
return ret;
}
+Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int p_maxsplit) const {
+
+ Vector<String> ret;
+ const int len = length();
+ int from = len;
+
+ while (true) {
+
+ int end = rfind(p_splitter, from);
+ if (end < 0)
+ end = 0;
+
+ if (p_allow_empty || (end < from)) {
+ const String str = substr(end > 0 ? end + p_splitter.length() : end, end > 0 ? from - end : from + 2);
+
+ if (p_maxsplit <= 0) {
+ ret.push_back(str);
+ } else if (p_maxsplit > 0) {
+
+ // Put rest of the string and leave cycle.
+ if (p_maxsplit == ret.size()) {
+ ret.push_back(substr(0, from + 2));
+ break;
+ }
+
+ // Otherwise, push items until positive limit is reached.
+ ret.push_back(str);
+ }
+ }
+
+ if (end == 0)
+ break;
+
+ from = end - p_splitter.length();
+ }
+
+ ret.invert();
+ return ret;
+}
+
Vector<float> String::split_floats(const String &p_splitter, bool p_allow_empty) const {
Vector<float> ret;
diff --git a/core/ustring.h b/core/ustring.h
index 1ed694bb80..b57e9629d9 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -172,6 +172,7 @@ public:
String get_slicec(CharType p_splitter, int p_slice) const;
Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> split_spaces() const;
Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 4e883d496f..4158c2a60e 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -257,6 +257,7 @@ struct _VariantCall {
VCALL_LOCALMEM2R(String, insert);
VCALL_LOCALMEM0R(String, capitalize);
VCALL_LOCALMEM3R(String, split);
+ VCALL_LOCALMEM3R(String, rsplit);
VCALL_LOCALMEM2R(String, split_floats);
VCALL_LOCALMEM0R(String, to_upper);
VCALL_LOCALMEM0R(String, to_lower);
@@ -1469,6 +1470,7 @@ void register_variant_methods() {
ADDFUNC2R(STRING, STRING, String, insert, INT, "position", STRING, "what", varray());
ADDFUNC0R(STRING, STRING, String, capitalize, varray());
ADDFUNC3R(STRING, POOL_STRING_ARRAY, String, split, STRING, "divisor", BOOL, "allow_empty", INT, "maxsplit", varray(true, 0));
+ ADDFUNC3R(STRING, POOL_STRING_ARRAY, String, rsplit, STRING, "divisor", BOOL, "allow_empty", INT, "maxsplit", varray(true, 0));
ADDFUNC2R(STRING, POOL_REAL_ARRAY, String, split_floats, STRING, "divisor", BOOL, "allow_empty", varray(true));
ADDFUNC0R(STRING, STRING, String, to_upper, varray());