From 9ea4452d2118fb071066cce1e2e2525bc4e29841 Mon Sep 17 00:00:00 2001 From: Leon Krause Date: Fri, 16 Feb 2018 05:11:25 +0100 Subject: [PATCH 1/5] Fix HTML5 HTTPClient failure detection --- platform/javascript/http_client_javascript.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp index 1cd27197230..badfe40e664 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/javascript/http_client_javascript.cpp @@ -239,15 +239,11 @@ Error HTTPClient::poll() { case STATUS_REQUESTING: polled_response_code = godot_xhr_get_status(xhr_id); - int response_length = godot_xhr_get_response_length(xhr_id); - if (response_length == 0) { - godot_xhr_ready_state_t ready_state = godot_xhr_get_ready_state(xhr_id); - if (ready_state == XHR_READY_STATE_HEADERS_RECEIVED || ready_state == XHR_READY_STATE_LOADING) { - return OK; - } else { - status = STATUS_CONNECTION_ERROR; - return ERR_CONNECTION_ERROR; - } + if (godot_xhr_get_ready_state(xhr_id) != XHR_READY_STATE_DONE) { + return OK; + } else if (!polled_response_code) { + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; } status = STATUS_BODY; @@ -263,9 +259,9 @@ Error HTTPClient::poll() { polled_response_header = String::utf8(reinterpret_cast(read.ptr())); read = PoolByteArray::Read(); - polled_response.resize(response_length); + polled_response.resize(godot_xhr_get_response_length(xhr_id)); write = polled_response.write(); - godot_xhr_get_response(xhr_id, write.ptr(), response_length); + godot_xhr_get_response(xhr_id, write.ptr(), polled_response.size()); write = PoolByteArray::Write(); break; } From 8a21f27f540750a76f19fcfb7d7a9d5e7f03f771 Mon Sep 17 00:00:00 2001 From: Leon Krause Date: Fri, 16 Feb 2018 05:38:36 +0100 Subject: [PATCH 2/5] Fix HTML5 HTTPClient response header retrieval --- platform/javascript/http_client_javascript.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp index badfe40e664..5e6b01f772a 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/javascript/http_client_javascript.cpp @@ -158,7 +158,7 @@ int HTTPClient::get_response_code() const { Error HTTPClient::get_response_headers(List *r_response) { - if (!polled_response_header.size()) + if (polled_response_header.empty()) return ERR_INVALID_PARAMETER; Vector header_lines = polled_response_header.split("\r\n", false); @@ -250,9 +250,11 @@ Error HTTPClient::poll() { PoolByteArray bytes; int len = godot_xhr_get_response_headers_length(xhr_id); - bytes.resize(len); + bytes.resize(len + 1); + PoolByteArray::Write write = bytes.write(); godot_xhr_get_response_headers(xhr_id, reinterpret_cast(write.ptr()), len); + write[len] = 0; write = PoolByteArray::Write(); PoolByteArray::Read read = bytes.read(); From 2cd7bc04ea9a99510c26113a81f8371be5b1f49f Mon Sep 17 00:00:00 2001 From: Leon Krause Date: Sat, 17 Feb 2018 16:56:40 +0100 Subject: [PATCH 3/5] Disable insecure HTTP methods CONNECT and TRACE in HTML5 platform --- platform/javascript/http_client_javascript.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp index 5e6b01f772a..5ab3d1b7703 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/javascript/http_client_javascript.cpp @@ -81,6 +81,8 @@ Ref HTTPClient::get_connection() const { Error HTTPClient::prepare_request(Method p_method, const String &p_url, const Vector &p_headers) { ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); + ERR_EXPLAIN("HTTP methods TRACE and CONNECT are not supported for the HTML5 platform"); + ERR_FAIL_COND_V(p_method == METHOD_TRACE || p_method == METHOD_CONNECT, ERR_UNAVAILABLE); ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(host.empty(), ERR_UNCONFIGURED); ERR_FAIL_COND_V(port < 0, ERR_UNCONFIGURED); From ca9fa9cca8a27f14a7b0178d6abf573815722996 Mon Sep 17 00:00:00 2001 From: Leon Krause Date: Sat, 17 Feb 2018 17:42:58 +0100 Subject: [PATCH 4/5] Warn when polling HTTPClient synchronously in HTML5 platform --- platform/javascript/http_client.h.inc | 5 +++++ .../javascript/http_client_javascript.cpp | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/platform/javascript/http_client.h.inc b/platform/javascript/http_client.h.inc index 23a74e68f55..d75d33a33ac 100644 --- a/platform/javascript/http_client.h.inc +++ b/platform/javascript/http_client.h.inc @@ -46,3 +46,8 @@ String password; int polled_response_code; String polled_response_header; PoolByteArray polled_response; + +#ifdef DEBUG_ENABLED +bool has_polled; +uint64_t last_polling_frame; +#endif diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp index 5ab3d1b7703..939a8d11f25 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/javascript/http_client_javascript.cpp @@ -240,6 +240,21 @@ Error HTTPClient::poll() { return ERR_CONNECTION_ERROR; case STATUS_REQUESTING: + +#ifdef DEBUG_ENABLED + if (!has_polled) { + has_polled = true; + } else { + // forcing synchronous requests is not possible on the web + if (last_polling_frame == Engine::get_singleton()->get_idle_frames()) { + WARN_PRINT("HTTPClient polled multiple times in one frame, " + "but request cannot progress more than once per " + "frame on the HTML5 platform."); + } + } + last_polling_frame = Engine::get_singleton()->get_idle_frames(); +#endif + polled_response_code = godot_xhr_get_status(xhr_id); if (godot_xhr_get_ready_state(xhr_id) != XHR_READY_STATE_DONE) { return OK; @@ -280,6 +295,10 @@ HTTPClient::HTTPClient() { port = -1; use_tls = false; polled_response_code = 0; +#ifdef DEBUG_ENABLED + has_polled = false; + last_polling_frame = 0; +#endif } HTTPClient::~HTTPClient() { From 98039909f202aac2795ead44104b56f7609059d8 Mon Sep 17 00:00:00 2001 From: Leon Krause Date: Sat, 17 Feb 2018 17:49:17 +0100 Subject: [PATCH 5/5] Flush HTTPClient response data only on request/close in HTML5 platform --- platform/javascript/http_client_javascript.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp index 939a8d11f25..118a77835e2 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/javascript/http_client_javascript.cpp @@ -193,8 +193,6 @@ PoolByteArray HTTPClient::read_response_body_chunk() { if (response_read_offset == polled_response.size()) { status = STATUS_CONNECTED; polled_response.resize(0); - polled_response_code = 0; - polled_response_header = String(); godot_xhr_reset(xhr_id); }