Add cache control headers with respect to Snippet expire time.

This commit is contained in:
Martin Mahner 2019-12-08 09:07:23 +01:00
parent a8574613ab
commit 0c9b346c4d
6 changed files with 63 additions and 18 deletions

View file

@ -613,6 +613,14 @@ class dpasteAppConfig(AppConfig):
# ('zephir', 'Zephir') # ('zephir', 'Zephir')
] ]
# Whether to send out cache headers (Max-Age, Never-Cache, etc.).
CACHE_HEADER = True
# Defines how long pages are cached by upstream Proxies (Max-Age Header).
# This does not affect caching of snippets, their max-age limit is set
# to the expire date.
CACHE_TIMEOUT = 60 * 10
@staticmethod @staticmethod
def get_base_url(request=None): def get_base_url(request=None):
""" """

View file

@ -1,9 +1,8 @@
from datetime import timedelta from datetime import timedelta
from django.apps import apps
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.utils import timezone from django.utils import timezone
from django.apps import apps
from dpaste.models import Snippet from dpaste.models import Snippet

View file

@ -30,7 +30,7 @@ ALLOWED_HOSTS = env("ALLOWED_HOSTS", "*").split(",")
TIME_ZONE = "UTC" TIME_ZONE = "UTC"
USE_I18N = True USE_I18N = True
USE_L10N = True USE_L10N = True
USE_TZ = True USE_TZ = False
LANGUAGE_CODE = "en" LANGUAGE_CODE = "en"
LANGUAGES = (("en", "English"),) LANGUAGES = (("en", "English"),)

View file

@ -2,6 +2,7 @@
Settings for the testsuite runs. Settings for the testsuite runs.
""" """
import django import django
from .base import * # noqa from .base import * # noqa
SECRET_KEY = "test-key" SECRET_KEY = "test-key"

View file

@ -1,6 +1,7 @@
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.conf.urls import url from django.conf.urls import url
from django.views.decorators.cache import cache_control
from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import TemplateView from django.views.generic import TemplateView
@ -13,9 +14,11 @@ urlpatterns = [
url(r"^$", views.SnippetView.as_view(), name="snippet_new"), url(r"^$", views.SnippetView.as_view(), name="snippet_new"),
url( url(
r"^about/$", r"^about/$",
cache_control(max_age=config.CACHE_TIMEOUT)(
TemplateView.as_view( TemplateView.as_view(
template_name="dpaste/about.html", template_name="dpaste/about.html",
extra_context=config.extra_template_context, extra_context=config.extra_template_context,
)
), ),
name="dpaste_about", name="dpaste_about",
), ),

View file

@ -1,6 +1,7 @@
import datetime import datetime
import difflib import difflib
import json import json
import time
from django.apps import apps from django.apps import apps
from django.http import ( from django.http import (
@ -10,12 +11,12 @@ from django.http import (
HttpResponseForbidden, HttpResponseForbidden,
HttpResponseRedirect, HttpResponseRedirect,
) )
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404, render
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.cache import add_never_cache_headers, patch_cache_control
from django.utils.http import http_date
from django.utils.translation import ugettext from django.utils.translation import ugettext
from django.views.defaults import page_not_found as django_page_not_found
from django.views.defaults import server_error as django_server_error
from django.views.generic import FormView from django.views.generic import FormView
from django.views.generic.base import TemplateView, View from django.views.generic.base import TemplateView, View
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
@ -43,6 +44,12 @@ class SnippetView(FormView):
form_class = SnippetForm form_class = SnippetForm
template_name = "dpaste/new.html" template_name = "dpaste/new.html"
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
if config.CACHE_HEADER:
patch_cache_control(response, max_age=config.CACHE_TIMEOUT)
return response
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super(SnippetView, self).get_form_kwargs() kwargs = super(SnippetView, self).get_form_kwargs()
kwargs.update({"request": self.request}) kwargs.update({"request": self.request})
@ -58,12 +65,13 @@ class SnippetView(FormView):
return ctx return ctx
class SnippetDetailView(SnippetView, DetailView): class SnippetDetailView(DetailView):
""" """
Details list view of a snippet. Handles the actual view, reply and Details list view of a snippet. Handles the actual view, reply and
tree/diff view. tree/diff view.
""" """
form_class = SnippetForm
queryset = Snippet.objects.all() queryset = Snippet.objects.all()
template_name = "dpaste/details.html" template_name = "dpaste/details.html"
slug_url_kwarg = "snippet_id" slug_url_kwarg = "snippet_id"
@ -106,7 +114,18 @@ class SnippetDetailView(SnippetView, DetailView):
snippet.view_count += 1 snippet.view_count += 1
snippet.save(update_fields=["view_count"]) snippet.save(update_fields=["view_count"])
return super(SnippetDetailView, self).get(request, *args, **kwargs) response = super(SnippetDetailView, self).get(request, *args, **kwargs)
# Set the Max-Age header up until the snippet would expire
if config.CACHE_HEADER:
if snippet.expire_type == Snippet.EXPIRE_KEEP:
patch_cache_control(response, max_age=config.CACHE_TIMEOUT)
if snippet.expire_type == Snippet.EXPIRE_ONETIME:
add_never_cache_headers(response)
if snippet.expire_type == Snippet.EXPIRE_TIME and snippet.expires:
response["Expires"] = http_date(snippet.expires.timestamp())
return response
def get_initial(self): def get_initial(self):
snippet = self.get_object() snippet = self.get_object()
@ -116,6 +135,11 @@ class SnippetDetailView(SnippetView, DetailView):
"rtl": snippet.rtl, "rtl": snippet.rtl,
} }
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({"request": self.request})
return kwargs
def form_valid(self, form): def form_valid(self, form):
snippet = form.save(parent=self.get_object()) snippet = form.save(parent=self.get_object())
return HttpResponseRedirect(snippet.get_absolute_url()) return HttpResponseRedirect(snippet.get_absolute_url())
@ -203,6 +227,11 @@ class SnippetHistory(TemplateView):
snippet_id_list = self.request.session.get("snippet_list", []) snippet_id_list = self.request.session.get("snippet_list", [])
return Snippet.objects.filter(pk__in=snippet_id_list) return Snippet.objects.filter(pk__in=snippet_id_list)
def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs)
add_never_cache_headers(response)
return response
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
""" """
Delete all user snippets at once. Delete all user snippets at once.
@ -332,12 +361,17 @@ class APIView(View):
def page_not_found(request, exception=None, template_name="dpaste/404.html"): def page_not_found(request, exception=None, template_name="dpaste/404.html"):
return django_page_not_found( context = {}
request, exception, template_name=template_name context.update(config.extra_template_context)
) response = render(request, template_name, context, status=404)
if config.CACHE_HEADER:
patch_cache_control(response, max_age=config.CACHE_TIMEOUT)
return response
def server_error(request, template_name="dpaste/500.html"): def server_error(request, template_name="dpaste/500.html"):
return django_server_error( context = {}
request, template_name=template_name context.update(config.extra_template_context)
) # pragma: no cover response = render(request, template_name, context, status=500)
add_never_cache_headers(response)
return response