Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple 404 and 428 errors #1485

Open
gigitux opened this issue Jun 5, 2024 · 16 comments
Open

Multiple 404 and 428 errors #1485

gigitux opened this issue Jun 5, 2024 · 16 comments
Assignees
Labels
[Aspect] Service Worker [Priority] High [Type] Bug An existing feature does not function as intended

Comments

@gigitux
Copy link

gigitux commented Jun 5, 2024

We tried to use WP Playground for testing Customize Your Store project. Unfortunately, we noticed that WP Playground gave some errors while testing this feature. The errors are shown in the attached image:

image

During my investigation to debug this issue, I noticed that the culprit is this one. For this project, we are using an high customized version of Gutenberg editor, so I think that we have to wait that this PR will be merged in trunk.

image
(iframe URL)

Reproduction steps

  1. Click on this link
  2. Click on "skip guided setup" on the right corner.
  3. Continue the setup flow.
  4. Click on "Customize your Store".
  5. Click on "Start designing".
  6. Wait that the loading screen finish.
  7. See the errors in the console
@brandonpayton
Copy link
Member

There is something funny going on here involving blob URLs.
Screenshot 2024-06-07 at 12 25 42 PM

It looks like the failing requests are not being intercepted or at least handled by the Service Worker.
Screenshot 2024-06-07 at 12 52 52 PM

The 404s are real because the resources do not exist. The 428s appear to be caused by WP Cloud rate-limiting after frequent 404s. I think it is safe to treat these 428s we're seeing as 404s.

@brandonpayton
Copy link
Member

The blobs are apparently full HTML documents.

Sample: blob:https://playground.wordpress.net/79f5d210-568f-4fba-8dd8-3a0f5c64890d
Content:

<!doctype html>
<html>
	<head>
		<script>window.frameElement._load()</script>
		<style>html{height:auto!important;min-height:100%;}body{margin:0}</style>
		<link rel='stylesheet' id='wp-components-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/components/style.min.css?ver=6.5.4' media='all' />
<link rel='stylesheet' id='wp-preferences-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/preferences/style.min.css?ver=6.5.4' media='all' />
<link rel='stylesheet' id='wp-block-editor-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/block-editor/style.min.css?ver=6.5.4' media='all' />
<link rel='stylesheet' id='wp-reusable-blocks-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/reusable-blocks/style.min.css?ver=6.5.4' media='all' />
<link rel='stylesheet' id='wp-patterns-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/patterns/style.min.css?ver=6.5.4' media='all' />
<link rel='stylesheet' id='wp-editor-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/editor/style.min.css?ver=6.5.4' media='all' />
<link rel='stylesheet' id='wp-block-library-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/block-library/style.min.css?ver=6.5.4' media='all' />
<style id='wp-block-library-inline-css'>

				.is-style-arrow-icon-details {
					padding-top: var(--wp--preset--spacing--10);
					padding-bottom: var(--wp--preset--spacing--10);
				}

				.is-style-arrow-icon-details summary {
					list-style-type: "\2193\00a0\00a0\00a0";
				}

				.is-style-arrow-icon-details[open]>summary {
					list-style-type: "\2192\00a0\00a0\00a0";
				}

				.is-style-pill a,
				.is-style-pill span:not([class], [data-rich-text-placeholder]) {
					display: inline-block;
					background-color: var(--wp--preset--color--base-2);
					padding: 0.375rem 0.875rem;
					border-radius: var(--wp--preset--spacing--20);
				}

				.is-style-pill a:hover {
					background-color: var(--wp--preset--color--contrast-3);
				}

				ul.is-style-checkmark-list {
					list-style-type: "\2713";
				}

				ul.is-style-checkmark-list li {
					padding-inline-start: 1ch;
				}

				.is-style-arrow-link .wp-block-navigation-item__label:after {
					content: "\2197";
					padding-inline-start: 0.25rem;
					vertical-align: middle;
					text-decoration: none;
					display: inline-block;
				}

				.is-style-asterisk:before {
					content: '';
					width: 1.5rem;
					height: 3rem;
					background: var(--wp--preset--color--contrast-2, currentColor);
					clip-path: path('M11.93.684v8.039l5.633-5.633 1.216 1.23-5.66 5.66h8.04v1.737H13.2l5.701 5.701-1.23 1.23-5.742-5.742V21h-1.737v-8.094l-5.77 5.77-1.23-1.217 5.743-5.742H.842V9.98h8.162l-5.701-5.7 1.23-1.231 5.66 5.66V.684h1.737Z');
					display: block;
				}

				/* Hide the asterisk if the heading has no content, to avoid using empty headings to display the asterisk only, which is an A11Y issue */
				.is-style-asterisk:empty:before {
					content: none;
				}

				.is-style-asterisk:-moz-only-whitespace:before {
					content: none;
				}

				.is-style-asterisk.has-text-align-center:before {
					margin: 0 auto;
				}

				.is-style-asterisk.has-text-align-right:before {
					margin-left: auto;
				}

				.rtl .is-style-asterisk.has-text-align-left:before {
					margin-right: auto;
				}
