Input on Web Network APIs from Game Developer perspectives

Hello,

Back in February, we had a joint meeting with the Games Community Group 
[1]; one of the outcomes of that conversation was feedback from one of 
the CG participant, Fabio Alessandrelli from Godot Engine, on the 
limitations of the capabilities provided by network API in Web browsers.

Fabio very kindly agreed to compile that feedback, which he now has done in:
 
https://docs.google.com/document/d/1kBaHZCkRd3lUiVW3xRWfGnLX4IdN9JtLww_IHPNA2QM/edit#heading=h.tcfuqee8mzcv

(also copied below for posterity)

It would be useful if our group could take the lead on figuring if and 
how some of these gaps could be fixed.

Dom

1. https://www.w3.org/events/meetings/43010bf1-547f-4c0d-b61b-cadeaca4b475

#### text copy of 
https://docs.google.com/document/d/1kBaHZCkRd3lUiVW3xRWfGnLX4IdN9JtLww_IHPNA2QM/edit#

Fetch
---

In general, fetch is much stricter than regular platform APIs, being 
subjected to CORS restrictions, but the main limitation we face is the 
impossibility to gather download progress information in the many 
scenarios where it would otherwise be possible.

Download Progress

In a native platform, you would be able to read the "Content-Length" 
header (often available) and count the bytes as you receive them.

With fetch, this is not possible whenever the response is compressed 
because the streaming API automatically decompresses it, and does not 
provide information about the number of compressed bytes processed.

Originally, we tried to support download progress detection when 
"Content-Encoding" was not set so we knew the response was not compressed.
That resulted in bugs during CORS requests due to "Content-Length" being 
added to the headers safelist but not "Content-Encoding", so we ended up 
removing it completely in the Web export (since non-compressed responses 
are rare anyway).

Currently, to have a progress bar of the download using fetch during 
engine start, we hard-code file sizes in the exported HTML, which is of 
course not a viable option for dynamic resources and quite a burden in 
terms of usability and potential optimizations during read.

I'm unsure what is the best way to solve it, and I suppose it depends on 
the level of abstraction that fetch wants to provide, and doing some 
research I found two related issues: 
https://github.com/whatwg/fetch/issues/1358 and 
https://github.com/whatwg/fetch/issues/607.

I would advocate for a much simpler solution and expose 
"Response.contentLength" (null when unavailable) and 
"Response.contentReceived" (body bytes received).

Those 2 properties could also allow better estimates of the amount of 
bytes transferred over the wire if it was possible to know when a cached 
response was returned.

Which also as far as I know is not possible to detect as of now.
I found a "cache state" mentioned in the living standard, but it seems 
mostly related to the "Resource Timing API" and found no trace of 
something similar in browser implementations, so maybe I'm missing 
something here.

CORS and credentials

Fetch cannot make authenticated CORS requests without explicitly setting 
the "credentials: 'include'" option, but that results in a rejected 
promise when "Access-Control-Allow-Origin: *" ( 
https://fetch.spec.whatwg.org/#cors-protocol-and-credentials ), which we 
cannot check since we cannot (AFAIK) make CORS preflight requests with 
`fetch` itself (i.e. OPTIONS "fetch" are themselves subjects to CORS).

We also had multiple requests from users asking to allow setting custom 
credentials (e.g. making a REST client which exchanges tokens), but 
since `Authorization` is a reserved header, that is also not currently 
possible (and people dangerously hack around it using query parameters 
instead).
I believe this is somehow by design, but I also think this design 
hinders both the usability of the web as a platform, and contrary to 
what it might seem, even security (people hack around it, authentication 
query parameters get logged/stored by proxies or the browser itself).

WebSocket
---

WebSocket is a really solid standard, one very surprising limitation of 
the browser API is it doesn't allow setting extra handshake headers.
Doing so is supported by many native implementation due to high user 
demand, here is a link to our own issue about that:
https://github.com/godotengine/godot/issues/27129

But a quick online search for "websocket custom headers" shows how much 
there's demand for that.

This can of course be circumvented using request query parameters and 
this is how it's done right now in most implementations when targeting 
the Web platform, but it makes both server processing and proxy 
filtering harder, more error prone (again, logging/storing issue for 
query parameters), and more costly in terms of resources.

I am not sure there is a good reason for not supporting them, beside 
requiring an API change to the constructor, they could be subject to 
usual header restrictions ( 
https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name 
) or even limiting them to `X-*` headers would be an improvement, but 
again, the headers restrictions seem to cause more troubles than the 
potential issues they solve.

Received on Tuesday, 31 May 2022 07:07:04 UTC