Worker push is corrupting image

I’m trying to use a worker to http/2 push two images, but somehow the images are getting corrupted when I enable the worker. As soon as I delete the worker, the image links work again.

An example of the corrupted image is at https://drive.google.com/open?id=1zvW8Txejp7wlv1hWO7tZMJqboHO2iV8g

The worker code is at https://drive.google.com/open?id=1ykPMAHcq6Nhnt8FIeymg9Hya090EChNw

The following lines are how I specify which images to push -

response.headers.append(“Link”, “</g3-1/632bff93-home2-cropped-blue_00000000000000000001o.jpg>; rel=preload; as=image;”)
response.headers.append(“Link”, “</g3-1/a944d3d8-landing-page-bg-desktop2-min_00000000000000000001o.jpg>; rel=preload; as=image;”)

EDIT:

It turns out that even if I remove the quoted lines of code above and do not use the worker for pushing the image (i.e. I use it only for appending the domain preconnect link tags) it still somehow corrupts the images and they don’t render. Does anyone have any idea why this is happening?

Whats the URL where the worker is mapped to?

I had to delete the worker for now because of this issue, but otherwise the worker was mapped to route = “refinance.seguroloans.com/*

Could you try to map it to root only, without the asterisk?

Even though I am not 100% sure - because of the presumed push instead of a regular request - I could imagine the problem to be that the asterisk makes the worker run for the image requests as well, which in turn could corrupt the image because of the string handling - and the file you posted does look a bit double/mis encoded.

An alternative would be to adjust the worker code to this (-> if clause)

async function handle(request)
{
	// Forward request to origin, get response.
	let response = await fetch(request);

	if (response.headers.get('Content-Type') != 'text/html') return response;

	// Define preconnect headers

	const precon1 = '<link rel="dns-prefetch preconnect" href="https://builder-assets.unbounce.com">';
	const precon2 = '<link rel="dns-prefetch preconnect" href="https://scripts.iconnode.com">';
	const precon3 = '<link rel="dns-prefetch preconnect" href="https://www.google-analytics.com">';
	const precon4 = '<link rel="dns-prefetch preconnect" href="https://www.googletagmanager.com">';
	const precon5 = '<link rel="dns-prefetch preconnect" href="https://embedsocial.com">';


	// Copy Response object so that we can edit headers.
	response = new Response(response.body, response);
	const html = await response.text();
	const newhtml = html.replace("<head>", ["<head>", precon1, precon2, precon3, precon4, precon5].join(""));
	response = new Response(newhtml, response);


	// Add headers.
	response.headers.append("Link", "</g3-1/632bff93-home2-cropped-blue_00000000000000000001o.jpg>; rel=preload; as=image;");
	response.headers.append("Link", "</g3-1/a944d3d8-landing-page-bg-desktop2-min_00000000000000000001o.jpg>; rel=preload; as=image;");

	// Return on to client.
	return response;
}

addEventListener('fetch', event => {
	event.respondWith(handle(event.request));
})
1 Like

Good idea! I tried removing the asterisk first, that prevented the image error, but then the server push did not work, probably because the worker wasn’t being triggered.

So I added the asterisk back and tried the IF clause, that also doesn’t cause a problem with the images, but the push still doesn’t work and the preconnect headers are also not appended, probably because the IF condition is always true for every web page.

Well, if the request was for the root URL the worker should have fired and subsequently include the two Link headers, which in turn should make Cloudflare push the two images. That last bit shouldnt require additional requests.

What do you mean by “with the images”? They still didnt get included.

If the preconnect headers did not get appended, the issue must be somewhere else. With the if the script is more restrictive than your version, not more inclusive.

The html request was not for the root URL. I have multiple pages under that root URL. I guess that’s the reason the worker didn’t get triggered.

I meant the worker didn’t corrupt the images because it didn’t get triggered.

The issue with your solution is if I’ve specified * to cover all URLs, not just root, then using the IF condition doesn’t work because “if (response.headers.get(‘Content-Type’) != ‘text/html’) return response;” is always activated, so the rest of the script doesn’t run, I think. I could be wrong.

The script will still do the same what it did before, just not for all resources but only HTML content.

Ok so here’s what fixed it. I removed the If condition and added multiple routes for all of the different pages, except I made sure to leave out the route that would cover the images. Previously I had just one route from root which covered all subfolders.

Now the worker gets triggered but it does not corrupt the images.

Thanks for your help, much appreciated!