</style>
<link rel='stylesheet' id='wp-block-editor-content-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/block-editor/content.min.css?ver=6.5.4' media='all' />
<link rel='stylesheet' id='wp-edit-blocks-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-includes/css/dist/block-library/editor.min.css?ver=6.5.4' media='all' />
<link rel='stylesheet' id='wc-blocks-style-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/wc-blocks.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-active-filters-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/active-filters.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-add-to-cart-form-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/add-to-cart-form.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-all-products-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/all-products.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-all-reviews-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/all-reviews.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-attribute-filter-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/attribute-filter.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-packages-style-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/packages-style.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-breadcrumbs-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/breadcrumbs.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-catalog-sorting-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/catalog-sorting.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-customer-account-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/customer-account.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-featured-category-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/featured-category.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-featured-product-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/featured-product.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-mini-cart-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/mini-cart.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-price-filter-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/price-filter.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-button-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-button.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-categories-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-categories.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-collection-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-collection.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-gallery-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-gallery.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-image-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-image.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-image-gallery-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-image-gallery.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-template-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-template.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-query-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-query.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-rating-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-rating.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-rating-stars-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-rating-stars.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-results-count-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-results-count.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-reviews-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-reviews.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-sale-badge-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-sale-badge.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-search-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-search.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-sku-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-sku.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-stock-indicator-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-stock-indicator.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-summary-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-summary.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-title-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-title.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-rating-filter-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/rating-filter.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-reviews-by-category-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/reviews-by-category.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-reviews-by-product-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/reviews-by-product.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-product-details-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/product-details.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-single-product-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/single-product.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-stock-filter-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/stock-filter.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-status-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-status.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-summary-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-summary.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-totals-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-totals.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-downloads-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-downloads.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-billing-address-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-billing-address.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-shipping-address-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-shipping-address.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-additional-information-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-additional-information.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-additional-fields-wrapper-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-additional-fields-wrapper.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-order-confirmation-additional-fields-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/order-confirmation-additional-fields.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-cart-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/cart.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-checkout-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/checkout.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='wc-blocks-style-mini-cart-contents-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/mini-cart-contents.css?ver=wc-9.1.0' media='all' />
<link rel='stylesheet' id='woocommerce-layout-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/css/woocommerce-layout.css?ver=9.1.0' media='all' />
<link rel='stylesheet' id='woocommerce-smallscreen-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/css/woocommerce-smallscreen.css?ver=9.1.0' media='only screen and (max-width: 768px)' />
<link rel='stylesheet' id='woocommerce-general-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/css/woocommerce.css?ver=9.1.0' media='all' />
<link rel='stylesheet' id='woocommerce-blocktheme-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/css/woocommerce-blocktheme.css?ver=9.1.0' media='all' />
<link rel='stylesheet' id='twentytwentyfour-button-style-outline-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/themes/twentytwentyfour/assets/css/button-outline.css?ver=1.1' media='all' />
<link rel='stylesheet' id='wc-blocks-editor-style-css' href='https://playground.wordpress.net/scope:0.9707661022834402/wp-content/plugins/woocommerce/assets/client/blocks/wc-blocks-editor-style.css?ver=wc-9.1.0' media='all' />

		
	</head>
	<body>
		<script>document.currentScript.parentElement.remove()</script>
	</body>
