« Back to Web

Test web server caching with curl

The web can save a lot of traffic by using optimized caching, especially for static files such as style sheets (CSS), JavaScript, images, and many other files containing static data. One option to set up caching is using the Expires header. Next step is to actually test if caching is working as expected!

Using ETag header

When ETag or entity tag is used on static files, we can retrieve the value from the response header. In that case we have to test it against a path that most likely is or should be cached, like an image.

1
2
3
4
curl --compressed \
      --head \
      --no-progress-meter \
      https://example.com/logo.svg | grep -i "^etag:" | awk '{print $2}'

This request will allow data encoding (1), and only show the response headers (2) without a progress meter (3). Finally we define the request itself and pull in the specific ETag header (4), followed by showing its value (second column).

No output? Then ETag is most likely not used or not applicable to that file type. Test it against another type of file.

If we do get a response, copy that into the request If-None-Match.

1
2
3
4
5
6
7
curl --compressed \
      --head \
      --header 'If-None-Match: "65fc4369-119"' \
      --no-progress-meter \
      --output /dev/null \
      --write-out '%{http_code}' \
      https://example.com/logo.svg

In this example we request a compressed version (1) of a SVG file (7). We perform a HEAD request (2) and any output (4 and 5) is redirected, as that part we are not interested in. The ETag is tested with a specific value, and finally we want only to see the HTTP status code (6).

If caching works as expected, you should receive a three digit response (304), which stands for HTTP 304 Not Modified. If you get a 200 or other code, then caching is not working, or the file can’t be found.

Using Last-Modified header

Another option is using the header value stored in Last-Modified. As the name implies, it tells the last modification of that particular file. Let’s see if we can retrieve it first:

1
2
3
4
# curl --compressed \
        --head \
        --no-progress-meter \
        https://example.com/logo.svg | grep -i "^last-modified:" | awk -F": " '{print $2}'

The response might look like this

Thu, 21 Mar 2024 14:25:45 GMT

Next step is using this value and combine it with the If-Modified-Since header.

1
2
3
4
5
6
7
curl --compressed \
      --head \
      --header 'If-Modified-Since: Thu, 21 Mar 2024 14:25:45 GMT' \
      --no-progress-meter \
      --output /dev/null \
      --write-out '%{http_code}' \
      https://example.com/logo.svg

This is similar to the ETag test, except line three.

Got another 304? Perfect, then caching is working.

Relevant commands in this article

Like to learn more about the commands that were used in this article? Have a look, for some there is also a cheat sheet available.

Feedback

Small picture of Michael Boelen

This article has been written by our Linux security expert Michael Boelen. With focus on creating high-quality articles and relevant examples, he wants to improve the field of Linux security. No more web full of copy-pasted blog posts.

Discovered outdated information or have a question? Share your thoughts. Thanks for your contribution!

Mastodon icon