godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.79k stars 21.13k forks source link

SharedArrayBuffer & Cross Origin Isolation For HTML5 Not Widely Implemented #69020

Closed ghost closed 1 year ago

ghost commented 1 year ago

Godot version

v4.0.beta5.official [89a33d28f]

System information

NA

Issue description

Hi,

SharedArrayBuffer & Cross Origin Isolation in the HTML5 build is not widely implemented. We think you should offer developers the option to disable both requirements in HTML5 builds. If this could be done in Beta 6 then that would be fine.

Jesse

Steps to reproduce

NA

Minimal reproduction project

NA

akien-mga commented 1 year ago

That's not possible.

Godot 4 is a multi-threaded engine, and multi-threading in WebAssembly requires SharedArrayBuffer support.

SharedArrayBuffer is now supported by all major browsers: https://caniuse.com/sharedarraybuffer

It's only hosting platforms such as itch.io which do not provide a good way to configure Cross Origin Isolation, but that's an ecosystem problem that hosting platforms will have to solve.

Xananax commented 1 year ago

A quick review of the ways to set the right headers. (I know the issue is closed, but this is what pops up when people search for the issue)

Edit: This gist has up to date and comprehensive info https://gist.github.com/nisovin/cf9dd74678641fb70902866c79692b17

More tips & tricks at https://github.com/godotengine/godot-proposals/issues/6616

For local testing

Of course, you can just run the game from Godot (little "html5" icon).

But in case you need something custom and have npm installed, this is easy and painless:

npx local-web-server \
  --https \
  --cors.embedder-policy "require-corp"\
  --cors.opener-policy "same-origin" \
  --directory <my-game-dir>

Own Webserver

You need to have a certificate (use https). Then;

if you use Nginx:

location some-location {
  add_header "Cross-Origin-Opener-Policy" "same-origin";
  add_header "Cross-Origin-Embedder-Policy" "require-corp";     
}

If you use Express:

app.use(function(req, res, next) {
  res.header("Cross-Origin-Embedder-Policy", "require-corp");
  res.header("Cross-Origin-Opener-Policy", "same-origin");
  next();
});

If you use Python: see the next comment

External Providers