</html>

I was able to obtain this by hacking woocommerce/assets/client/admin/chunks/customize-store.js to no longer provide a disposal function that calls URL.revokeObjectURL(). Once the URLs were no longer being revoked, it was possible to view their source by clicking on them in the initiator column of the devtools Network tab.

It seems like the Service Worker may not be given an opportunity to intercept requests for the resources referenced by the HTML blob.

Will continue digging.

@brandonpayton
Copy link
Member

Some ServiceWorker spec discussion from 2015:
w3c/ServiceWorker#712

And an unresolved Chromium bug:
"Script created documents in iframes aren't being associated with the correct SW registration"
https://issues.chromium.org/issues/40397133

cc @adamziel @bgrgicak for visibility

@brandonpayton
Copy link
Member

brandonpayton commented Jun 7, 2024

This issue also exists in Firefox v126.0.1.

Probably a good next step is to create an isolated test case without Playground or Woo to see whether it is possible to:

  • create an HTML blob URL
  • set it as iframe src
  • handle subrequests for HTML blob dependencies in a service worker

@adamziel
Copy link
Collaborator

adamziel commented Jun 10, 2024

It sounds like there'a an uncontrolled iframe somewhere – it's why we patch Gutenberg in the service worker:

/*
 * Pair the site editor's nested iframe to the Service Worker.
 *
 * Without the patch below, the site editor initiates network requests that
 * aren't routed through the service worker. That's a known browser issue:
 *
 * * https://bugs.chromium.org/p/chromium/issues/detail?id=880768
 * * https://bugzilla.mozilla.org/show_bug.cgi?id=1293277
 * * https://github.com/w3c/ServiceWorker/issues/765
 *
 * The problem with iframes using srcDoc and src="about:blank" as they
 * fail to inherit the root site's service worker.
 *
 * Gutenberg loads the site editor using <iframe srcDoc="<!doctype html">
 * to force the standards mode and not the quirks mode:
 *
 * https://github.com/WordPress/gutenberg/pull/38855
 *
 * This commit patches the site editor to achieve the same result via
 * <iframe src="/doctype.html"> and a doctype.html file containing just
 * `<!doctype html>`. This allows the iframe to inherit the service worker
 * and correctly load all the css, js, fonts, images, and other assets.
 *
 * Ideally this issue would be fixed directly in Gutenberg and the patch
 * below would be removed.
 *
 * See https://github.com/WordPress/wordpress-playground/issues/42 for more details
 *
 * ## Why does this code live in the service worker?
 *
 * There's many ways to install the Gutenberg plugin:
 *
 * * Install plugin step
 * * Import a site
 * * Install Gutenberg from the plugin directory
 * * Upload a Gutenberg zip
 *
 * It's too difficult to patch Gutenberg in all these cases, so we blanket-patch
 * all the scripts requested over the network whose names seem to indicate they're
 * related to the Gutenberg plugin.
 */

@adamziel
Copy link
Collaborator

adamziel commented Jun 10, 2024

I don't know any solution other than using <iframe src="/file-loaded-from-the-server.html"></iframe> instead of blobs, srcdocs, and all other ways of populating the iframe. Perhaps we could have a MutationObserver in each iframe that would enforce loading an empty.html file and would then populate the contentDocument with the content of the actual blob, srcDoc etc.

@brandonpayton
Copy link
Member

