[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.
This commit is contained in:
parent
6588a4a29a
commit
f4713d235a
|
@ -41,6 +41,7 @@
|
||||||
<description>
|
<description>
|
||||||
Returns the response's body length.
|
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] 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>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="get_response_code" qualifiers="const">
|
<method name="get_response_code" qualifiers="const">
|
||||||
|
|
|
@ -149,7 +149,15 @@ Error HTTPClientWeb::get_response_headers(List<String> *r_response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t HTTPClientWeb::get_response_body_length() const {
|
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() {
|
PackedByteArray HTTPClientWeb::read_response_body_chunk() {
|
||||||
|
|
|
@ -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 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 void godot_js_fetch_free(int p_id);
|
||||||
extern godot_js_fetch_state_t godot_js_fetch_state_get(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_http_status_get(int p_id);
|
||||||
extern int godot_js_fetch_is_chunked(int p_id);
|
extern int godot_js_fetch_is_chunked(int p_id);
|
||||||
|
|
||||||
|
|
|
@ -50,22 +50,17 @@ const GodotFetch = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let chunked = false;
|
let chunked = false;
|
||||||
let bodySize = -1;
|
|
||||||
response.headers.forEach(function (value, header) {
|
response.headers.forEach(function (value, header) {
|
||||||
const v = value.toLowerCase().trim();
|
const v = value.toLowerCase().trim();
|
||||||
const h = header.toLowerCase().trim();
|
const h = header.toLowerCase().trim();
|
||||||
if (h === 'transfer-encoding' && v === 'chunked') {
|
if (h === 'transfer-encoding' && v === 'chunked') {
|
||||||
chunked = true;
|
chunked = true;
|
||||||
}
|
}
|
||||||
if (h === 'content-length') {
|
|
||||||
bodySize = parseInt(v, 10);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
obj.status = response.status;
|
obj.status = response.status;
|
||||||
obj.response = response;
|
obj.response = response;
|
||||||
obj.reader = response.body.getReader();
|
obj.reader = response.body.getReader();
|
||||||
obj.chunked = chunked;
|
obj.chunked = chunked;
|
||||||
obj.bodySize = bodySize;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onerror: function (id, err) {
|
onerror: function (id, err) {
|
||||||
|
@ -87,7 +82,6 @@ const GodotFetch = {
|
||||||
reading: false,
|
reading: false,
|
||||||
status: 0,
|
status: 0,
|
||||||
chunks: [],
|
chunks: [],
|
||||||
bodySize: -1,
|
|
||||||
};
|
};
|
||||||
const id = IDHandler.add(obj);
|
const id = IDHandler.add(obj);
|
||||||
const init = {
|
const init = {
|
||||||
|
@ -224,15 +218,6 @@ const GodotFetch = {
|
||||||
return p_buf_size - to_read;
|
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__sig: 'ii',
|
||||||
godot_js_fetch_is_chunked: function (p_id) {
|
godot_js_fetch_is_chunked: function (p_id) {
|
||||||
const obj = IDHandler.get(p_id);
|
const obj = IDHandler.get(p_id);
|
||||||
|
|
Loading…
Reference in New Issue