Automatically serve webp if browser supports it

I would like to automatically serve webp images to browsers that support webp. I think this is a feature caddy can do out of the box in the future. But for now now how can I do did using the http.rewrite function?

Hi @watermelonjuice,

Of the three methods recommended by Google to detect webp support, one of them - server-side content negotiation - can be handled quite simply. It’ll need to be done with a regex substitution:

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

In this untested example, if the client sends image/webp in their Accept header, Caddy rewrites any URI ending in .jpg, .jpeg, or .png. First it will try the .webp version - if it doesn’t exist, it will fall back to serving the originally requested file (if it is a file) or the directory (for the edge case where a directory is named with a file extension). You can alter the capture group to add/remove extensions as necessary.

Google has more detail on the other (non-server-side) methods if you’re interested:

This works when its a rule by itself. However, for some reason I can’t get it to work with my other rewrite rule:

rewrite {
        ext !ico !pdf !jpg !jpeg !png !gif !svg !css !js !ttf !eot !woff !txt
        to {path} {path}/ /index.php?{query}

After some investigation I’d advice against serving webp server side. As it seems many caches will cache the first request for an image. If the first request is from a webp supporting browser then the cache will start serving webp to browsers that do not support webp.

You could use the Vary header (set to Content-Type). That way caches will distinguish between the returned content type (e.g. image/webp vs image/jpeg).

How would you add Vary: Content-type to the rewrite rule?

The content-type using the above method is coming back as image/jpeg despite it being webp.

That might actually be the issue here. Your content type should be set to image/webp when serving a webp image. If you tell the cache that your webp is a jpeg file as well, then of course it’s gonna think it’s the same as the actual jpeg image :slight_smile:

To set the header, you need to add a header directive. I haven’t implemented this specific one myself but I’m pretty sure it shouldn’t be too difficult if you check out the docs.

Edit: going by the code posted by @Whitestrake you’ll need to figure out whether or not you’re actually serving the webp file or not, to know if you should add the header. Also, if you get a content type image/jpeg back, you might actually just be serving the jpeg image and not the webp. So I’d try to narrow that down first.

1 Like

From my testing I am actually serving the webp to clients that accept image/webp. When the file extension is webp the content type is image/webp. When the file extension is .jpg but a webp is being served instead the content type is image/jpeg.

Would this be considered a bug? If so, I’ll report it on github.

1 Like

Sounds like a bug, or at the very least unwanted behaviour.

Content type on a rewritten request should be the content type of the rewrite target, not the original request. Possibly this is some problem with Caddy’s static file server?

Go ahead and open an issue - thanks!

1 Like

I am doing further testing and it now responding with the correct content type. I have made no changes in configuration. Maybe I was imagining it before.

curl --head https://....jpg
HTTP/2 200 
accept-ranges: bytes
content-type: image/jpeg
etag: W/"...-8c921"
last-modified: Wed, 01 Nov 2017 12:20:31 GMT
server: Caddy
content-length: 575777
date: Thu, 02 Nov 2017 01:05:48 GMT

curl --head https://....jpg -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" 
HTTP/2 200 
accept-ranges: bytes
content-type: image/webp
etag: W/"...-abc8"
last-modified: Wed, 01 Nov 2017 12:20:32 GMT
server: Caddy
content-length: 43976
date: Thu, 02 Nov 2017 01:07:40 GMT

I have made this work for my site. This rewrite must be placed before any other rewrite.

The needed configuration for caddy has been submitted to the webp-detect project: webp-detect/caddy.conf at master · igrigorik/webp-detect · GitHub

The above content type issue I was experiencing is a chrome bug. Caddy is working as expected. Please see 626081 - chromium - An open-source project to help move the web forward. - Monorail


This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.