Browse Source

Merge pull request #79846 from Faless/web/no_body_length

[Web] Always return -1 as body length in HTTPClientWeb
Yuri Sizov 2 years ago
parent
commit
bec47cdbbc

+ 1 - 0
doc/classes/HTTPClient.xml

@@ -41,6 +41,7 @@
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="get_response_code" qualifiers="const">

+ 9 - 1
platform/web/http_client_web.cpp

@@ -149,7 +149,15 @@ Error HTTPClientWeb::get_response_headers(List<String> *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() {

+ 0 - 1
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);
 

+ 0 - 15
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);