serve static brotli or gzip compressed files as well
This commit is contained in:
parent
10abb9cd2f
commit
ed69bdfb12
|
@ -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)
|
||||||
|
|
|
@ -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():
|
||||||
|
|
Loading…
Reference in New Issue