serve static brotli or gzip compressed files as well

This commit is contained in:
codl 2017-08-11 19:44:09 +02:00
parent 10abb9cd2f
commit ed69bdfb12
No known key found for this signature in database
GPG Key ID: 6CD7C8891ED1233A
2 changed files with 30 additions and 7 deletions

View File

@ -1,16 +1,18 @@
import brotli from brotli import compress
from flask import request from flask import request, make_response
from functools import wraps from functools import wraps
from threading import Thread from threading import Thread
from hashlib import sha256 from hashlib import sha256
import redis import redis
import os.path
import mimetypes
class BrotliCache(object): class BrotliCache(object):
def __init__(self, redis_kwargs={}): def __init__(self, redis_kwargs={}):
self.redis = redis.StrictRedis(**redis_kwargs) self.redis = redis.StrictRedis(**redis_kwargs)
def compress(self, cache_key, lock_key, body): def compress(self, cache_key, lock_key, body):
encbody = brotli.compress(body) encbody = compress(body)
self.redis.set(cache_key, encbody, ex=3600) self.redis.set(cache_key, encbody, ex=3600)
self.redis.delete(lock_key) self.redis.delete(lock_key)
@ -25,13 +27,35 @@ class BrotliCache(object):
encbody = self.redis.get(cache_key) encbody = self.redis.get(cache_key)
if encbody: if encbody:
response.headers.set('content-encoding', 'br') response.headers.set('content-encoding', 'br')
response.headers.set('vary', 'content-encoding') response.headers.set('vary', 'accept-encoding')
response.set_data(encbody) response.set_data(encbody)
return response return response
else: else:
lock_key = 'brotlicache:lock:{}'.format(digest) lock_key = 'brotlicache:lock:{}'.format(digest)
if self.redis.set(lock_key, 1, nx=True, ex=60): if self.redis.set(lock_key, 1, nx=True, ex=10):
t = Thread(target=self.compress, args=(cache_key, lock_key, body)) t = Thread(target=self.compress, args=(cache_key, lock_key, body))
t.run() t.run()
return response return response
def brotli(app, static = True, dynamic = True):
original_static = app.view_functions['static']
def static_maybe_gzip_brotli(filename=None):
path = os.path.join(app.static_folder, filename)
for encoding, extension in (('br', '.br'), ('gzip', '.gz')):
if encoding not in request.accept_encodings:
continue
encpath = path + extension
if os.path.isfile(encpath):
resp = make_response(original_static(filename=filename + extension))
resp.headers.set('content-encoding', encoding)
resp.headers.set('vary', 'accept-encoding')
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
resp.headers.set('content-type', mimetype)
return resp
return original_static(filename=filename)
if static:
app.view_functions['static'] = static_maybe_gzip_brotli
if dynamic:
cache = BrotliCache()
app.after_request(cache.wrap_response)

View File

@ -36,9 +36,8 @@ def touch_viewer(resp):
db.session.commit() db.session.commit()
return resp return resp
brcache = lib.brotli.BrotliCache(app.config.get('REDIS', {}))
app.after_request(brcache.wrap_response) lib.brotli.brotli(app)
@app.route('/') @app.route('/')
def index(): def index():