From f4713d235a498ee7805e8bd39273622e363059d0 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 24 Jul 2023 08:32:44 +0200 Subject: [PATCH] [Web] Always return -1 as body length in HTTPClientWeb. Body length cannot be reliably retrieved from the web. Reading the "content-length" value will return a meaningless value when the response is compressed, as reading will return uncompressed chunks in any case, resulting in a mismatch between the detected body size and the actual size returned by repeatedly calling read_response_body_chunk. Additionally, while "content-length" is considered a safe CORS header, "content-encoding" is not, so using the "content-encoding" to decide if "content-length" is meaningful is not an option either. We simply must accept the fact that browsers are awful when it comes to networking APIs. --- doc/classes/HTTPClient.xml | 1 + platform/web/http_client_web.cpp | 10 +++++++++- platform/web/http_client_web.h | 1 - platform/web/js/libs/library_godot_fetch.js | 15 --------------- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml index 9a8207d1fcd..f0385a78148 100644 --- a/doc/classes/HTTPClient.xml +++ b/doc/classes/HTTPClient.xml @@ -41,6 +41,7 @@ Returns the response's body length. [b]Note:[/b] Some Web servers may not send a body length. In this case, the value returned will be [code]-1[/code]. If using chunked transfer encoding, the body length will also be [code]-1[/code]. + [b]Note:[/b] This function always returns [code]-1[/code] on the Web platform due to browsers limitations. diff --git a/platform/web/http_client_web.cpp b/platform/web/http_client_web.cpp index 3e4ba5a2ae1..ea9226a5a48 100644 --- a/platform/web/http_client_web.cpp +++ b/platform/web/http_client_web.cpp @@ -149,7 +149,15 @@ Error HTTPClientWeb::get_response_headers(List *r_response) { } int64_t HTTPClientWeb::get_response_body_length() const { - return godot_js_fetch_body_length_get(js_id); + // Body length cannot be consistently retrieved from the web. + // Reading the "content-length" value will return a meaningless value when the response is compressed, + // as reading will return uncompressed chunks in any case, resulting in a mismatch between the detected + // body size and the actual size returned by repeatedly calling read_response_body_chunk. + // Additionally, while "content-length" is considered a safe CORS header, "content-encoding" is not, + // so using the "content-encoding" to decide if "content-length" is meaningful is not an option either. + // We simply must accept the fact that browsers are awful when it comes to networking APIs. + // See GH-47597, and GH-79327. + return -1; } PackedByteArray HTTPClientWeb::read_response_body_chunk() { diff --git a/platform/web/http_client_web.h b/platform/web/http_client_web.h index bb9672ab82e..4d3c457a7d0 100644 --- a/platform/web/http_client_web.h +++ b/platform/web/http_client_web.h @@ -51,7 +51,6 @@ extern int godot_js_fetch_read_headers(int p_id, void (*parse_callback)(int p_si extern int godot_js_fetch_read_chunk(int p_id, uint8_t *p_buf, int p_buf_size); extern void godot_js_fetch_free(int p_id); extern godot_js_fetch_state_t godot_js_fetch_state_get(int p_id); -extern int godot_js_fetch_body_length_get(int p_id); extern int godot_js_fetch_http_status_get(int p_id); extern int godot_js_fetch_is_chunked(int p_id); diff --git a/platform/web/js/libs/library_godot_fetch.js b/platform/web/js/libs/library_godot_fetch.js index 1bb48bfd6a3..4ef24903e38 100644 --- a/platform/web/js/libs/library_godot_fetch.js +++ b/platform/web/js/libs/library_godot_fetch.js @@ -50,22 +50,17 @@ const GodotFetch = { return; } let chunked = false; - let bodySize = -1; response.headers.forEach(function (value, header) { const v = value.toLowerCase().trim(); const h = header.toLowerCase().trim(); if (h === 'transfer-encoding' && v === 'chunked') { chunked = true; } - if (h === 'content-length') { - bodySize = parseInt(v, 10); - } }); obj.status = response.status; obj.response = response; obj.reader = response.body.getReader(); obj.chunked = chunked; - obj.bodySize = bodySize; }, onerror: function (id, err) { @@ -87,7 +82,6 @@ const GodotFetch = { reading: false, status: 0, chunks: [], - bodySize: -1, }; const id = IDHandler.add(obj); const init = { @@ -224,15 +218,6 @@ const GodotFetch = { return p_buf_size - to_read; }, - godot_js_fetch_body_length_get__sig: 'ii', - godot_js_fetch_body_length_get: function (p_id) { - const obj = IDHandler.get(p_id); - if (!obj || !obj.response) { - return -1; - } - return obj.bodySize; - }, - godot_js_fetch_is_chunked__sig: 'ii', godot_js_fetch_is_chunked: function (p_id) { const obj = IDHandler.get(p_id);