Cache Fixes, Django 4.0 Update

This commit is contained in:
Martin Mahner 2021-12-13 11:00:40 +01:00
parent 0291bcd908
commit 49ca2d7631
7 changed files with 49 additions and 47 deletions

View File

@ -1,6 +1,14 @@
Changelog Changelog
========= =========
3.6 (master)
------------
- Added support for Python 3.9.
- Added support for Python 3.10.
- Removed cache headers for all views except 404. Due to that snippets can be
deleted, it's not trivial to have them removed from upstream caches.
3.5 (2020-01-08) 3.5 (2020-01-08)
---------------- ----------------

View File

@ -2,6 +2,9 @@ from django.apps import AppConfig, apps
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from logging import getLogger
log = getLogger(__file__)
class dpasteAppConfig(AppConfig): class dpasteAppConfig(AppConfig):
name = "dpaste" name = "dpaste"
@ -610,12 +613,8 @@ class dpasteAppConfig(AppConfig):
# ('zephir', 'Zephir') # ('zephir', 'Zephir')
] ]
# Whether to send out cache headers (Max-Age, Never-Cache, etc.). # Cache timeout for 404 and static pages. Snippets don't have an explicit
CACHE_HEADER = True # Cache timeout set to avoid caching in upstream proxies.
# 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 CACHE_TIMEOUT = 60 * 10
@staticmethod @staticmethod

View File

@ -1,11 +1,11 @@
from django.conf.urls import include, url from django.urls import include, re_path
urlpatterns = [ urlpatterns = [
url(r"^", include("dpaste.urls.dpaste_api")), re_path(r"^", include("dpaste.urls.dpaste_api")),
url(r"^", include("dpaste.urls.dpaste")), re_path(r"^", include("dpaste.urls.dpaste")),
url(r"^i18n/", include("django.conf.urls.i18n")), re_path(r"^i18n/", include("django.conf.urls.i18n")),
] ]
# Custom error handlers which load `dpaste/<code>.html` instead of `<code>.html` # Custom error handlers which load `dpaste/<code>.html` instead of `<code>.html`
handler404 = "dpaste.views.page_not_found" handler404 = "dpaste.views.handler404"
handler500 = "dpaste.views.server_error" handler500 = "dpaste.views.handler500"

View File