@adamziel, since MutationObserver only gives async feedback, I wonder if it would be better to override document.createElement within the wp iframe to do the following after creating iframe elements:

  • Override newIFrame.setAttribute() to handle newIFrame.setAttribute('src', value) differently
  • Define a newIFrame.src property to handle setting values differently

Usually, it is better to avoid doing this kind of thing, but since Playground is serving as a platform, maybe it makes sense for Playground to be more opinionated in the service of that platform.

@brandonpayton
Copy link
Member

During my investigation to debug this issue, I noticed that the culprit is #646 (comment). For this project, we are using an high customized version of Gutenberg editor, so I think that we have to wait thathttps://github.com/WordPress/gutenberg/pull/55152 will be merged in trunk.

@gigitux already pointed to the issue related to blobs, iframes and Service Worker in this issue description, but I assumed all relevant details were communicated via a separate Slack thread and skipped reading this issue description closely.

Then I found the same with independent investigation. Thanks for pointing us in the right direction anyway @gigitux. :)

@brandonpayton
Copy link
Member

I'm planning to experiment with overriding DOM APIs to fix the general case here. We don't really want to force software not to use a web platform feature just to run adequately within WordPress Playground.

@brandonpayton
Copy link
Member

@gigitux the original blueprint you linked under this issue no longer works for repro because the GitHub build artifact has expired by now, but I was able to load your changes using a more recent CI build from this PR:
woocommerce/woocommerce#48129

Specifically, I grabbed an updated plugins-#### from this line:
https://github.com/woocommerce/woocommerce/actions/runs/9500080818/job/26182334827#step:7:28

Unfortunately (or fortunately?), when I do that, I am no longer able to reproduce this issue in WordPress Playground. Check out this nice looking Customize Your Store screen.
Screenshot 2024-06-14 at 3 59 59 PM

Are you still able to reproduce this issue in Playground?

@gigitux
Copy link
Author

gigitux commented Jun 17, 2024

@brandonpayton The Gutenberg iframe is loaded after that, you click on "Start designing": you should start to get errors after clicking on the button.

@brandonpayton
Copy link
Member

@brandonpayton The Gutenberg iframe is loaded after that, you click on "Start designing": you should start to get errors after clicking on the button.

Ah, right. Thanks. Also in your repro instructions. 🤦‍♂️

I'm planning to experiment with overriding DOM APIs to fix the general case here. We don't really want to force software not to use a web platform feature just to run adequately within WordPress Playground.

I roughed out the following platform patches for the iframe-with-blog URL issue, and with initial, incomplete testing, it resolves the issue:

function readBlobAsText(blobUrl) {
	try {
		let xhr = new XMLHttpRequest();
		xhr.open('GET', blobUrl, false);
		xhr.overrideMimeType('text/plain;charset=utf-8');
		xhr.send();
		return xhr.responseText;
	} catch(e) {
		return '';
	} finally {
		// TODO: Should we really revoke someone else's blob URL?
		//URL.revokeObjectURL(url);
	}
};

function looksLikeBlobUrl(url) {
	return url.startsWith('blob:');
}

function maybeOverrideIframeSrc(srcValue) {
	if (looksLikeBlobUrl(srcValue)) {
		const blobText = readBlobAsText(srcValue);
		return '/blob-relay.html#' + encodeURIComponent(blobText);
	} else {
		return srcValue;
	}
}

export default applyBlobUrlWorkaround;

