8000 [Worker support] test for no cors headers (#1374) · pyscript/pyscript@cd1aa94 · GitHub
[go: up one dir, main page]

Skip to content

Commit cd1aa94

Browse files
[Worker support] test for no cors headers (#1374)
* test for no cors headers * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix tests * suggested changes * disable directly * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add error message * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * improve test * improve error message * remove py-config tag from cors test --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 82613d0 commit cd1aa94

File tree

5 files changed

+92
-20
lines changed

5 files changed

+92
-20
lines changed

pyscriptjs/src/main.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,21 @@ export class PyScriptApp {
162162
);
163163
}
164164
this.config = loadConfigFromElement(el);
165+
if (this.config.execution_thread === 'worker' && crossOriginIsolated === false) {
166+
throw new UserError(
167+
ErrorCode.BAD_CONFIG,
168+
`When execution_thread is "worker", the site must be cross origin isolated, but crossOriginIsolated is false.
169+
To be cross origin isolated, the server must use https and also serve with the following headers: ${JSON.stringify(
170+
{
171+
'Cross-Origin-Embedder-Policy': 'require-corp',
172+
'Cross-Origin-Opener-Policy': 'same-origin',
173+
},
174+
)}.
175+
176+
The problem may be that one or both of these are missing.
177+
`,
178+
);
179+
}
165180
logger.info('config loaded:\n' + JSON.stringify(this.config, null, 2));
166181
}
167182

pyscriptjs/tests/integration/conftest.py

Lines changed: 21 additions & 6 deletions
8000
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,17 @@ def browser_type_launch_args(request):
123123
return launch_options
124124

125125

126-
class HTTPServer(SuperHTTPServer):
126+
class DevServer(SuperHTTPServer):
127127
"""
128128
Class for wrapper to run SimpleHTTPServer on Thread.
129129
Ctrl +Only Thread remains dead when terminated with C.
130130
Keyboard Interrupt passes.
131131
"""
132132

133+
def __init__(self, base_url, *args, **kwargs):
134+
self.base_url = base_url
135+
super().__init__(*args, **kwargs)
136+
133137
def run(self):
134138
try:
135139
self.serve_forever()
@@ -140,15 +144,26 @@ def run(self):
140144

141145

142146
@pytest.fixture(scope="session")
143-
def http_server(logger):
147+
def dev_server(logger):
144148
class MyHTTPRequestHandler(SimpleHTTPRequestHandler):
149+
enable_cors_headers = True
150+
151+
@classmethod
152+
def my_headers(cls):
153+
if cls.enable_cors_headers:
154+
return {
155+
"Cross-Origin-Embedder-Policy": "require-corp",
156+
"Cross-Origin-Opener-Policy": "same-origin",
157+
}
158+
return {}
159+
145160
def end_headers(self):
146161
self.send_my_headers()
147162
SimpleHTTPRequestHandler.end_headers(self)
148163

149164
def send_my_headers(self):
150-
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
151-
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
165+
for k, v in self.my_headers().items():
166+
self.send_header(k, v)
152167

153168
def log_message(self, fmt, *args):
154169
logger.log("http_server", fmt % args, color="blue")
@@ -157,12 +172,12 @@ def log_message(self, fmt, *args):
157172
base_url = f"http://{host}:{port}"
158173

159174
# serve_Run forever under thread
160-
server = HTTPServer((host, port), MyHTTPRequestHandler)
175+
server = DevServer(base_url, (host, port), MyHTTPRequestHandler)
161176

162177
thread = threading.Thread(None, server.run)
163178
thread.start()
164179

165-
yield base_url # Transition to test here
180+
yield server # Transition to test here
166181

167182
# End thread
168183
server.shutdown()

pyscriptjs/tests/integration/support.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -158,24 +158,24 @@ def init(self, request, tmpdir, logger, page, execution_thread):
158158
self.tmpdir.chdir()
159159
self.logger = logger
160160
self.execution_thread = execution_thread
161+
self.dev_server = None
161162

162163
if request.config.option.no_fake_server:
163164
# use a real HTTP server. Note that as soon as we request the
164165
# fixture, the server automatically starts in its own thread.
165-
self.http_server = request.getfixturevalue("http_server")
166+
self.dev_server = request.getfixturevalue("dev_server")
167+
self.http_server_addr = self.dev_server.base_url
166168
self.router = None
167-
self.is_fake_server = False
168169
else:
169170
# use the internal playwright routing
170-
self.http_server = "https://fake_server"
171+
self.http_server_addr = "https://fake_server"
171172
self.router = SmartRouter(
172173
"fake_server",
173174
cache=request.config.cache,
174175
logger=logger,
175176
usepdb=request.config.option.u F438 sepdb,
176177
)
177178
self.router.install(page)
178-
self.is_fake_server = True
179179
#
180180
self.init_page(page)
181181
#
@@ -211,6 +211,18 @@ def init_page(self, page):
211211
page.on("console", self._on_console)
212212
page.on("pageerror", self._on_pageerror)
213213

