Rewrite jpeg to webp (or avif?)

Before Caddy2, I was able to have Caddy detect whether a browser supports webp images and rewrite jpeg urls to serve webp instead to those browsers using this code from this thread:

rewrite {
  if {>Accept} has image/webp
  r ^(.+)\.(jpg|jpeg|png)$
  to {1}.webp {path} {path}/
  }
header / Vary Accept

First, how would I replicate this in Caddy2? I assume it would have something to do with rewrite and header, but I’m still having trouble translating stuff into Caddy2 Caddyfiles. (EDIT: Actually, would we want to involve try_files? I wouldn’t want to do the rewrite if there isn’t a webp version of an image for whatever reason.)

Second, does anyone know if this approach would work for AVIF files as well? This article excited me about avif: https://jakearchibald.com/2020/avif-has-landed/ Would I have to choose between rewriting to webp or avif, or could I offer both options at the same time?

Third, is there any way I could change the actual URL / filename on the webpage, so that people know before they click whether they will receive a jpeg, webp, or avif? I found it slightly annoying that if I downloaded a file called whatever.jpeg that it would actually turn out to be a webp file. There are worse sins committed on the internet, but I don’t like lying to my visitors.

I guess something like this:

@acceptsWebp {
	header Accept *image/webp*
	path_regexp webp ^(.+)\.(jpg|jpeg|png)$
}
handle @acceptsWebp {
	@hasWebp file {re.webp.1}.webp
	rewrite @hasWebp {re.webp.1}.webp
}

It’s a bit funky, but it needs to be done this way (two separate matchers, cascading with a handle) because matchers in the same set aren’t guaranteed to run in any particular order, therefore you need to split them up to make sure they run in order. This matters because you need to use the regexp result in the file matcher.

:man_shrugging:

I guess you could try to do another rewrite like this, handle blocks are mutually exclusive so you don’t need to worry they’ll step on eachother’s toes, but you might need to wrap the whole thing in a route to make sure the priority (which of the two file types you prefer) is proper (i.e. check if accepts avif first, then webp, I guess).

I guess, but it would mean serving a redirect instead of a rewrite, which is much slower because it involves an extra round-trip. There’s no other way to manipulate the URL in the browser at this layer.

2 Likes

OK, let’s say I figure out how to do the rewrite thing (with your generous help!). Is it a good idea? Would it be more wise to do this in HTML with picture tags?

One concern I have with this approach: What if a visitor decides they like a picture on my website, and they download it to their computer? Let’s say it’s named photograph.jpeg, and they try to open it, but it’s actually an AVIF, and their file browser can’t read it. They’ll be mystified, “I never had trouble opening JPEGs before, what’s wrong?” It may be quite some time before they look at the metadata and realize what the problem is.

I considered not putting a filename extension on images at all, or some fake extension like .IMG or .PIC, so that they aren’t necessarily expecting a JPG. But then file browsers won’t know what the file is and won’t open it in an image viewer without you telling them to. If you don’t put an extension on it at all, you wouldn’t even be able to tell a file browser to “open all files of this type” in your image viewer. So out of those two choices, a fake extension like .IMG seems better, but it still seems user hostile in its own way.

So, is rewriting jpegs to webp or avif just a bad idea? Are there approaches to this problem that would be less confusing and more user-friendly?

Let me be clear: The main reason I don’t want to do this with picture tags is that I’m already planning to use picture tags to display different image sizes based on people’s screen size and pixel density (and possibly their connection speed). If I add different file formats as well, i.e. webp and avif, those are going to be some really long and complicated picture tags cluttering up my HTML.

I not an expert in that area so I can’t give a definitive answer, but it feels to me that your HTML content should take care of that itself with the image source tooling the browsers provide. You can use templating tools on your server to generate the right HTML. And don’t worry about bloated HTML, gzipping will make that effectively moot - duplicated blocks of text are efficiently compressed.

1 Like

Thank you for your advice. I’m still going to try this out as soon as I convert my images to webp and avif, content negotiation seems like it should work with avif since it’s in Chrome’s user agent and presumably other browsers will add it to their user agents as well once they support it. If it turns out to be too annoying, I’ll probably fall back to HTML picture tags as you suggest.