cloudflare-esi icon indicating copy to clipboard operation
cloudflare-esi copied to clipboard

Page truncated after ESI processing

Open shukitchan opened this issue 11 months ago • 19 comments

I have a test page at https://esi-test-pages.netlify.app/esi-variables.html with the right response header -

surrogate-control: content="ESI/1.0" And here is my Worker code

import esi from "cloudflare-esi"

export default {
	async fetch(request, env, ctx): Promise<Response> {
      const url = "https://esi-test-pages.netlify.app/esi-variables.html";
      const modifiedRequest = new Request(url, request);

      const parser = new esi()
      return parser.parse(modifiedRequest)

	},
} satisfies ExportedHandler<Env>;

and the output is truncated in the middle for me after the ESI variable tag being processed.

<html lang="en">
<head><title>Test Page for ESI Variables</title></head>
<body>
<p>
Host: 
example.myaccount.workers.dev

I am wondering if I did something wrong in my test. Thanks.

shukitchan avatar Feb 08 '25 01:02 shukitchan

👋 Hi @shukitchan!

Your HTML page currently has the esi tag commented out so its a bit hard to test.

I'm surprised it's truncating.

I'll see if I can setup a test page later on to have a play.

Thanks, Callum

cdloh avatar Feb 10 '25 23:02 cdloh

The commented piece is like this <!--esi<esi:vars>$(HTTP_HOST)</esi:vars>-->

So when displayed without ESI processing, it may not show on your page. But if you view the source, you should see the above.

I can remove the <!--esi ... --> if you want. The result to me is the same with the page truncated after the processing.

shukitchan avatar Feb 10 '25 23:02 shukitchan

hey @shukitchan that's working for me. Bit odd. Is your worker returning any logs?

cdloh avatar Feb 11 '25 17:02 cdloh

Hmm.. That's strange. I deployed on a Cloudflare account and never run locally, though. Does that make a difference? On the Cloudflare Worker Web UI, I can test my worker running and see the page truncated but there is no logs returned.

shukitchan avatar Feb 11 '25 18:02 shukitchan

@shukitchan @cdloh I had a similar symptom with truncated output when converting from a normal fetch to esi.parse, although based on your code, it seems like the cause may be different.

In my case, the culprit was a subsequent await fetch(apiReq) my worker was making. The truncated output was resolved by moving this to ctx.waitUntil(fetch(apiReq)) (which it should have been anyway).

That said, I still don't fully understand what has happening, or why it only manifest with the esi parser in place. It seemed like what was happening was the subsequent await fetch was short-circuiting worker response (even though I wasn't returning it).

While debugging I also saw lots of TypeError: Illegal invocation: function called with incorrect this reference, which seems likely related.

timkelty avatar Feb 12 '25 15:02 timkelty

Are you sure that's your exact worker? I just tested myself in a new worker

<html lang="en">
<head><title>Test Page for ESI Variables</title></head>
<body>
<p>
Host: 
<worker-domain>.workers.dev

</p>
</body>
</html>

cdloh avatar Feb 12 '25 19:02 cdloh

Yes thats exactly my worker code above. I have no idea why you will have a different result from me, though

shukitchan avatar Feb 12 '25 23:02 shukitchan

I may have to find some time to debug this over the weekend if you have no other ideas.

May be it is a platform issue? I doubt that but i might need to consult with cf as well if i have no luck

shukitchan avatar Feb 13 '25 00:02 shukitchan

Also i was in 0.4.1 . Let me try 0.4.2

shukitchan avatar Feb 13 '25 04:02 shukitchan

I tried 0.4.2 and it is still not working for me.

I debugged this a bit further and this is very strange. The problem is with https://github.com/cdloh/cloudflare-esi/blob/main/src/index.ts#L297

My test ESI page is divided into 3 blocks and for the last block, the "r" variable contains the right value of the last block. And I can print this out with console.log() .

But passing it through line 297 gives me nothing.

I changed line 297 to the following writer2.write(encoder.encode('<test>' + r + '</test>'));

And I can see the output page with the <test> </test> around each of the 3 block but the last block contains nothing.

Now I think it is a problem of the platform and I should talk to CF instead.

shukitchan avatar Feb 19 '25 22:02 shukitchan

Upon further debugging through a bunch of promises, I find that the above analysis is not right. Instead my problem is fixed if I

  1. Mark this function as async - https://github.com/cdloh/cloudflare-esi/blob/main/src/index.ts#L306
  2. add await to https://github.com/cdloh/cloudflare-esi/blob/main/src/index.ts#L308

I think the problem is related to how we should coordinate the writing to the output stream.

Let me know what you think and I can also have submit a PR with the change

shukitchan avatar Apr 01 '25 23:04 shukitchan

The writer does return an async operation. But in all my usage of this in Production it's not been an issue because the data that comes down the wire is chunked anyway. If you can get some reproduction steps together that prove otherwise i'm happy to take MRs @shukitchan

cdloh avatar Apr 03 '25 22:04 cdloh

Unfortunately I am not sure how to consistently reproduce this issue on your end. I can do that with my own setup, though.

shukitchan avatar Apr 05 '25 18:04 shukitchan

@cdloh I think I've finally been able to reproduce this!

I'm still working on reproducible test, but in this case, it seems to choke if the page has inline SVGs.

Issues like this could be a reason to use HTMLRewriter to parse things, though I'm yet to use it.

timkelty avatar Nov 07 '25 16:11 timkelty

After some more testing, it seems likely this may be large single tags, like those found in SVGs or <img> tags with large srcsets.

timkelty avatar Nov 08 '25 02:11 timkelty

@cdloh I was curious, so whipped up an HTMLRewriter version: https://github.com/timkelty/esi-html-rewriter

This is the test that I think cloudflare-esi might choke on: https://github.com/timkelty/esi-html-rewriter/blob/main/tests/long-attributes-and-svg.test.ts

timkelty avatar Nov 18 '25 12:11 timkelty

Wow! Thanks heaps for the example etc. I'll see if I can replicate this somewhere in production as well.

cdloh avatar Nov 18 '25 21:11 cdloh

@timkelty do you mind if I reuse that test over here?

cdloh avatar Nov 18 '25 21:11 cdloh

@timkelty do you mind if I reuse that test over here?

Please do! If you can't reproduce, email me and I can give you the full HTML src that triggers it. I'm guessing its just a "single tag length" thing…but ya never know. SVGs can have some freaky stuff.

timkelty avatar Nov 18 '25 22:11 timkelty