214+
@property
215+
def headers(self):
216+
if self.dev_server is None:
217+
return self.router.headers
218+
return self.dev_server.RequestHandlerClass.my_headers()
219+
220+
def disable_cors_headers(self):
221+
if self.dev_server is None:
222+
self.router.enable_cors_headers = False
223+
else:
224+
self.dev_server.RequestHandlerClass.enable_cors_headers = False
225+
214226
def run_js(self, code):
215227
"""
216228
allows top level await to be present in the `code` parameter
@@ -301,7 +313,7 @@ def writefile(self, filename, content):
301313
def goto(self, path):
302314
self.logger.reset()
303315
self.logger.log("page.goto", path, color="yellow")
304-
url = f"{self.http_server}/{path}"
316+
url = f"{self.http_server_addr}/{path}"
305317
self.page.goto(url, timeout=0)
306318

307319
def wait_for_console(
@@ -433,8 +445,8 @@ def _pyscript_format(self, snippet, *, execution_thread, extra_head=""):
433445
doc = f"""
434446
<html>
435447
<head>
436-
<link rel="stylesheet" href="{self.http_server}/build/pyscript.css" />
437-
<script defer src="{self.http_server}/build/pyscript.js"></script>
448+
<link rel="stylesheet" href="{self.http_server_addr}/build/pyscript.css" />
449+
<script defer src="{self.http_server_addr}/build/pyscript.js"></script>
438450
{extra_head}
439451
</head>
440452
<body>
@@ -851,6 +863,16 @@ def __init__(self, fake_server, *, cache, logger, usepdb=False):
851863
self.usepdb = usepdb
852864
self.page = None
853865
self.requests = [] # (status, kind, url)
866+
self.enable_cors_headers = True
867+
868+
@property
869+
def headers(self):
870+
if self.enable_cors_headers:
871+
return {
872+
"Cross-Origin-Embedder-Policy": "require-corp",
873+
"Cross-Origin-Opener-Policy": "same-origin",
874+
}
875+
return {}
854876

855877
def install(self, page):
856878
"""
@@ -903,13 +925,9 @@ def _router(self, route):
903925
assert url.path[0] == "/"
904926
relative_path = url.path[1:]
905927
if os.path.exists(relative_path):
906-
headers = {
907-
"Cross-Origin-Embedder-Policy": "require-corp",
908-
"Cross-Origin-Opener-Policy": "same-origin",
909-
}
910-
route.fulfill(status=200, headers=headers, path=relative_path)
928+
route.fulfill(status=200, headers=self.headers, path=relative_path)
911929
else:
912-
route.fulfill(status=404)
930+
route.fulfill(status=404, headers=self.headers)
913931
return
914932

915933
# network requests might be cached

pyscriptjs/tests/integration/test_00_support.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def test_check_js_errors_simple(self):
113113
f"""
114114
JS errors found: 1
115115
Error: this is an error
116-
at {self.http_server}/mytest.html:.*
116+
at {self.http_server_addr}/mytest.html:.*
117117
"""
118118
).strip()
119119
assert re.search(expected, msg)

pyscriptjs/tests/integration/test_01_basic.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,30 @@ def test_execution_thread(self):
3232
expected = f"[pyscript/main] Starting the interpreter in {where}"
3333
assert expected in self.console.info.lines
3434

35+
def test_no_cors_headers(self):
36+
self.disable_cors_headers()
37+
self.pyscript_run(
38+
"""
39+
<!-- we don't really need anything here, we just want to check that
40+
pyscript starts -->
41+
""",
42+
wait_for_pyscript=False,
43+
)
44+
assert self.headers == {}
45+
if self.execution_thread == "worker":
46+
expected_alert_banner_msg = (
47+
'(PY1000): When execution_thread is "worker", the site must be cross origin '
48+
"isolated, but crossOriginIsolated is false. To be cross origin isolated, "
49+
"the server must use https and also serve with the following headers: "
50+
'{"Cross-Origin-Embedder-Policy":"require-corp",'
51+
'"Cross-Origin-Opener-Policy":"same-origin"}. '
52+
"The problem may be that one or both of these are missing."
53+
)
54+
alert_banner = self.page.wait_for_selector(".alert-banner")
55+
assert expected_alert_banner_msg in alert_banner.inner_text()
56+
else:
57+
self.assert_no_banners()
58+
3559
def test_print(self):
3660
self.pyscript_run(
3761
"""

0 commit comments

Comments
 (0)
0