I have a case of where
window.open
Then the return value of window.open
is null
, even though the tab opens successfully.
For example if
main.py
pip install fastapi
uvicorn main:app --reload --port 8000
and uvicorn main:app --reload --port 8001
Then a new tab opens showing the Google home page, but I'll see null
in the console on the original tab.
from typing import Union
from fastapi import FastAPI, Response
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
def read_root(response: Response):
response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
return '''
<iframe src="http://localhost:8001/iframe"></iframe>
'''
@app.get("/iframe", response_class=HTMLResponse)
def read_iframe(response: Response):
response.headers["Cross-Origin-Opener-Policy"] = "same-origin"
return '''
<button id="button">Open</button>
<script>
document.getElementById("button").addEventListener("click", () => {
const w = window.open('https://www.google.com/', "_blank");
console.log(w);
});
</script>
'''
However if I visit the iframe directly by going to http://localhost:8001/iframe
and do the same thing, I see what seems to be a Window(/Window proxy?) object in the console.
Or: if I make the iframe be on the same domain as the parent page, I'll also see a Window/Window proxy object in the console.
Or: if I change same-origin
to same-origin-allow-popups
, I'll also see a Window/Window proxy object in the console.
Why in the case of a cross origin iframe with Cross-Origin-Opener-Policy set to same-origin does window.open
return null
? At https://developer.mozilla.org/en-US/docs/Web/API/Window/open it says
null is returned if the browser fails to open the new browsing context, for example because it was blocked by a browser popup blocker.
But it did open the browsing context...
The reasons why I want to understand: I have a similar setup on a site, and I'm deciding between Cross-Origin-Opener-Policy: same-site
and Cross-Origin-Opener-Policy: same-site-allow-popups
. So, I need to understand what it does. However, window.open's behaviour. depending on whether it's in a cross domain iframe or not is slightly thwarting that understanding
Why in the case of a cross origin iframe with Cross-Origin-Opener-Policy set to same-origin does window.open return null?
It's in the spec. In this exact situation it makes window.open
behave as though you passed noopener
to it, which in turn makes window.open return null.
In more detail, from The rules for choosing a navigable
- If currentDocument's cross-origin opener policy's value is "same-origin" or "same-origin-plus-COEP", and currentDocument's origin is not same origin with currentDocument's relevant settings object's top-level origin, then:
- Set noopener to true.
- Set name to "_blank".
- Set windowType to "new with no opener".
and then from 7.2.2.1 Opening and closing windows, when it's describing what window.open does
- If noopener is true or windowType is "new with no opener", then return null.
You can also see how window.open
behaves with noopener
- with no COOP and no iframe involved - it returns null just as in the case of this question.
from typing import Union
from fastapi import FastAPI, Response
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
def read_root(response: Response):
return '''
<button id="button">Open</button>
<script>
document.getElementById("button").addEventListener("click", () => {
const w = window.open('https://www.google.com/', "_blank", "noopener");
console.log(w);
});
</script>
'''