Procházet zdrojové kódy

Use a temporary redirect for image URLs when using serve view

- If the underlying image changes underneath (eg S3 file key), then the rendition URL becomes incorrect. Use a temporary redirect in this case.
- Set cache control header when serving images
- This will help with the redirect no longer being permanent
Jake Howard před 2 roky
rodič
revize
e991a8e8d9

+ 1 - 0
CHANGELOG.txt

@@ -51,6 +51,7 @@ Changelog
  * Update documentation dependencies; Sphinx Wagtail Theme to v5.3.2, MyST Parser to v0.18.1, add Sphinx Copy Button (LB (Ben) Johnston)
  * Add "What's New" dashboard banner and "Help" menu in sidebar (Sage Abdullah)
  * Implement new "minimap" component for the page editor (Thibaud Colas)
+ * The `image_url` template tag, when using the serve view to redirect rather than serve directly, will now use temporary redirects with a cache header instead of permanent redirects (Jake Howard)
  * Fix: Prevent `PageQuerySet.not_public` from returning all pages when no page restrictions exist (Mehrdad Moradizadeh)
  * Fix: Ensure that duplicate block ids are unique when duplicating stream blocks in the page editor (Joshua Munn)
  * Fix: Revise colour usage so that privacy & locked indicators can be seen in Windows High Contrast mode (LB (Ben Johnston))

+ 1 - 0
docs/releases/4.1.md

@@ -94,6 +94,7 @@ There are multiple improvements to the documentation theme this release, here ar
  * Improve side panels’ resizing in page editor and listings (Steven Steinwand)
  * Adjust breadcrumb text alignment and size in page listings & page editor (Steven Steinwand)
  * Improvements to getting started tutorial aimed at developers who are very new to Python and have no Django experience (Damilola Oladele)
+ * The `image_url` template tag, when using the serve view to redirect rather than serve directly, will now use temporary redirects with a cache header instead of permanent redirects (Jake Howard)
 
 ### Bug fixes
 

+ 11 - 1
wagtail/images/tests/tests.py

@@ -414,7 +414,7 @@ class TestFrontendServeView(TestCase):
         self.assertRedirects(
             response,
             expected_redirect_url,
-            status_code=301,
+            status_code=302,
             fetch_redirect_response=False,
         )
 
@@ -523,6 +523,16 @@ class TestFrontendServeView(TestCase):
         # Check response
         self.assertEqual(response.status_code, 410)
 
+    def test_get_cache_control(self):
+        signature = generate_signature(self.image.id, "fill-800x600")
+        response = self.client.get(
+            reverse(
+                "wagtailimages_serve_action_serve",
+                args=(signature, self.image.id, "fill-800x600"),
+            )
+        )
+        self.assertEqual(response["Cache-Control"], "max-age=3600, public")
+
 
 class TestFrontendSendfileView(TestCase):
     def setUp(self):

+ 6 - 8
wagtail/images/views/serve.py

@@ -2,14 +2,11 @@ import imghdr
 from wsgiref.util import FileWrapper
 
 from django.core.exceptions import ImproperlyConfigured, PermissionDenied
-from django.http import (
-    HttpResponse,
-    HttpResponsePermanentRedirect,
-    StreamingHttpResponse,
-)
-from django.shortcuts import get_object_or_404
+from django.http import HttpResponse, StreamingHttpResponse
+from django.shortcuts import get_object_or_404, redirect
 from django.urls import reverse
-from django.utils.decorators import classonlymethod
+from django.utils.decorators import classonlymethod, method_decorator
+from django.views.decorators.cache import cache_control
 from django.views.generic import View
 
 from wagtail.images import get_image_model
@@ -41,6 +38,7 @@ class ServeView(View):
 
         return super(ServeView, cls).as_view(**initkwargs)
 
+    @method_decorator(cache_control(max_age=3600, public=True))
     def get(self, request, signature, image_id, filter_spec, filename=None):
         if not verify_signature(
             signature.encode(), image_id, filter_spec, key=self.key
@@ -75,7 +73,7 @@ class ServeView(View):
 
     def redirect(self, rendition):
         # Redirect to the file's public location
-        return HttpResponsePermanentRedirect(rendition.url)
+        return redirect(rendition.url)
 
 
 serve = ServeView.as_view()