Serve images directly from cache with Responses


#1

I’m wondering if it’s possible to serve a static image file using a custom response setup in the web interface. I see that we have the ability to change the mime type, but it looks like the response only allows for text.

Is there any way to get it to serve a static image when certain conditions are matched, or do we have to present that from our host in order to get it cached?


#2

Hi James,

Since the Responses are put into the VCL, and the VCL is compiled to C and then to machine code, they have to be text.

However, there’s a few tricks you can use:

  1. Use SVG images, since they’re basically XML.

  2. If the images are used by HTML Responses, use data URLs instead. See http://www.websiteoptimization.com/speed/tweak/inline-images/

  3. If you manage to make an image file without any NULL bytes in it, you could base64 encode it and use our base64 decoder. In the Response you would put something like:

    "} digest.base64_decode("MrGUN17QSAtJ5UfyQOwt9A==") "{
    

    The "} at the start is to close the long string (that’s a Varnish term) that the Response is contained in, so we can use functions and variables, and the "{ at the end is to start the containing long string again, to keep the compiler happy. But because VCL doesn’t do binary, but only deals with strings, the image must not contain any NULL bytes, since NULL bytes are string terminators.

I hope that helps.


#3

I did some additional research into this today and thought I’d add to the thread. The problem of not being able to represent data in our STRING data type if it contains a null byte is something we hope to address soon. In the meantime, it’s worth documenting that

  • PNG format images are impossible to represent without null bytes, because each chunk starts with a fixed 8 byte header that specifies the length of the chunk as a 4-byte sequence. If any chunk is shorter than 16MB, the highest order byte in that chunk’s header will be a null byte.
  • GIF also requires null bytes. The first nulls in a GIF are the terminators for the width and height of the canvas, so it’s also impossible to create a GIF without nulls.
  • JPEG uses null bytes to separate image chunks.

So all conventional image formats are going to fall foul of this. The only option that would work is an SVG containing an embedded image, inlined using a data: uri. This would mean that the image data would leave the Fastly server still in base64 encoded form, and would only be decoded on the browser. However, there’s really no sensible reason to do this!


#4

well, thanks, to be honest, i think that this should be quite helpful.


#5

Hey guys!

Any update on this? @triblondon You mentioned that it was something you hoped you could address soon, I was just wondering if anything moved in that direction.

I’m looking to serve a 1x1 transparent GIF (beacon) through the Responses interface or using a Custom VCL Snippet. Would it be possible now?

Thanks a lot!


#6

Hi @timmy,

If you are sending a beacon, you should not need a 1x1 GIF. Instead, send an empty response with an HTTP status 204 (“No Content”). In the browser, you can dispatch the request using navigator.sendBeacon or use an image if you like - the only reason we ever needed 1x1 GIFs was that browsers would display a ‘broken image’ placeholder. No browsers do that today, so your zero-data image will still be completely invisible (further, you could make it invisible using CSS, so there are really lots of options for ensuring that there is no visual artefact).

However, to address your question more directly, there is still no way to serve a binary object directly from the Fastly edge. You need to serve it from a backend, and cache it on fastly. Using an S3 or GCS bucket is a good solution to this if you decide you really need to serve an image.


#7

Hi !

Thanks for the quick answer.

I won’t be in control of the page where the beacon will be inserted and I wanted to avoid inserting Javascript. Inserting an img tag was what I was looking for.

Fwiw, I’m still noticing the ‘broken image’ placeholder in my browser (Chrome 70.x).
But I guess I could still go with style="display: none" though.

But anyway, regarding the initial question, I’ll probably do what you said. I’ll either serve a file from S3 or jump on the JS solution.

Thanks a lot!