(if you have info for more providers, tell me and I'll add them)

Client/Worker solution

People point at https://github.com/gzuidhof/coi-serviceworker

This may be a universal solution. I tested it locally and it worked perfectly fine. The trade off is that the page has to reload once.

What does this mean?

Those headers restrict your page's access, making it highly sandboxed. This unlocks ShareArrayBuffers. Browsers don't give you access to this feature by default because it is easily exploitable.

When you have those headers, you will not be able to request any external resources to your domain. If you want to load a youtube video or some 3rd party javascript, the browser will block it.

But you only need those headers for the page hosting the Godot game. That page can be set in an iframe on another page with less stringent sandboxing requirements.

pijamarda commented 1 year ago

Hi!
If you are using python3 to run a local server for testing you can also use this:
Create a file called server.py with the following code

import http.server
import socketserver

PORT = 8000

class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
        self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
        super().end_headers()

Handler = MyHTTPRequestHandler

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print(f"Serving at port {PORT}")
    httpd.serve_forever()

Then run python3 server.py

brice-noowu commented 1 year ago

@Xananax

But you only need those headers for the page hosting the Godot game. That page can be set in an iframe on another page with less stringent sandboxing requirements.

That's my usecase ! Could you expand a little what you meant by that ?

I managed to host my game on a simple Firebase Hosting, on which I added the proper headers. You can see it working here : https://godot-games-24c5d.web.app/game/game.html

Now I have a separate singlepage application, on which I would like to embed this game via an iframe, but when I add : <iframe src="https://godot-games-24c5d.web.app/game/game.html" frameborder="0"></iframe>.

I get the famous Error The following features required to run Godot projects on the Web are missing: Cross Origin Isolation - Check web server configuration (send correct headers) SharedArrayBuffer - Check web server configuration (send correct headers)

And I can't set the same headers to my singlepage app (the one containing the iframe) because it causes so many problems (with images, external scripts etc).

Sorry if it's not the place to discuss this, but I could really need a hand here !

Bonus : my game uses JavaScriptBridgeto send message via postMessageto the iframe parent, (so I can react to some in-game events from the singlepage app that have the iframe). Will this work ?

Xananax commented 1 year ago

You would need to set custom headers firebase-side on the URL that serves your game, and for the page that hosts the iframe.

Something like:

{
  "hosting": {
    "headers": [
      {
        "source": "**/game/game.html",
        "headers": [
          { "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" },
          {
            "key": "Cross-Origin-Opener-Policy",
            "value": "same-origin"
          }
        ]
      },
      {
        "source": "**/game/index.html",
        "headers": [
          { "key": "Cross-Origin-Embedder-Policy", "value": "credentialless" },
          {
            "key": "Cross-Origin-Opener-Policy",
            "value": "same-origin"
          }
        ]
      }
    ]
  }
}

I'm not sure, I don't use Firebase.

Note that this does restrict even the containing page somewhat. For example, Youtube videos won't embed. Also note that this is brittle (only works in latest Firefox; doesn't work in Safari (and they don't seem to intend to implement it)).

I have no idea if postMessage works under those conditions, and if does in all browsers.

Additionally, you will need to add the following allow attribute to your iframe:

<iframe allow="cross-origin-isolated"></iframe>

Good luck!

oliversitan commented 1 year ago

Hi! If you are using python3 to run a local server for testing you can also use this: Create a file called server.py with the following code

import http.server
import socketserver

PORT = 8000

class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
        self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
        super().end_headers()

Handler = MyHTTPRequestHandler

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print(f"Serving at port {PORT}")
    httpd.serve_forever()

Then run python3 server.py

py server.py or python server.py depending on python installation and SO

refeals commented 1 year ago

For netlify, create a _headers file and add the following:

/*
  Cross-Origin-Opener-Policy: same-origin
  Cross-Origin-Embedder-Policy: require-corp

Had to use this page and the official docs for this. Official docs: https://docs.netlify.com/routing/headers/

golopogus commented 1 year ago

@brice-noowu

I've been struggling to make my godot game run on firebase just as you have it. I'm getting the same error.

Error The following features required to run Godot projects on the Web are missing: Cross Origin Isolation - Check web server configuration (send correct headers) SharedArrayBuffer - Check web server configuration (send correct headers)

But it seems you have been able to make it work. I've added what I thought were the appropriate headers, but nothing seems to work.

teiman commented 10 months ago

With Apache, you can upload a .htaccess file with the content:

Header add Cross-Origin-Opener-Policy: "same-origin"
Header add Cross-Origin-Embedder-Policy: "require-corp"
lubien commented 9 months ago

External Providers

*

if anyone here stumble on this issue like I just did, Ive figured how to do a Caddyfile deploy so I could host on Fly.io

https://community.fly.io/t/deploy-godot-web-to-fly-io-fast-booting-vms/17686

You just need a Caddyfile like this:

:8080

root * /path/to/html/files

header * {
    Cross-Origin-Embedder-Policy require-corp
    Cross-Origin-Opener-Policy same-origin
    Access-Control-Allow-Origin "*"
}
file_server

And a place to run it. Cheers

teiman commented 9 months ago

If you are using iframes, you might also need to add cross-origin-isolated to the allow attribute of the iframe html.

allow="autoplay; fullscreen *; geolocation; microphone; camera; midi; monetization; xr-spatial-tracking; gamepad; gyroscope; accelerometer; xr; cross-origin-isolated"

So you would have the server headers in the host html page, and the iframe html page. And this hint in the allow attribute of the iframe.

FartFish commented 5 months ago

https://github.com/godotengine/godot/issues/69020#issuecomment-1324253401

It's only hosting platforms such as itch.io which do not provide a good way to configure Cross Origin Isolation, but that's an ecosystem problem that hosting platforms will have to solve.

The only issue here is, many hosting platforms can't solve this issue.

As an example, from my own discussions with employees of Cool Math Games and Armor Games, websites that use advertisements are unable to enable COI without interfering with their advertisement software, as this software is generally incompatible with COI.

This means that, without a reliable method of migrating a project from Godot 4 to Godot 3, developers would need to entirely remake a game in Godot 3 in order to contract with web-hosting services that show advertisements. While it is certainly an ecosystem problem, I do not believe that this means we should ignore the issue entirely, as it does potentially adversely affect developers hoping to contract with certain web-hosting services.

akien-mga commented 5 months ago

See https://godotengine.org/article/progress-report-web-export-in-4-3/

Godot 4.3 brings back support for single threaded mode (no need for SharedArrayBuffer or COI).

RichardJECooke commented 5 months ago

@akien-mga , I exported the Godot starter project from the docs for web, then ran npx http-server --cors to play it, but I get the browser error:

The following features required to run Godot projects on the Web are missing:
Cross Origin Isolation - Check web server configuration (send correct headers)
SharedArrayBuffer - Check web server configuration (send correct headers)

On the page you link to it says there should be a thread support box to disable, but I don't see it. I have the latest version of Godot from the website, but it is 4.2, I cannot find 4.3.

I'm new to Godot, reading the tutorial. Is Godot not working on web yet? Or is there a way to fix this. Thank you.

refeals commented 5 months ago

@RichardJECooke Godot 4.3 isn't officially out yet. Should be out pretty soon though. Check out the latest blog posts in https://godotengine.org. Alternatively you can try compiling it yourself, but I do recommend waiting a bit longer on this one.

Godot does work on web, but there are a few limitations, mostly addressed in the article mentioned by @akien-mga.