Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions agent/pages/internal_server_error.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,21 @@
<h1>The application returned an error</h1>
<p>Error: 500 Internal Server Error</p>
</div>
<!-- nginx serves this page inside an iframe. A link with no target loads
into that frame, and both destinations send X-Frame-Options:
SAMEORIGIN, so the browser refuses to render them. _blank opens a new
top-level tab, which is never framed, and leaves this page up. -->
<a
class="button"
target="_blank"
href="https://docs.frappe.io/cloud/performance-error-debugging#500-internal-server-error"
>View troubleshooting guide</a
>
</div>
<p class="footer">
Site owner? Review the
<a
target="_blank"
href="https://frappecloud.com/dashboard/benches/__BENCH_NAME__/logs/web.error.log"
>error logs</a
>
Expand Down
16 changes: 16 additions & 0 deletions agent/tests/test_pages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import glob
import os
import re
import unittest

PAGES_DIRECTORY = os.path.join(os.path.dirname(__file__), "..", "pages")
Expand Down Expand Up @@ -37,6 +38,21 @@ def test_placeholder_dashboard_links_are_rewritten(self):
if "dashboard-url" in html:
self.assertIn("dashboard/sites/${window.location.hostname}", html, name)

def test_iframed_pages_escape_the_frame(self):
# nginx injects the 500 page as an iframe. A link with no target loads into
# that frame, and every destination sends X-Frame-Options: SAMEORIGIN.
escaping_targets = ('target="_blank"', 'target="_top"')
with open(BENCH_NGINX_TEMPLATE) as f:
template = f.read()

for name, html in read_pages():
if f'iframe src="/{name}"' not in template:
continue
for tag in re.findall(r"<a\b[^>]*>", html):
if 'href="http' in tag:
escapes = any(target in tag for target in escaping_targets)
self.assertTrue(escapes, f"{name}: {tag}")

def test_bench_name_placeholder_is_substituted_by_nginx(self):
# an unsubstituted __BENCH_NAME__ ships a dead link to the site owner
with open(BENCH_NGINX_TEMPLATE) as f:
Expand Down
Loading