export function applyBlobUrlWorkaround() {
	const originalIframeSetAttribute = HTMLIFrameElement.prototype.setAttribute;
	HTMLIFrameElement.prototype.setAttribute = function setAttribute_maybeBlobUrlWorkaround(name, value) {
		if (name === 'src') {
			value = maybeOverrideIframeSrc(value);
		}
		originalIframeSetAttribute.call(this, name, value);
	};
	// TODO: Consider overriding getter to show blob: URL

	const originalIframeSrcDescriptor = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, 'src');
	if (!originalIframeSrcDescriptor.configurable) {
		// TODO: Improve warning
		console.warn('iframe.src is not configurable');
	}
	const srcDescriptor = {
		...originalIframeSrcDescriptor,
		set: function setSrcProperty_maybeBlobUrlWorkaround(value) {
			value = maybeOverrideIframeSrc(value);
			originalIframeSrcDescriptor.set.call(this, value);
		}
	}
	Object.defineProperty(HTMLIFrameElement.prototype, 'src', srcDescriptor);

	const originElementInnerHtmlDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'innerHTML');
	// TODO: Warn if not configurable
	const innerHtmlDescriptor = {
		...originElementInnerHtmlDescriptor,
		set: function setInnerHtmlProperty_maybeBlobUrlWorkaround(value) {
			const template = document.createElement('template');
			template.innerHTML = value;
			template.content.querySelectorAll('iframe').forEach(iframe => {
				if (iframe.src && looksLikeBlobUrl(iframe.src)) {
					iframe.src = maybeOverrideIframeSrc(iframe.src);
				}
			});
			originElementInnerHtmlDescriptor.set.call(this, template.innerHTML);
		},
	};
	Object.defineProperty(HTMLElement.prototype, 'innerHTML', innerHtmlDescriptor);

	const originElementOuterHtmlDescriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'outerHTML');
	// TODO: Warn if not configurable
	const outerHtmlDescriptor = {
		...originElementOuterHtmlDescriptor,
		set: function setOuterHtmlProperty_maybeBlobUrlWorkaround(value) {
			const template = document.createElement('template');
			template.outerHTML = value;
			template.content.querySelectorAll('iframe').forEach(iframe => {
				if (iframe.src && looksLikeBlobUrl(iframe.src)) {
					iframe.src = maybeOverrideIframeSrc(iframe.src);
				}
			});
			originElementOuterHtmlDescriptor.set.call(this, template.innerHTML);
		},
	};
	Object.defineProperty(HTMLElement.prototype, 'outerHTML', outerHtmlDescriptor);

	document.addEventListener('DOMContentLoaded', () => {
		document.querySelectorAll('iframe').forEach(iframe => {
			if (iframe.src && looksLikeBlobUrl(iframe.src)) {
				iframe.src = maybeOverrideIframeSrc(iframe.src);
			}
		});
	});

	// TODO: Return a function to undo the workaround
}

blob-relay.html is based on empty.html from the existing Playground workaround for the block editor:

<!doctype html><script>const hash = window.location.hash.substring(1); if ( hash ) document.write(decodeURIComponent(hash))</script>

I don't love patching the DOM APIs like this, but since Playground is a platform, I think it may make sense to apply a workaround like this to pages loaded in a WordPress context within Playground.

Next: Planning to make a blueprint to demonstrate this workaround.

@brandonpayton
Copy link
Member

As an aside:
In my testing, it looks like Safari may not have this problem with blob URLs, but Firefox and Chrome do.

@adamziel adamziel moved this to Needs Triage/Our Reply in Playground Board Jul 1, 2024
@adamziel adamziel added [Type] Bug An existing feature does not function as intended [Priority] High labels Jul 1, 2024
@brandonpayton brandonpayton self-assigned this Jul 16, 2024
@brandonpayton brandonpayton moved this from Needs Triage/Our Reply to Up next in Playground Board Jul 16, 2024
@adamziel
Copy link
Collaborator

@brandonpayton any updates here?

@brandonpayton
Copy link
Member

@brandonpayton any updates here?

@adamziel there are no updates yet. The next step is to make a PR. It was next on my list for the weekend, but at this point, it will have to wait for the coming week. Will try to wrap this soon.

@adamziel adamziel removed this from the Zero Crashes milestone Nov 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Aspect] Service Worker [Priority] High [Type] Bug An existing feature does not function as intended
Projects
Status: Bugs Backlog
Development

No branches or pull requests

4 participants
@adamziel @brandonpayton @gigitux and others