Refactor gzip creation
This commit is contained in:
parent
abc1f119d5
commit
5b7f08ed08
3 changed files with 27 additions and 34 deletions
|
@ -224,6 +224,7 @@ DATABASES = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UMAP_READONLY = False
|
UMAP_READONLY = False
|
||||||
|
UMAP_GZIP = True
|
||||||
LOCALE_PATHS = [os.path.join(PROJECT_DIR, 'locale')]
|
LOCALE_PATHS = [os.path.join(PROJECT_DIR, 'locale')]
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import gzip
|
import gzip
|
||||||
|
import os
|
||||||
|
|
||||||
from django.urls import get_resolver
|
from django.urls import get_resolver
|
||||||
from django.urls import URLPattern, URLResolver
|
from django.urls import URLPattern, URLResolver
|
||||||
|
@ -106,9 +107,11 @@ def decorated_patterns(func, *urls):
|
||||||
|
|
||||||
|
|
||||||
def gzip_file(from_path, to_path):
|
def gzip_file(from_path, to_path):
|
||||||
|
stat = os.stat(from_path)
|
||||||
with open(from_path, 'rb') as f_in:
|
with open(from_path, 'rb') as f_in:
|
||||||
with gzip.open(to_path, 'wb') as f_out:
|
with gzip.open(to_path, 'wb') as f_out:
|
||||||
f_out.writelines(f_in)
|
f_out.writelines(f_in)
|
||||||
|
os.utime(to_path, (stat.st_mtime, stat.st_mtime))
|
||||||
|
|
||||||
|
|
||||||
def is_ajax(request):
|
def is_ajax(request):
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import hashlib
|
|
||||||
import json
|
import json
|
||||||
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import socket
|
import socket
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import mimetypes
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import logout as do_logout
|
from django.contrib.auth import logout as do_logout
|
||||||
|
@ -689,38 +689,16 @@ class GZipMixin(object):
|
||||||
|
|
||||||
EXT = ".gz"
|
EXT = ".gz"
|
||||||
|
|
||||||
def _path(self):
|
@property
|
||||||
|
def path(self):
|
||||||
return self.object.geojson.path
|
return self.object.geojson.path
|
||||||
|
|
||||||
def path(self):
|
|
||||||
"""
|
|
||||||
Serve gzip file if client accept it.
|
|
||||||
Generate or update the gzip file if needed.
|
|
||||||
"""
|
|
||||||
path = self._path()
|
|
||||||
statobj = os.stat(path)
|
|
||||||
ae = self.request.META.get('HTTP_ACCEPT_ENCODING', '')
|
|
||||||
if re_accepts_gzip.search(ae) and getattr(settings, 'UMAP_GZIP', True):
|
|
||||||
gzip_path = "{path}{ext}".format(path=path, ext=self.EXT)
|
|
||||||
up_to_date = True
|
|
||||||
if not os.path.exists(gzip_path):
|
|
||||||
up_to_date = False
|
|
||||||
else:
|
|
||||||
gzip_statobj = os.stat(gzip_path)
|
|
||||||
if statobj.st_mtime > gzip_statobj.st_mtime:
|
|
||||||
up_to_date = False
|
|
||||||
if not up_to_date:
|
|
||||||
gzip_file(path, gzip_path)
|
|
||||||
path = gzip_path
|
|
||||||
return path
|
|
||||||
|
|
||||||
def etag(self):
|
def etag(self):
|
||||||
path = self.path()
|
|
||||||
# Align ETag with Nginx one, because when using X-Send-File, If-None-Match
|
# Align ETag with Nginx one, because when using X-Send-File, If-None-Match
|
||||||
# and If-Modified-Since are handled by Nginx.
|
# and If-Modified-Since are handled by Nginx.
|
||||||
# https://github.com/nginx/nginx/blob/4ace957c4e08bcbf9ef5e9f83b8e43458bead77f/src/http/ngx_http_core_module.c#L1675-L1709
|
# https://github.com/nginx/nginx/blob/4ace957c4e08bcbf9ef5e9f83b8e43458bead77f/src/http/ngx_http_core_module.c#L1675-L1709
|
||||||
statobj = os.stat(path)
|
statobj = os.stat(self.path)
|
||||||
return 'W/"%x-%x"' % (int(statobj.st_mtime), statobj.st_size)
|
return '"%x-%x"' % (int(statobj.st_mtime), statobj.st_size)
|
||||||
|
|
||||||
|
|
||||||
class DataLayerView(GZipMixin, BaseDetailView):
|
class DataLayerView(GZipMixin, BaseDetailView):
|
||||||
|
@ -728,29 +706,40 @@ class DataLayerView(GZipMixin, BaseDetailView):
|
||||||
|
|
||||||
def render_to_response(self, context, **response_kwargs):
|
def render_to_response(self, context, **response_kwargs):
|
||||||
response = None
|
response = None
|
||||||
path = self.path()
|
path = self.path
|
||||||
|
# Generate gzip if needed
|
||||||
|
accepts_gzip = re_accepts_gzip.search(
|
||||||
|
self.request.META.get("HTTP_ACCEPT_ENCODING", "")
|
||||||
|
)
|
||||||
|
if accepts_gzip and settings.UMAP_GZIP:
|
||||||
|
gzip_path = Path(f"{path}{self.EXT}")
|
||||||
|
if not gzip_path.exists():
|
||||||
|
gzip_file(path, gzip_path)
|
||||||
|
|
||||||
if getattr(settings, "UMAP_XSENDFILE_HEADER", None):
|
if getattr(settings, "UMAP_XSENDFILE_HEADER", None):
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
path = path.replace(settings.MEDIA_ROOT, "/internal")
|
path = path.replace(settings.MEDIA_ROOT, "/internal")
|
||||||
response[settings.UMAP_XSENDFILE_HEADER] = path
|
response[settings.UMAP_XSENDFILE_HEADER] = path
|
||||||
else:
|
else:
|
||||||
# TODO IMS
|
# Do not use in production
|
||||||
|
# (no cache-control/If-Modified-Since/If-None-Match)
|
||||||
statobj = os.stat(path)
|
statobj = os.stat(path)
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
# Should not be used in production!
|
# Should not be used in production!
|
||||||
response = HttpResponse(f.read(), content_type="application/json")
|
response = HttpResponse(f.read(), content_type="application/geo+json")
|
||||||
response["Last-Modified"] = http_date(statobj.st_mtime)
|
response["Last-Modified"] = http_date(statobj.st_mtime)
|
||||||
response["ETag"] = self.etag()
|
response["ETag"] = self.etag()
|
||||||
response["Content-Length"] = statobj.st_size
|
response["Content-Length"] = statobj.st_size
|
||||||
response["Vary"] = "Accept-Encoding"
|
response["Vary"] = "Accept-Encoding"
|
||||||
if path.endswith(self.EXT):
|
if accepts_gzip and settings.UMAP_GZIP:
|
||||||
response["Content-Encoding"] = "gzip"
|
response["Content-Encoding"] = "gzip"
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
class DataLayerVersion(DataLayerView):
|
class DataLayerVersion(DataLayerView):
|
||||||
def _path(self):
|
|
||||||
|
@property
|
||||||
|
def path(self):
|
||||||
return "{root}/{path}".format(
|
return "{root}/{path}".format(
|
||||||
root=settings.MEDIA_ROOT,
|
root=settings.MEDIA_ROOT,
|
||||||
path=self.object.get_version_path(self.kwargs["name"]),
|
path=self.object.get_version_path(self.kwargs["name"]),
|
||||||
|
|
Loading…
Reference in a new issue