Image cache headers are sometimes provided by Drupal, sometimes by Apache

Created on 26 February 2024, about 1 year ago
Updated 28 March 2024, about 1 year ago

Problem/Motivation

We configured our Apache to serve image derivatives straight from disk when they exist, using the snippet in htaccess.prepend.txt. This works mostly well, but not for the user first requesting the derivative: they get the response from DrImageController, which has either the max-age defined in proxy_cache_maximum_age or the default max-age of the website.

I want to be able to disable caching on this response, since the cache headers set by Drupal are a lot less ideal than the ones set by Apache: Apache sets the Etag header which causes the image to be invalidated from the browser when it changes. Drupal only sets the max-age, without any possibility to invalidate the image, causing the image to always be cached for the duration defined in the max-age - even if the image (crop) changes.

Apart from the headers not being ideal, it's confusing that sometimes images get cache headers defined by Drupal and sometimes they get cache headers defined by Apache. In most cases these will not be the same, which can lead to unexpected results.

Steps to reproduce

  1. Clear image derivatives (drush if --all)
  2. Open your browser dev tools network tab, but make sure cache stays enabled
  3. Filter the network tab by images and (re)load the page. All image derivatives will be (re)generated.
  4. You'll notice that on subsequent page loads, the response with header x-generator: Drupal 10 (https://www.drupal.org) will keep being served instead of Apache taking over.

Proposed resolution

Add a possibility to disable caching on the responses coming from DrImageController so that next request, the image derivative will be served straight from the file with Apache headers, instead of the initial Drupal response to stay cached.

🐛 Bug report
Status

Fixed

Version

2.0

Component

Code

Created by

🇧🇪Belgium dieterholvoet Brussels

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @dieterholvoet
  • 🇧🇪Belgium dieterholvoet Brussels

    I also propose renaming the proxy_cache_maximum_age option to cache_max_age since it's misleading: that max-age is not only used in case of reverse proxies, but every time an image is served by drimage.

  • Status changed to Needs review about 1 year ago
  • Status changed to Needs work about 1 year ago
  • 🇧🇪Belgium dieterholvoet Brussels

    I changed DrImageController to disable caching in case the option is set to 0, but that doesn't fix everything yet. Redirect responses caused by PathProcessorImageStyles are still being cached, which causes any subsequent page loads to keep redirecting to the drimage endpoint with a path in the format $path_prefix . $width . '/' . $height . '/' . $fid . '/' . $iwc_id . '/' . $format, not allowing Apache to directly serve the generated file. I'll try to add a response subscriber that disables caching for those redirect responses.

  • Status changed to Needs review about 1 year ago
  • 🇧🇪Belgium dieterholvoet Brussels

    Okay, so this works:

    1. First request is to /nl/drimage/1500/0/67/event_header/sites/default/files/media/images/Agenda_Detail%20Page%204_%20Study%20Spaces%20Zomer%20-%20Content.jpg.webp, redirects to /nl/drimage/1500/0/67/event_header/webp (served by Drupal, not cached)
    2. Second request is to /nl/drimage/1500/0/67/event_header/webp, serves the image (served by Drupal, not cached)
    3. After reloading the page, first request is again to /nl/drimage/1500/0/67/event_header/sites/default/files/media/images/Agenda_Detail%20Page%204_%20Study%20Spaces%20Zomer%20-%20Content.jpg.webp, but this time served by Apache and still not cached
    4. After reloading the page, the request is served from browser cache

    This could still be improved: if we could get rid of PathProcessorImageStyles, the second request could serve the image and the image would be served from cache during the second page load instead of during the third. This is only the case for the first user loading the image if it hasn't been generated yet though, so might not be worth the effort.

  • Pipeline finished with Skipped
    about 1 year ago
    #119240
  • Status changed to Fixed about 1 year ago
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024