@ -1,6 +1,6 @@
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.urls import re_path
from django.views.decorators.cache import cache_control 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
@ -11,8 +11,8 @@ L = getattr(settings, "DPASTE_SLUG_LENGTH", 4)
config = apps.get_app_config("dpaste") config = apps.get_app_config("dpaste")
urlpatterns = [ urlpatterns = [
url(r"^$", views.SnippetView.as_view(), name="snippet_new"), re_path(r"^$", views.SnippetView.as_view(), name="snippet_new"),
url( re_path(
r"^about/$", r"^about/$",
cache_control(max_age=config.CACHE_TIMEOUT)( cache_control(max_age=config.CACHE_TIMEOUT)(
TemplateView.as_view( TemplateView.as_view(
@ -22,18 +22,18 @@ urlpatterns = [
), ),
name="dpaste_about", name="dpaste_about",
), ),
url(r"^history/$", views.SnippetHistory.as_view(), name="snippet_history"), re_path(r"^history/$", views.SnippetHistory.as_view(), name="snippet_history"),
url( re_path(
r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$" % L, r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/?$" % L,
views.SnippetDetailView.as_view(), views.SnippetDetailView.as_view(),
name="snippet_details", name="snippet_details",
), ),
url( re_path(
r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$" % L, r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/raw/?$" % L,
views.SnippetRawView.as_view(), views.SnippetRawView.as_view(),
name="snippet_details_raw", name="snippet_details_raw",
), ),
url( re_path(
r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/slim/?$" % L, r"^(?P<snippet_id>[a-zA-Z0-9]{%d,})/slim/?$" % L,
xframe_options_exempt( xframe_options_exempt(
views.SnippetDetailView.as_view(template_name="dpaste/details_slim.html") views.SnippetDetailView.as_view(template_name="dpaste/details_slim.html")

View File

@ -1,8 +1,8 @@
from django.conf.urls import url from django.urls import re_path
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from ..views import APIView from ..views import APIView
urlpatterns = [ urlpatterns = [
url(r"^api/$", csrf_exempt(APIView.as_view()), name="dpaste_api_create_snippet",) re_path(r"^api/$", csrf_exempt(APIView.as_view()), name="dpaste_api_create_snippet",)
] ]

View File

@ -1,5 +1,6 @@
import datetime import datetime
import difflib import difflib
import ipaddress
import json import json
from django.apps import apps from django.apps import apps
@ -14,19 +15,22 @@ 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.cache import add_never_cache_headers, patch_cache_control
from django.utils.http import http_date from django.utils.translation import gettext
from django.utils.translation import ugettext
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
from pygments.lexers import get_lexer_for_filename from pygments.lexers import get_lexer_for_filename
from pygments.util import ClassNotFound from pygments.util import ClassNotFound
from ratelimit.decorators import ratelimit
from ratelimit.exceptions import Ratelimited
from dpaste import highlight from dpaste import highlight
from dpaste.forms import SnippetForm, get_expire_values from dpaste.forms import SnippetForm, get_expire_values
from dpaste.highlight import PygmentsHighlighter from dpaste.highlight import PygmentsHighlighter
from dpaste.models import Snippet from dpaste.models import Snippet
from django.conf import settings
config = apps.get_app_config("dpaste") config = apps.get_app_config("dpaste")
@ -45,8 +49,6 @@ class SnippetView(FormView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs) response = super().get(request, *args, **kwargs)
if config.CACHE_HEADER:
patch_cache_control(response, max_age=config.CACHE_TIMEOUT)
return response return response
def get_form_kwargs(self): def get_form_kwargs(self):
@ -111,18 +113,7 @@ class SnippetDetailView(DetailView, FormView):
snippet.view_count += 1 snippet.view_count += 1
snippet.save(update_fields=["view_count"]) snippet.save(update_fields=["view_count"])
response = super().get(request, *args, **kwargs) return super().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()
@ -153,8 +144,8 @@ class SnippetDetailView(DetailView, FormView):
d = difflib.unified_diff( d = difflib.unified_diff(
snippet.parent.content.splitlines(), snippet.parent.content.splitlines(),
snippet.content.splitlines(), snippet.content.splitlines(),
ugettext("Previous Snippet"), gettext("Previous Snippet"),
ugettext("Current Snippet"), gettext("Current Snippet"),
n=1, n=1,
) )
diff_code = "\n".join(d).strip() diff_code = "\n".join(d).strip()
@ -188,7 +179,7 @@ class SnippetRawView(SnippetDetailView):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if not config.RAW_MODE_ENABLED: if not config.RAW_MODE_ENABLED:
return HttpResponseForbidden( return HttpResponseForbidden(
ugettext("This dpaste installation has Raw view mode disabled.") gettext("This dpaste installation has Raw view mode disabled.")
) )
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
@ -332,7 +323,10 @@ class APIView(View):
expire_type = Snippet.EXPIRE_TIME expire_type = Snippet.EXPIRE_TIME
snippet = Snippet.objects.create( snippet = Snippet.objects.create(
content=content, lexer=lexer, expires=expires, expire_type=expire_type, content=content,
lexer=lexer,
expires=expires,
expire_type=expire_type,
) )
# Custom formatter for the API response # Custom formatter for the API response
@ -349,17 +343,15 @@ class APIView(View):
# handle them here. # handle them here.
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def handler404(request, exception=None, template_name="dpaste/404.html"):
def page_not_found(request, exception=None, template_name="dpaste/404.html"):
context = {} context = {}
context.update(config.extra_template_context) context.update(config.extra_template_context)
response = render(request, template_name, context, status=404) response = render(request, template_name, context, status=404)
if config.CACHE_HEADER: patch_cache_control(response, max_age=config.CACHE_TIMEOUT)
patch_cache_control(response, max_age=config.CACHE_TIMEOUT)
return response return response
def server_error(request, template_name="dpaste/500.html"): def handler500(request, template_name="dpaste/500.html"):
context = {} context = {}
context.update(config.extra_template_context) context.update(config.extra_template_context)
response = render(request, template_name, context, status=500) response = render(request, template_name, context, status=500)

View File

@ -4,7 +4,8 @@ skip_missing_interpreters=True
envlist= envlist=
readme readme
coverage_setup coverage_setup
py{36,37,38}-django-{22,30,31} py{36,37,38,39,310}-django-{22,30,31,32}
py{38,39,310}-django-{40}
coverage_report coverage_report
[testenv] [testenv]
@ -18,6 +19,8 @@ deps=
django-22: django>=2.2,<3.0 django-22: django>=2.2,<3.0
django-30: django>=3.0,<3.1 django-30: django>=3.0,<3.1
django-31: django>=3.1,<3.2 django-31: django>=3.1,<3.2
django-32: django>=3.2,<4.0
django-40: django>=4.0,<4.1
[testenv:coverage_setup] [testenv:coverage_setup]
skip_install = True skip_install = True